Não sei como continuar meu script!

6 Respostas   226 Visualizações

0 Membros e 1 Visitante estão vendo este tópico.

Nunnu

  • *
  • Posts: 39
  • Ouros: 2
  • cala boca
Tópico criado em: 02/11/2016 às 17:17 - Última modificação por Nunnu em 12/11/2016 às 12:33

Boa tarde, estou fazendo um script em que achei estar praticamente pronto, mas como sou muito iniciante, qualquer obstáculo é uma pedra enorme.

Meu script é uma formação de grupo, o erro é o seguinte:



Se eu aperto a tecla "A", eles fazem essa formação. Se andar na direção em que foi feita a formação, eles vão alinhados, mas se virar eles dão um passo antes de virarem junto com o player, dai tem que dar mais um passo, até lá já cagou toda a coisa. Eles vão estar sempre um passo atrás.

Sei que é uma formação nova e que contém alguns aspectos do sistema de formação anterior (Caterpillar). Então fui atrás disso, descobri onde tenho que mexer, mas não sei como anular a coisa.

Peço que me ajudem com isso da forma que puderem, aqui está o código:

Código: [Selecionar]
class Game_Followers

  attr_reader :switch_one
  attr_reader :switch_two
 
  alias prev_initialize initialize
  def initialize(leader)
    prev_initialize(leader)
    @switch_one = false
    @switch_two = false
  end

  alias prev_update update
  def update
    prev_update
    if Input.trigger?(:X)
      @switch_two = false
      gather
      @switch_one = true
    end

    if !moving? && !gathering? && @switch_one
      triangle_formation
    end
  end

  def move
    if @switch_two == false
      reverse_each {|follower| follower.chase_preceding_character }
    elsif @switch_two == true
      reverse_each {|follower| self.triangle_formation_follow }
    end
  end
 
  def triangle_formation
    case $game_player.direction
    when 2
      self[0].move_straight(4)
      self[0].set_direction(2)

      self[1].move_straight(6)
      self[1].set_direction(2)
     
      self[2].move_straight(2)
      self[2].set_direction(2)
     
    when 4
      self[0].move_straight(8)
      self[0].set_direction(4)
     
      self[1].move_straight(2)
      self[1].set_direction(4)
     
      self[2].move_straight(4)
      self[2].set_direction(4)

    when 6
      self[0].move_straight(8)
      self[0].set_direction(6)
     
      self[1].move_straight(2)
      self[1].set_direction(6)
     
      self[2].move_straight(6)
      self[2].set_direction(6)
     
    when 8
      self[0].move_straight(4)
      self[0].set_direction(8)
     
      self[1].move_straight(6)
      self[1].set_direction(8)

      self[2].move_straight(8)
      self[2].set_direction(8)
    end
   
    @switch_one = false; @switch_two = true

  end
 
  def triangle_formation_follow
    unless moving?
      case $game_player.direction
      when 2
        $game_player.followers[0].move_straight(2)
        $game_player.followers[1].move_straight(2)
        $game_player.followers[2].move_straight(2)
             
      when 4
        $game_player.followers[0].move_straight(4)
        $game_player.followers[1].move_straight(4)
        $game_player.followers[2].move_straight(4)
         
      when 6
        $game_player.followers[0].move_straight(6)
        $game_player.followers[1].move_straight(6)
        $game_player.followers[2].move_straight(6)
           
      when 8
        $game_player.followers[0].move_straight(8)
        $game_player.followers[1].move_straight(8)
        $game_player.followers[2].move_straight(8)
      end
    end
  end
end

=begin

ABAIXO TEM UMAS DAS MINHAS TENTATIVAS DE SOLUÇÃO, DEIXEI PARA VOCÊS ANALISAREM
O CAMINHO QUE EU ESTOU TOMANDO (não funciona, obviamente).

=end


class Game_Follower < Game_Character
 
  def chase_preceding_character
    unless moving?
      if @switch_two == false
        sx = distance_x_from(@preceding_character.x)
        sy = distance_y_from(@preceding_character.y)
      elsif @switch_two == true
        sx = nil
        sy = nil
      end

      if sx != 0 && sy != 0
        move_diagonal(sx > 0 ? 4 : 6, sy > 0 ? 8 : 2)
      elsif sx != 0
        move_straight(sx > 0 ? 4 : 6)
      elsif sy != 0
        move_straight(sy > 0 ? 8 : 2)
      end
    end
  end
end
Feito por:   King Gerar          ManecBR3
                   
                   (um gato)            (outro gato)

Kyo Panda

  • Mito
  • *
  • Posts: 259
  • Ouros: 195
Resposta 1: 02/11/2016 às 20:18

O problema do movimento é esse:

Código: [Selecionar]
def move_straight(d, turn_ok = true)
  @followers.move if passable?(@x, @y, d)
  super
end

Esse é o comando do Game_Player. Isso significa que o comando de mover dos seguidores ocorre antes do movimento do jogador, fazendo com que a nova direção do jogador não esteja definida no momento do movimento, causando o comportamento.

É por essa causa que o código de seguidores utiliza a coordenada do personagem a frente para definir o movimento, dado que a direção em si se torna irrelevante:

Código: [Selecionar]
def chase_preceding_character
  unless moving?
    sx = distance_x_from(@preceding_character.x)
    sy = distance_y_from(@preceding_character.y)
    if sx != 0 && sy != 0
      move_diagonal(sx > 0 ? 4 : 6, sy > 0 ? 8 : 2)
    elsif sx != 0
      move_straight(sx > 0 ? 4 : 6)
    elsif sy != 0
      move_straight(sy > 0 ? 8 : 2)
    end
  end
end

Uma solução simples é utilizar o comando do jogador para fazer o movimento, fazendo os seguidores terem o mesmo comportamento que o personagem:

Código: [Selecionar]
def triangle_formation_follow
  unless moving?
    each do |follower|
      follower.move_straight(Input.dir4) if Input.dir4 > 0
    end
  end
end

Você só terá que criar restrições de movimento para os seguidores e personagens caso encontre uma barreira, pois eles sairão de formação quando encostar numa parede, por exemplo.

:blink:

Nunnu

  • *
  • Posts: 39
  • Ouros: 2
  • cala boca
Resposta 2: 03/11/2016 às 18:43 - Última modificação por Nunnu em 03/11/2016 às 18:46

@Kyo Panda

Preciso me atentar mais a esse tipo de coisa, não olhei direito o que poderia ter causado o problema, nem cogitei o "move_straight" como causador do bug.

Primeiro queria lhe agradecer de verdade, me foi extremamente útil sua ajuda. Depois queria entender melhor o que acontece:

Você diz que o comando de mover dos seguidores vem antes do jogador, e que isso causa o comportamento já que a nova direção do jogador não está definida no momento do movimento, não sei se entendi direito, o problema está na mudança de direção, porque o jogador quando muda de direção ele não dá um passo logo em seguida, e sim vira primeiro.

E o chase_preceding_character é o sistema de movimento do jogo (um anda atrás do outro) que utiliza esse método, já que para dar certo a lógica a mudança de direção tem que ser ignorada.

A mudança do triangle_formation_follow faz com que os seguidores andem junto com o personagem certo? Só pra mim entender, seria possível remover o "each do |follower|" caso fosse dentro da classe Game_Followers e com essa condição: "self.move_straight(Input.dir4) if Input.dir4 > 0"? (sei que eu poderia testar isso eu mesmo, mas meu objetivo não é colocar isso no Game_Followers, é sim entender direitinho tudo.)

Aguardo sua resposta, e obrigado novamente pela atenção.
Feito por:   King Gerar          ManecBR3
                   
                   (um gato)            (outro gato)

Kyo Panda

  • Mito
  • *
  • Posts: 259
  • Ouros: 195
Resposta 3: 03/11/2016 às 22:49

Quanto ao movimento, o grande ponto está na invocação da superclasse:

Código: [Selecionar]
def move_straight(d, turn_ok = true)
  @followers.move if passable?(@x, @y, d)
  super
end

Se formos verificar o que o super está realizando, verificamos, lá no Game_CharacterBase:

Código: [Selecionar]
def move_straight(d, turn_ok = true)
  @move_succeed = passable?(@x, @y, d)
  if @move_succeed
    set_direction(d)
    @x = $game_map.round_x_with_direction(@x, d)
    @y = $game_map.round_y_with_direction(@y, d)
    @real_x = $game_map.x_with_direction(@x, reverse_dir(d))
    @real_y = $game_map.y_with_direction(@y, reverse_dir(d))
    increase_steps
  elsif turn_ok
    set_direction(d)
    check_event_trigger_touch_front
  end
end

É nele que ocorre o set_direction, responsável pela alteração do $game_player.direction. Então o que podemos definir é que "antes da invocação da superclasse do método move_straight do $game_player, sua direção não se altera, a não ser que alterada por um comportamento exterior", no caso do script de alguém o mude antes do movimento.

---

Para o Game_Follower.chase_preceding_character, não é importante o que ele realiza, mas como. Para isso, precisamos entender como o movimento todo ocorre:

  • O jogador pressiona o botão de mover, executando o Game_Player.move_by_input, o Game_Player.movable? retorna verdadeiro e com nenhum evento executando, o personagem executa o comando Game_Player.move_straight.
  • O Game_Player.move_straight executa o Game_Followers.move.
  • O Game_Followers.move executa o comando Game_Follower.chase_preceding_character para cada um dos seguidores.
  • Game_Follower.chase_preceding_character calcula a distância do seguidor para o personagem a frente dele e move de acordo.
  • Então o Game_Player move.

O que se pode deduzir é que o comando de mover os seguidores ocorre antes do comando do personagem, fazendo com que cada seguidor mova em direção ao personagem frente. Logo, o seguidor #0 vai para a coordenada do personagem, o seguidor #1 para o #0 e o #2 para o #1, então o personagem move.

Como o seu movimento de formação não tem como determinar para onde os seguidores devem mover antes do jogador mover, não temos como usar esse método, por isso realizamos o mesmo que o procedimento do Game_Player.move_by_input no Game_Followers.

Código: [Selecionar]
def move_by_input
  return if !movable? || $game_map.interpreter.running?
  move_straight(Input.dir4) if Input.dir4 > 0
end

---

O each do |follower| basicamente tira proveito dessa função do Game_Followers

Código: [Selecionar]
def each
  @data.each {|follower| yield follower } if block_given?
end

Isso quer dizer que esses comandos fariam o mesmo:

Código: [Selecionar]
each do |follower|
  puts follower.actor.name
end

self.each do |follower|
  puts follower.actor.name
end

@data.each do |follower|
  puts follower.actor.name
end

Para que o self.move_straight(Input.dir4) if Input.dir4 > 0 funcionasse — não há a necessidade de declarar o self —, o mesmo deveria estar dentro do Game_Follower e não do Game_Followers.

Supomos que o seu Game_Followers.move estivesse assim:

Código: [Selecionar]
#--------------------------------------------------------------------------
# * Movement
#--------------------------------------------------------------------------
alias move_201611032221 move
def move
  if @switch_two
    reverse_each {|follower| follower.triangle_formation_follow }
    return
  end
  move_201611032221
end

O Game_Follower.triangle_formation_follow poderia estar dessa forma:

Código: [Selecionar]
#--------------------------------------------------------------------------
# * Triangle Formation Follow
#--------------------------------------------------------------------------
def triangle_formation_follow
  unless moving?
    move_straight(Input.dir4) if Input.dir4
  end
end

^-^


Nunnu

  • *
  • Posts: 39
  • Ouros: 2
  • cala boca
Resposta 4: 04/11/2016 às 15:14

Então, antes de tudo, obrigado de novo por me responder, e deu para ver seu empenho ao dar essa resposta tão bem organizada, sinto-me honrado! e-e

Mas ok, pelo que parece não estava correto meus pensamentos, quero ver se eu entendi dessa vez:

O que acontece quanto ao movimento, é que o @followers.move só vai acontecer se o @move_succeed for igual a true, significa que os seguidores só vão andar quando o super for verificado. Quando for verificado, eles vão receber primeiro o comando de mover=se que o jogador, segundo o método do move_straight da classe Game_Player (@followers.move if passable?(@x, @y, d); super).
--
Minha formação desajusta as regras do método. Os seguidores avançam perfeitamente se andarem na direção em que forem formados, mas quando o jogador vira, pronto, desalinha tudo. Isso se dá porque os seguidores tem definido seus passos antes do jogador pelo move_straight, por isso quando o jogador muda de direção e avança, eles dão um passo na direção anterior, conforme as condições do método move_straight.
--
Quanto ao each do |follower|, minha intenção era dizer que:

Código: [Selecionar]
  def triangle_formation_follow
    unless moving?
      each do |follower|
        follower.move_straight(Input.dir4) if Input.dir4 > 0
      end
    end
  end

Significa:

Definição de seguir em formato de triângulo
  Exceto quando estiver se movendo
    Para cada seguidor, estas condições:
      Mova-se reto(em uma das quatro direções) se uma das quatro direções não for estar parado.
    Fim
  Fim
Fim


E se fosse no Game_Followers:

Definição de seguir em formato de triângulo
  Exceto quando estiver se movendo
      Seguidores, movam-se reto(em uma das quatro direções) se uma das quatro direções não for estar parado.
    Fim
  Fim
Fim


Desculpe pelo jeito que eu expliquei xD , mas acho que ficou melhor de entender, porque eu estou mostrando como vejo esse método, essa é a forma que eu a traduziria, e ai você pode ver onde eu errei. Mas o que eu quis dizer foi que o Game_Followers são os seguidores em conjunto, então penso que usar essa classe resumiria o método, mas pelo que você explicou percebi que não, só que ainda não entendi o porquê.

E também descobri que não sei como funciona o "return", pelo que eu pensava, se tu não botar nada no lado do return, retornaria nil.
--

É isso, vou lhe agradecer de novo pela atenção. Aguardo sua resposta.

:=p:
Feito por:   King Gerar          ManecBR3
                   
                   (um gato)            (outro gato)

Kyo Panda

  • Mito
  • *
  • Posts: 259
  • Ouros: 195
Resposta 5: 04/11/2016 às 15:54

Quanto ao movimento. está correto.

Código: [Selecionar]
@followers.move if passable?(@x, @y, d)
Isso basicamente limita que os seguidores se aglomerem no personagem se o mesmo estiver tentando andar enquanto bloqueado por uma parede. Logo, se o personagem não pode andar, os seguidores não andam.

---

Quanto a formação, também correto. Os seguidores andam e após o personagem anda. Como a formação exige saber para onde o personagem andará para o seguir, isso se torna inviável.

---

Quanto ao each, o primeiro método está no Game_Followers, por isso não entendi muito bem o "E se fosse no Game_Followers". O fato é que esse código:

Código: [Selecionar]
self.move_straight(Input.dir4)
Se chamado dentro da classe Game_Followers, resultaria em erro, pois a class Game_Followers não possui o método move_straight, a Game_Follower, filha do Game_Character possui.

Não que você não possa criar tal método na Game_Followers:

Código: [Selecionar]
def move_straight(*args)
  each {|follower| follower.move_straight(*args) }
end

^-^


Nunnu

  • *
  • Posts: 39
  • Ouros: 2
  • cala boca
Resposta 6: 04/11/2016 às 18:34 - Última modificação por Nunnu em 12/11/2016 às 12:35

Olha, muito obrigado, sanei todas as minhas dúvidas e estou bem satisfeito, aprendi muito contigo!

Foi muito bom ter contado com você, espero que se eu precisar de ajuda futuramente, você e outros aqui do fórum estejam à disposição.

Até a próxima!

o/

EDIT: Estou com dificuldade na criação da restrição de movimento ;-;
Feito por:   King Gerar          ManecBR3
                   
                   (um gato)            (outro gato)