O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

[VXAce] Função wait/esperar.

Iniciado por Conspiracy, 10/10/2015 às 20:33

10/10/2015 às 20:33 Última edição: 11/10/2015 às 00:44 por Conspiracy
Olá, pessoal, estou com uma dúvida para fazer uma função de esperar.
Ou seja: O Script executa um método, e aguarda determinado tempo (pode ser em segundos ou frames, etc.) para reativar. (Um exemplo similar a função "esperar" por eventos.)

Contexto: O sistema é uma ação, por exemplo, um pulo. a ideia é criar um tempo mínimo de espera para que se execute novamente a ação. (Por isso o wait no fim do jump_by_input).

Lista de Tentativas/Erro.
Spoiler

Chamando:
Game_Interpreter.wait(duration).

Erro.
Line 82 (A linha onde estava o comando acima): NoMethodError occurred.
undefined method 'wait' for Game_Interpreter:Class


Chamando:
wait(duration)

Erro.
Line 82 (A linha onde estava o comando acima): NoMethodError occurred.
undefined method 'wait' for #<Game_Player:0x6bab660>
Nota: A classe onde estou fazendo estas tentativas é escrita sobre a Game_Player.



Tentei também re-escrever a Game_Interpreter usando um alias.
class Game_Interpreter
  alias old_wait wait
  def wait(duration)
    old_wait(duration)
  end

end


Então, tentei chamar o Game_Interpreter.wait(duration)
Erro.
Line 82 (A linha onde estava o comando acima): NoMethodError occurred.
undefined method 'wait' for Game_Interpreter:Class

Chamando o Game_Interpreter.old_wait(duration)
E obtive o erro:
Line 82 (A linha onde estava o comando acima): NoMethodError occurred.
undefined method 'old_wait' for Game_Interpreter:Class

[close]
No caso, o meu código atualmente está dessa forma:
*Nota: Eu removi os pedaços do código que não influenciam em nada, para confundir menos e economizar espaço.
class Game_Interpreter
  alias old_wait wait
  def wait(duration)
    old_wait(duration)
  end

end

class Game_Player < Game_Character
  alias old_jump jump
    def jump(x_plus, y_plus)
      #Jump...
  end
  
  alias novo_update update
  def update
    novo_update    
    if Input.trigger?(:X)
      jump_by_input
    end
    
  end
  def jump_by_input
    #Chama o jump.
    
    Game_Interpreter.wait(120)
  end

end


No caso, este foi o código após as tentativas acima.
Writing codes. Writing novels. Writing... Fates.

Experimenta:

$game_map.interpreter.wait(time)

Substitui o Game_Interpreter.wait(time)
no fim do script, pelo: $game_map.interpreter.wait(time), como sugerido.

No caso, o erro obtido veio do Game_Interpreter original.
Script 'Game_Interpreter' line 241: FiberError Occurred.
can't yield from root fiber

O local do erro remeteu a:
class Game_Interpreter
...
Linha 240:  def wait(duration)
Linha 241:    duration.times { Fiber.yield } #Erro nesta linha. no Fiber.yield.
Linha 242:  end
Writing codes. Writing novels. Writing... Fates.

você não pode colocar um if em vez do tempo?

Como assim um if?

Bom, no caso, o sistema é uma ação, por exemplo, um pulo. a ideia é criar um tempo mínimo de espera para que se execute novamente a ação. (Por isso o wait no fim do jump_by_input).
Writing codes. Writing novels. Writing... Fates.

vc em vez do comando esperar metia


$game_switches[1] = true
if ($game_variables[1] > 30)
$game_switches[1] = false
$game_variables[1] = 0

jump

end

e criava um evento comum com ativação para a switch 1

a esperar 60 frames = 1seg
e a adicionar variavel1 + 1

entendeu?

Bom, a minha ideia seria deixar todo por script, mas acho que dessa forma vai servir.
Writing codes. Writing novels. Writing... Fates.

Basicamente, use uma variável 'time' com o tempo que precisa passar e execute alguma coisa quando ele acabar, por exemplo:
class WaitingObject
  attr_reader :time, :active

  def initialize
    @time = 0
    @active = false
    @_methods = []
  end

  def add_method(method)
    @_methods << method
  end

  def clear_methods
    @_methods.clear
  end

  def wait(frames)
    @time = frames
    @active = true
  end

  def update
    @time -= 1 if @time > 0
    if complete? && active
      @_methods.each(&:call)
      @active = false
    end
  end

  def abort
    @active = false
  end

  def complete?
    @time == 0
  end
end


Essa classe é (teoricamente, não testei) uma classe que espera X iterações do método update para executar um ou mais métodos, um exemplo de uso:
class Scene_Wait < Scene_Base
  def start
    super
    @waiting = WaitingObject.new
    @waiting.add_method(method :gameover)
    @waiting.wait(600) # Espera 600 frames ou 10 segundos
  end
  def update
    super
    @waiting.update
  end
  def gameover
    SceneManager.goto(Scene_Gameover)
  end
end


Agora tente chamar essa cena, em teoria, deve haver dez segundos de espera e a cena de game over deve aparecer (suposição, não testei...)
Se quiser testar você também pode ver que dá pra fazer o que quiser com o resto da cena durante o tempo de espera.
~ Masked

No caso, Masked, de onde vem esse método wait? O meu problema, é justamente conseguir chamá-lo sem obter uma mensagem de erro.
No caso, consegui implementar sua classe. Mas não aconteceu nada. O Game_Over não foi chamado após 10 segundos (esperei uns 20).
Ainda chamei um "x = WaitingObject.new" mas o update não parecia estar funcionando.
chamei o seu wait, e não criou o tempo de espera também.
Coloquei um print no método update, e não estava printando.

Desculpa se usei errado, ainda estou aprendendo RGSS.
Writing codes. Writing novels. Writing... Fates.

O wait na verdade não existe, eu que criei ele. No caso do Game_Interpreter, ele usa Threads/Fiber para fazer essa espera enquanto executa outras coisas, basicamente igual ao que eu fiz, só não usei a fiber porque dada a minha falta de experiência com isso é bem capaz que fosse dar errado, além do que a ideia é idêntica.
Tem certeza que está chamando o update? É que o método update precisa ser chamado para funcionar, se não chamar ele não vai mesmo :B

Tente usar o script da cena que eu fiz junto com o do WaitingObject e chamar a cena com SceneManager.call(Scene_Wait)
~ Masked

10/10/2015 às 23:31 #10 Última edição: 11/10/2015 às 00:42 por Conspiracy
No caso eu teria que chamar o WaitingObject.update repetidas vezes? Já que ele não se "atualiza sozinho" e não fica repetindo sozinho.
Writing codes. Writing novels. Writing... Fates.

Sim, teria, como é o caso da cena, que tem o método 'main' que fica chamando o update dela até que a SceneManager.scene não seja mais ela mesma, por isso inclusive que eu fiz em uma cena, o método update já é chamado todo frame pela natureza da classe, veja que se você quiser criar um loop com o update também vai precisar chamar o Graphics.update pra iteração do loop durar 1 frame, se não vai dar duzentas mil contagens por segundo e buga tudo.
~ Masked

Entendi, mas acho que vou usar a solução por eventos, como sugerido acima. Muito Obrigado pelas respostas, Masked e Lima!
Ainda não entendo muito bem o ruby em si.
Eu vou estudar mais um pouco de RGSS e depois vejo se consigo por script.
Podem trancar o tópico.
Caso não dê certo, eu peço para reabrir aqui.
Writing codes. Writing novels. Writing... Fates.