public void atacar(){
// operacoes
pausa();
// operacoes
apanhar();
}
public void apanhar(){
// operacoes
pausa();
// operacoes
}
O que está acontecendo é que o programa aguarda 2 segundos e executa as operações de ambos os métodos. Como é possível aguardar 1 segundo, realizar algumas operações, aguardar outro 1 segundo e finalizar as operações?
Tentei usando apenas o código que citei acima e também criando uma classe que herda Thread, e a cada “pausa” eu criava uma nova Thread e utilizava o join(), mas ainda assim o tempo era acumulado.
Sobre as classes, tem alguma informação específica? Porque já tem umas 15 classes com bastante código.
Inicialmente, usar threads para jogos vai te dar muito mais problemas do que vantagens, principalmente por causa da sincronização.
Uma boa abordagem para jogos é usar um loop de jogo (game loop). Este artigo explica a ideia. Neste aqui, há um outro exemplo, em que o tempo entre cada loop é usado na lógica do jogo. Basicamente, a cada volta do laço, você tem uma determinada quantidade de tempo passado (por exemplo, 17 milissegundos). Com isso, você pode realizar ações baseadas no tempo que passou.
Com isso, é possível ter assim:
class Inimigo{
private float tempoDePausa = 0;
private float tempoAtacando = 1;
private boolean atacando = false;
public void update(float deltaTime){
if (tempoAtacando > 0.0f) {
// bla bla bla: aqui, faz o que o ataque precisa
tempoAtacando -= deltaTime;
if (tempoAtacando <= 0.0f){
tempoDePausa = 1; // a partir daqui, o inimigo irá ficar pausado
}
}else{
// aqui ele fica esperando
tempoDePausa -= deltaTime;
if (tempoDePausa <= 0.0f){
tempoAtacando = 1; // a partir daqui, o inimigo irá atacar
}
}
}
}
Daí, na classe que contém o game loop, você faz algo como:
Inimigo orc = new Inimigo();
private void gameLoop(){
float delta = 0;
while (gameRunning){
// resto do código
delta = tempopassado;// delta recebe o tempo passado entre as voltas do laço
orc.update(delta);
// resto do código
}
}
Procure dar uma lida sobre game loop pra entender esse conceito, que é extremamente útil. Muitas bibliotecas e engines inclusive já implementam algo parecido (para o programador não ter que se preocupar com isso).
Estou terminando de ler os artigos, são excelentes e estou aprendendo bastante. Conforme leio, tento novas coisas, mas ainda tenho o mesmo resultado. Talvez faltou esclarecer um pouco do problema:
O jogo é de turnos, onde você seleciona uma ação, executa ela, e o inimigo executa outra (estilo Pokémon de GameBoy).
Tendo essa imagem como referência, eu gostaria de executar a ação de dizer que houve o ataque (1), aguardar 3 segundos para futuramente colocar alguma animação (2), e só depois exibir o dano feito e as demais coisas (3).
O que acontece é que são aguardados os 3 segundos e todas as mensagens chegam de uma vez. Quando coloco o método pausa() entre os métodos que exibem mensagens, todos eles são acumulados (se coloco 4 pausa(), ele aguarda 12 segundos), e só depois as mensagens são exibidas, todas ao mesmo tempo.
Segue o método pausa:
public void pausa(){
long tempo1 = System.currentTimeMillis();
long tempo2;
boolean waiting = true;
while (waiting){
tempo2 = System.currentTimeMillis();
if ( (tempo2 - tempo1)/1000 == 3 ){
waiting = false;
}
}
diz("Aguardou 3 segundos");
}
Agora estou escrevendo as frases do jogo tanto com append na interface gráfica quanto com system out. No segundo caso, está funcionando normalmente, mas no append da JLabel acontece o problema.
Lembrando que você só deve mexer na interface do swing através da AWT Event Dispatching Thread. Talvez isso esteja causando o atraso na UI, só um palpite.
O que o lvbarbosa disse faz sentido. Swing não é thread safe, então alguns eventos acabam tendo uma execução “bagunçada” quando envolvem timers, sleeps e threads. Às vezes é necessário inclusive tentar forçar a atualização de componentes, com coisas como revalidate(), invalidate(), repaint(), …
Uma abordagem que você pode tentar também é o conceito de estados. A ideia é que cada estado represente um momento definido dentro da sua lógica (exemplo: atacando, defendendo, tomando ataque) e haja transições de estado de acordo com cada situação, (exemplo: clique, passados x segundos, etc). Adicione máquinas de estado finitas (finite state machines - FSM) a seus estudos.
Por exemplo:
abstract class State{
public abstract void execute();
}
class AtackState extends State{
public void execute(){
System.out.println("Atacando");
}
}
class WaitState extends State{
public void execute(){
System.out.println("Aguardando");
Thread.sleep(5000); // aqui precisa do exception de InterruptedStation, etc
}
}
É meio complicado explicar em poucas linhas, mas dê uma lida que é um conceito interessante. Inclusive, você pode fazer seu jogo todo baseado em estados (não só as batalhas). Cada estado pode processar o input (teclado, mouse) e exibir uma tela diferente, sem precisar de um monte de ifs. . Exemplo:
estados do jogo: andando, batalhando, comprando;
estados de batalha: atacando, aguardando, tomando ataque;