Ajuda com animações em java

Bom, nem sei se isso e ‘java básico’ ou não , mas so por eu ter a duvida resolvi postar aqui mesmo…
e o seguinte gosto bastante de programar em java porem não trabalho com isto , então pra praticar bem a linguagem resolvi brincar de fazer joguinhos, que eu acho que da pra treinar bem porque engloba muita coisa , esta semana resvoli tentar fazer minha propria engine, e comecei pelas classes de recuperação de imagem e desenho .

estava tudo indo certo até que aconteceu algo que nao previ…
so e desenhado na tela a ultima instancia da classe Fighter , quando eu
esperava que todas fossem desenhadas ( ja que são instancias da mesma clase ) , pensei por um momento
que uma estava desenhando em cima da outro mas não e isso ,
derrepente alguem pode ter uma expliacação simples, as duas
instancias chegam a ser criadas e rodam em background, mas so uma
e desenhada =(


public static void main (String[] args)
{
JFrame janela = new JFrame();
Fighter goku = new Fighter();
Fighter goku2 = new Fighter();
goku.setPos(100,100);
goku2.setPos(200,200);
janela.add(goku2 );
janela.add(goku );
janela.setSize(800 , 600 );
janela.setVisible(true);
}

classe fighter


public class Fighter extends Sprite {
	private Imagem imLoader;
	Fighter()
	{
		imLoader = new Imagem();
		setActive(true);
		setBehavior(true); // tem loop de animacao
		setNextAnim(true); // animacao foi carregada
		setBehaviorImage(imLoader.loadImageArray("goku.gif", 4));
		resetCurrentPosImage();  //aponta para 1 imagem do buffer
}
}

classe sprite



import java.awt.Component;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;



public class Sprite extends JPanel implements Runnable {




private Graphics gw;
private Image dbImage;
private final int INITIAL_STATE = 0;

//boolean setters
private boolean active = false;
private boolean behavior = false;
private boolean looping;
private boolean isNext; 



//image setters 
private BufferedImage image;
private BufferedImage imageAnim;
private int currentAnim;
private int animLenght;

private BufferedImage[] imagesAnim;
private Imagem imLoader;
private int locX , locY;
private int currentImage;
public void setPos(int x , int y )
{
locX = x ;
locY = y;
}

private Thread threadimage;
public void init()
{
	System.out.println("SPRITE CRIADO");
if (threadimage == null )
{
threadimage = new Thread(this);
threadimage.start();
}

}
public void addNotify( )
/* Wait for the JPanel to be added to the
   JFrame/JApplet before starting. */
{
  super.addNotify( );   // creates the peer
  init();
} 


public void paintComponent(Graphics g)
{
drawSprite(g);	
}

public void run()
{
while (true)
{
try 
	{
	if ( currentAnim < animLenght ){
		System.out.println("run currentAnim " +currentAnim );
		System.out.println("run nimLenght "+animLenght );
		
	updateAnim();
	repaint();
	currentAnim++;
	threadimage.sleep(100);
	}
else {
	setNextAnim(false);
	resetCurrentPosImage();
	System.out.println("image counter reseted" );
	threadimage.sleep(20);
}
} // try thread
catch (InterruptedException e) {
		
} // thread morta
}

}


public Image getCurrentImage()
{
return image;
}

public Image getCurrentAnimImage()
{
return imageAnim;
}

public void setImage(String name)
{
image = imLoader.loadImage(name);
//setCurrentImage( imLoader.loadImage(name) );
}



/** configura a imagem de animação comportamental 
 * */
public void setBehaviorImage(BufferedImage[] anim)
{
animLenght = anim.length;
imagesAnim = anim;

}


/** atualiza para o proximo movimento da animação 
 * comportamental
 */

public void updateAnim()
{
if( isNextAnim() ) // se ainda existir proxima animção 

{
System.out.println("current image: "+currentAnim);
imageAnim = imagesAnim[currentAnim];
//currentImage++;


}
else{
	resetCurrentPosImage();
	System.out.println("image image reseted: updateAnim" );
}
//setNextAnim(false);

}

public boolean isNextAnim()
{
return isNext;
}
public void resetCurrentPosImage ()
{
	currentAnim = INITIAL_STATE;
	setNextAnim(true);
	
}
public void setNextAnim(boolean value)
{
isNext = value;
}


public void setCurrentImage(BufferedImage image)
{
this.image = image;
}


public void setActive(boolean active)
{
this.active = active;
}

public void loopImage(String name){}

public boolean isBehaved()
{
return behavior;
}

public void setBehavior(boolean value)

{
behavior = value;
}


public void getPWidth(){}
public void getPHeight(){}
public void getXPos(){}
public void getYPos(){}
public void updateSprite(){}
public void drawSprite(Graphics g)
{

if ( isBehaved() )  // tem loop constante
{

if ( isActive() )  // sprite ativo
{
	//image = getCurrentImage();
	
	dbImage = createImage(this.getWidth(),this.getHeight());
	gw = dbImage.getGraphics( );
	gw.setColor (getBackground ());
	
	gw.drawImage(imageAnim,locX,locY,null);
	g.drawImage(dbImage,locX,locY,null);
	System.out.println("image painted");
		
}

}

if (isActive())
{
	if (imageAnim==null)
	{
	System.out.println("the sprite has no image");
	//draw a cirle instead of the image
	//code here

	}
else
	{

	if ( isNext )

	{

	//image = getCurrentImage();
	g.drawImage(image,locX,locY,null);

	}

} // end of else statement 


}// out of isActive()

 

} // end of drawnsprite()

public boolean isActive()
{
return active;
}


public void getMyRectangle(){}



} // end of Sprite() class

tem muita coisa no codigo que ainda nao configurei nem se atentem a isso, como comportamento das janelas e tal…

desculpem pelo flood de codigos …vlw

Para começar mude janela.add() para janela.getContentPane().add()
Não se faz add() diretamente num JFrame.

Depois , tlv possa pensar em não fazer os seus Sprites serem JPanel.
Eles não precisam ser JPanel para se puderem desenhar na tela. (E do ponto de vista OO um sprite não e um painel)
Tente criar um só JPanel que é “area de ação” onde os sprites se movimentam, mas não os faça filhos desse JPanel. Ou seja, quando o JPanel.drawGrpahics() for invocado pelo Swing simplesmente delege para os sprites.

beleza acho que peguei a idéia vo implementar aqui pra ver se da certo.
Obrigado.

[quote=sergiotaborda]Para começar mude janela.add() para janela.getContentPane().add()
Não se faz add() diretamente num JFrame.
[/quote]

???
A partir do Java 1.5 pode-se usar o add diretamente sim.

Quanto a desenhar suas sprites, etc, desenha tudo em um buffer, e depois que tudo estiver desenhado vc manda pintar o buffer no seu componente.

[quote=davidbuzatto][quote=sergiotaborda]Para começar mude janela.add() para janela.getContentPane().add()
Não se faz add() diretamente num JFrame.
[/quote]

???
A partir do Java 1.5 pode-se usar o add diretamente sim.

Quanto a desenhar suas sprites, etc, desenha tudo em um buffer, e depois que tudo estiver desenhado vc manda pintar o buffer no seu componente.[/quote]

se voce ta se refirindo a tecnica de double buffering , pintar 1° em background , eu ja faço isso sim…

bom valeu ai, ja consegui oque eu queria, agora ja posso dar continuidade a minha engine… flw

[quote=davidbuzatto][quote=sergiotaborda]Para começar mude janela.add() para janela.getContentPane().add()
Não se faz add() diretamente num JFrame.
[/quote]

???
A partir do Java 1.5 pode-se usar o add diretamente sim.
[/quote]

Isso é uma dúvida q eu tenho mas nunca consegui sanar… qual a diferença entre dar add direto e usar o getContentPane?

Alguns comentários:

  1. Nem todo sprite precisa implementar Runnable. É muito mais fácil ter um só animation loop, especialmente se você garantir que a taxa de updates por segundo desse animation loop é constante.

Há dicas sobre isso no Killer Game Programming in Java e nesse artigo (em português). Com um loop só, rodando em uma única thread, fica mais fácil calcular a taxa de frames por segundo.

  1. Se você vai usar DoubleBuffering, é melhor trabalhar com a classe BufferStrategy, do próprio Java. A vantagem dela é que, além da simplicidade, ela garante que não haverá tearing (raro, mas pode acontecer), ou seja, que a imagem não será atualizada exatamente no meio de um refresh do monitor. Essa técnica é chamada de Page Flipping.
    Esse tópico trata exatamente desse assunto.

  2. As dicas do sergio são ótimas. Sua classe Sprite deve manipular BufferedImages diretamente. Use a dica da pintura direta dada no artigo descrito no tópico 2. Você vai ver um grande ganho de performance, além de facilitar a migração da sua aplicação para o modo Full Screen (algo que realmente supreende, pois muita gente nem sequer sabe que é possível mudar a resolução e deixar em full screen em java). Se você quiser, baixe os fontes do meu jogo, aqui nesse link, e veja como foi implementado. E qualquer dúvida, continua postando!!! :slight_smile: :wink: