Só o paint funcionou p/ mim também.
Em teoria só precisaria colocar painel.setDoubleBuffered(true); Mas components com buffer duplo já são padrão, não precisa setar pra true q eles já começam nesse estado.
Eu particularmente não vi muita diferença usando buffer duplo ou não ao fazer um joguinho/simulador.
Vou até postar aqui se alguem quiser dar uma olhada.
Controles p/ jogar:
Clique do mouse: Seta uma célula como viva:
Espaço: Começa/Pausa o jogo
Teclas esquerda e direita: Diminuem e aumentam a velocidade.
C: Limpa a tela
Esc: Fecha o jogo (Alt F4, clicar no X na janela também faz isso)
Como jogar: http://en.wikipedia.org/wiki/Conway's_Game_of_Life
JogoDaVida.java
[code]
package jogodavida;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.Timer;
public class JogoDaVida extends javax.swing.JFrame implements ActionListener
{
private final Dimension MIN;
private final Mapa mapa;
private Timer timer;
private int speed;
private int PIXEL_SIZE;
public JogoDaVida(Mapa mapa, int pixel)
{
this.mapa = mapa;
this.PIXEL_SIZE = pixel;
this.MIN = new Dimension(mapa.getLargura() * pixel, mapa.getAltura() * pixel);
this.speed = 500;
this.timer = new Timer(speed, this);
initComponents();
}
private void desenhaMapa()
{
Graphics g = painel.getGraphics();
int p = PIXEL_SIZE;
for (int linha = 0; linha < mapa.getAltura(); linha++)
for (int coluna = 0; coluna < mapa.getLargura(); coluna++)
if (mapa.getMatriz()[linha][coluna])
g.fillRect(coluna * p, linha * p, p, p);
}
@Override
public void paint(Graphics g)
{
super.paint(g);
desenhaMapa();
}
public void actionPerformed(ActionEvent e)
{
mapa.avaliaTodos();
repaint();
timer.restart();
}
public static void main(String args[])
{
final Mapa mapa = new Mapa(64, 64);
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
new JogoDaVida(mapa, 10).setVisible(true);
}
});
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
//
private void initComponents() {
painel = new javax.swing.JPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle(“Jogo da Vida”);
setResizable(false);
addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
formMouseClicked(evt);
}
});
addKeyListener(new java.awt.event.KeyAdapter() {
public void keyPressed(java.awt.event.KeyEvent evt) {
formKeyPressed(evt);
}
});
painel.setBackground(new java.awt.Color(255, 255, 255));
painel.setDoubleBuffered(false);
painel.setName(“painel”); // NOI18N
painel.setPreferredSize(MIN);
javax.swing.GroupLayout painelLayout = new javax.swing.GroupLayout(painel);
painel.setLayout(painelLayout);
painelLayout.setHorizontalGroup(
painelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 10, Short.MAX_VALUE)
);
painelLayout.setVerticalGroup(
painelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 10, Short.MAX_VALUE)
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(painel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(painel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
pack();
}//
private void formMouseClicked(java.awt.event.MouseEvent evt) {
if (painel.getMousePosition() != null)
{
int x = painel.getMousePosition().x;
int y = painel.getMousePosition().y;
int p = PIXEL_SIZE;
int linha = y / p;
int coluna = x / p;
mapa.mudaCelula(linha, coluna);
//repaint();
repaint(coluna * p, linha * p, (coluna + 1) * p, (linha + 1) * p);
}
}
private void formKeyPressed(java.awt.event.KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_SPACE)
if (timer.isRunning())
timer.stop();
else
timer.restart();
else if (key == KeyEvent.VK_RIGHT)
{
timer.stop();
if (speed > 50)
speed -= 50;
timer = new Timer(speed, this);
timer.start();
}
else if (key == KeyEvent.VK_LEFT)
{
timer.stop();
if (speed < 2000)
speed += 50;
timer = new Timer(speed, this);
timer.start();
}
else if (key == KeyEvent.VK_C)
{
timer.stop();
mapa.limpar();
repaint();
}
else if (key == KeyEvent.VK_ESCAPE)
System.exit(0);
}
// Variables declaration - do not modify
private javax.swing.JPanel painel;
// End of variables declaration
}
[/code]Desculpe pela bagunça, a maior parte disso é gerada pelo Netbeans.
Mapa.java
package jogodavida;
public class Mapa
{
// true = celula viva
private boolean[][] matriz;
private int altura;
private int largura;
public Mapa(int largura, int altura)
{
this.matriz = new boolean[altura][largura];
this.altura = altura;
this.largura = largura;
}
/**
* x = matriz[linha][coluna]
*
* Vizinhos de x na matriz:
*
* 123
* 4x5
* 678
*
* @param linha
* @param coluna
* @return int quantidade de vizinhos vivos da célula
*/
private int getQtdVizinhos(int linha, int coluna)
{
int qtd = 0;
// Faz um mapa sem fronteiras, onde indo p/ cima acaba saido em baixo
int linhaCima = (linha == 0) ? altura - 1 : linha - 1;
int linhaBaixo = (linha == altura - 1) ? 0 : linha + 1;
int colunaCima = (coluna == 0) ? largura - 1 : coluna - 1;
int colunaBaixo = (coluna == largura - 1) ? 0 : coluna + 1;
//1
if (matriz[linhaCima][colunaCima])
qtd++;
//2
if (matriz[linhaCima][coluna])
qtd++;
//3
if (matriz[linhaCima][colunaBaixo])
qtd++;
//4
if (matriz[linha][colunaCima])
qtd++;
//5
if (matriz[linha][colunaBaixo])
qtd++;
//6
if (matriz[linhaBaixo][colunaCima])
qtd++;
//7
if (matriz[linhaBaixo][coluna])
qtd++;
//8
if (matriz[linhaBaixo][colunaBaixo])
qtd++;
return qtd;
}
/**
* Regra 1: Celula morre se vizinhos < 2
* Regra 2: Celula morre se vizinhos > 3
* Regra 3: Celula nasce se vizinhos == 3
* Regra 4: Celula continua a mesma se vizinhos == 2
*
* @param linha
* @param coluna
* @return boolean Novo estado da célula
*/
private boolean aplicaRegras(int linha, int coluna)
{
int qtd = getQtdVizinhos(linha, coluna);
if (matriz[linha][coluna] && (qtd < 2 || qtd > 3))
return false;
else if (!matriz[linha][coluna] && qtd == 3)
return true;
else
return matriz[linha][coluna];
}
/**
* Calcula o próximo estado do mapa de células
*/
public void avaliaTodos()
{
boolean[][] matrizNova = new boolean[altura][largura];
for (int linha = 0; linha < altura; linha++)
for (int coluna = 0; coluna < largura; coluna++)
matrizNova[linha][coluna] = aplicaRegras(linha, coluna);
matriz = matrizNova;
}
public void mudaCelula(int linha, int coluna)
{
if (linha < 0 || linha >= altura || coluna < 0 || coluna >= largura)
throw new IndexOutOfBoundsException("Índice: (" + linha + "," + coluna + ")");
matriz[linha][coluna] = !matriz[linha][coluna];
}
public void limpar()
{
this.matriz = new boolean[altura][largura];
}
public boolean[][] getMatriz()
{
return matriz;
}
public int getAltura()
{
return altura;
}
public int getLargura()
{
return largura;
}
}