gpt4 book ai didi

java - 生命游戏未正确重置

转载 作者:行者123 更新时间:2023-12-02 01:05:40 26 4
gpt4 key购买 nike

我试图在单击重置按钮时重置我的生命游戏版本,但遇到问题。单击按钮后,一切都成功重置,但我们看到世代移动的主 Jpanel 却没有重置。我有两个 JLabel,一个显示当前代的数量,另一个显示该代中活细胞的数量。它们都已成功重置,但主 JPanel 只是卡住,我再也看不到动画了。

GameOfLife 类:

public class GameOfLife extends JFrame implements ActionListener {

private static class GameStep extends TimerTask {
static GameOfLife life = new GameOfLife();

@Override
public void run() {
updateLabels();
}
}

static JLabel aliveLabel = new JLabel("Alive:");
static JLabel GenerationLabel = new JLabel("Generation #");
static CellGrid body = new CellGrid();
static JPanel header = new JPanel();
static int genNumber = 1;
static JButton PlayToggleButton = new JButton("pause");
static JButton ResetButton = new JButton("reset");
static Boolean isPaused = false;
static GameStep game = new GameStep();
static Timer timer = new Timer();


public GameOfLife() {
super("Game of life");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(700, 660);
setLocationRelativeTo(null);
setLayout(new FlowLayout());

GenerationLabel.setName("GenerationLabel");
aliveLabel.setName("aliveLabel");
PlayToggleButton.setName("PlayToggleButton");
ResetButton.setName("ResetButton");

PlayToggleButton.addActionListener(this);
ResetButton.addActionListener(this);

PlayToggleButton.setIcon(new ImageIcon(play));
ResetButton.setIcon(new ImageIcon(reset));

PlayToggleButton.setPreferredSize(new Dimension(40,30));
ResetButton.setPreferredSize(new Dimension(40,30));

header.setLayout(new FlowLayout());
header.setPreferredSize(new Dimension(100, this.getHeight()));
header.add(PlayToggleButton);
header.add(ResetButton);
header.add(GenerationLabel);
header.add(aliveLabel);

body.setLayout(new BorderLayout());
body.setPreferredSize(new Dimension(500, this.getHeight()));

add(header, BorderLayout.WEST);
add(body, BorderLayout.CENTER);
setVisible(true);

}

public static void updateLabels(){
body.run();
GenerationLabel.setText("Generation #"+ genNumber++);
aliveLabel.setText("Alive: "+ body.totalAlive());
}

@Override
public void actionPerformed(ActionEvent e) {

if(e.getActionCommand().equals("pause")){
pauseResume();
}
else if(e.getActionCommand().equals("reset")){
reset();
}
}

static void loopStep(){
timer.schedule(game, 0,1000);
}

static void pauseResume() {

if(!isPaused){
isPaused = true;
timer.cancel();
}
else{
isPaused = false;
timer = new Timer();
timer.schedule(new GameStep(), 0,1000);
}
}
static void reset() {
timer.cancel();
isPaused = false;

genNumber = 1;
header = new JPanel();
body = new CellGrid();
body.repaint();

timer = new Timer();
timer.schedule(new GameStep(), 0,1000);
}

public static void main(String[] args) {
loopStep();
}
}

CellGrid 类:

public class CellGrid extends JPanel implements Runnable{
private static final int ROWS = 60;
private static final int COLS = 60;
private static final int CELL_WIDTH = 10;
private static Cell[][] cellGrid = new Cell[ROWS][COLS];

public CellGrid() {
for (int row = 0; row < cellGrid.length; row++) {
for (int col = 0; col < cellGrid[row].length; col++) {
int x = col * CELL_WIDTH;
int y = row * CELL_WIDTH;
cellGrid[row][col] = new Cell(x, y, CELL_WIDTH);

if (new Random().nextBoolean()) {
cellGrid[row][col].setAlive(true);
} else {
cellGrid[row][col].setAlive(false);
}
}
}
}
public int totalAlive(){
int totalAlive = 0;
for (Cell[] cells : cellGrid) {
for (int j = 0; j < cellGrid.length; j++) {
if (cells[j].isAlive())
totalAlive++;
}
}
return totalAlive;
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
for (Cell[] cellRow : cellGrid) {
for (Cell cell : cellRow) {
cell.draw(g2);
}
}
}

@Override
public void run() {
cellGrid = new GenerationMaker4().nextGeneration(cellGrid);
repaint();
}
}

知道为什么会这样吗?

最佳答案

您的reset()方法:

static void reset() {
timer.cancel();
isPaused = false;

genNumber = 1;
header = new JPanel();
body = new CellGrid();
body.repaint();

timer = new Timer();
timer.schedule(new GameStep(), 0,1000);
}

这个问题是新手常见的错误——您认为更改变量引用会更改该变量最初引用的先前对象。

具体来说,你有 body = new CellGrid(); ,它的作用是让 body 变量引用一个新的 CellGrid 对象,但是(这是重要的部分),它*确实当前显示在 GUI 中的 CellGrid 对象与之前引用的 body 变量无关。

几种替代解决方案:

  • 将 body 变量中现在引用的新 CellGrid 对象添加到 GUI 中相同的 BorderLayout 位置,覆盖前一个
  • 更好的是不要创建新的 CellGrid 对象,而是创建一种将当前 CellGrid 设置回其初始状态的方法。

例如,如果您将 CellGrid 更改为...

public class CellGrid extends JPanel implements Runnable{
private static final int ROWS = 60;
private static final int COLS = 60;
private static final int CELL_WIDTH = 10;
private Cell[][] cellGrid = new Cell[ROWS][COLS]; // make this non-static

public CellGrid() {
reset();
}

public void reset() {
cellGrid = new Cell[ROWS][COLS];
for (int row = 0; row < cellGrid.length; row++) {
for (int col = 0; col < cellGrid[row].length; col++) {
int x = col * CELL_WIDTH;
int y = row * CELL_WIDTH;
cellGrid[row][col] = new Cell(x, y, CELL_WIDTH);

if (new Random().nextBoolean()) {
cellGrid[row][col].setAlive(true);
} else {
cellGrid[row][col].setAlive(false);
}
}
}
}

// ..... more code below

然后您需要做的就是对当前 CellGrid 对象调用 reset(),然后调用 repaint()

其他问题:

  • 您严重过度使用了 static 修饰符。除了 main 方法、常量之外,该程序中的任何内容都不应是静态的。这对于这个小程序来说可能并不重要,但是当您尝试进行单元测试或扩展或增强该程序或将其添加到另一个较大的程序时,它会变得很重要。
  • 您使用 java.util.Timerjava.util.TimerTask 在 Swing GUI 程序中运行动画循环,这样做并不安全,因为这些类不是 Swing 线程安全的。最好使用 javax.swing.Timer 或“Swing Timer”代替这两个类来运行动画,因为这对于该 GUI 库来说是线程安全的。

关于java - 生命游戏未正确重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60086125/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com