我正在努力让我的生活游戏程序面向对象遵循我教授的风格指南,而不是失去分数,但我无法弄清楚如何以我的程序编码的方式这样做。
import java.awt.*;
import java.awt.event.*;
import java.util.Hashtable;
import javax.swing.*;
public class GameOfLife2 extends JFrame implements ActionListener {
static final Color[] color = { Color.LIGHT_GRAY, Color.BLUE };
// size in pixel of every label
static final int size = 15;
static final Dimension dim = new Dimension(size, size);
// the cells labels
private LifeLabel[][] label;
// timer that fires the next feneration
private Timer timer;
// generation counter
private int generation = 0;
private JLabel generationLabel = new JLabel("Generation: 0");
// the 3 buttons
private JButton bClear = new JButton("Clear"), bPause = new JButton("Pause"), bGo = new JButton("Go");
// the slider for the speed
JSlider slider = new JSlider(0, 5000); // 0 to 5000 milliseconds (5 seconds)
// state of the game (running or pause)
private boolean gameRunning = false;
// if the mouse is down or not
private boolean mouseDown = false;
GameOfLife2(int nbRow, int nbCol) {
super("GameOfLife");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// create the labels (2 more on each size) these wont be shown
// but will be used in calculating the cells alive around
label = new LifeLabel[nbRow + 2][nbCol + 2];
for (int r = 0; r < nbRow + 2; r++) {
for (int c = 0; c < nbCol + 2; c++) {
label[r][c] = new LifeLabel();
}
}
// panel in the center with the labels
JPanel panel = new JPanel(new GridLayout(nbRow, nbCol, 1, 1));
panel.setBackground(Color.BLACK);
panel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
// add each label (not the one on the border) to the panel and add to
// each of them its neighbours
for (int r = 1; r < nbRow + 1; r++) {
for (int c = 1; c < nbCol + 1; c++) {
panel.add(label[r][c]);
label[r][c].addNeighbour(label[r - 1][c]); // North
label[r][c].addNeighbour(label[r + 1][c]); // South
label[r][c].addNeighbour(label[r][c - 1]); // West
label[r][c].addNeighbour(label[r][c + 1]); // East
label[r][c].addNeighbour(label[r - 1][c - 1]); // North West
label[r][c].addNeighbour(label[r - 1][c + 1]); // North East
label[r][c].addNeighbour(label[r + 1][c - 1]); // South West
label[r][c].addNeighbour(label[r + 1][c + 1]); // South East
}
}
// now the panel can be added
add(panel, BorderLayout.CENTER);
// the bottom panel with the buttons the generation label and the slider
// this panel is formed grid panels
panel = new JPanel(new GridLayout(1, 3));
// another panel for the 3 buttons
JPanel buttonPanel = new JPanel(new GridLayout(1, 3));
bClear.addActionListener(this);
buttonPanel.add(bClear);
bPause.addActionListener(this);
bPause.setEnabled(false); // game is pause the pause button is disabled
buttonPanel.add(bPause);
bGo.addActionListener(this);
buttonPanel.add(bGo);
// add the 3 buttons to the panel
panel.add(buttonPanel);
// the generation label
generationLabel.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(generationLabel);
// the slider
slider.setMajorTickSpacing(1000);
slider.setMinorTickSpacing(250);
slider.setPaintTicks(true);
// the labels for the Slider
Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer, JLabel>();
for (int i = 0; i <= 5; i++) {
labelTable.put(new Integer(i * 1000), new JLabel("" + i));
}
slider.setLabelTable(labelTable);
slider.setPaintLabels(true);
panel.add(slider);
// in the JFrame
add(panel, BorderLayout.SOUTH);
// put the frame on
setLocation(20, 20);
pack();
setVisible(true);
// start the thread that run the cycles of life
timer = new Timer(5000 - slider.getValue(), this);
}
// called by the Timer and the JButtons
public synchronized void actionPerformed(ActionEvent e) {
// test the JButtons first
Object o = e.getSource();
// the clear button
if (o == bClear) {
timer.stop(); // stop timer
gameRunning = false; // flag gamme not running
bPause.setEnabled(false); // disable pause button
bGo.setEnabled(true); // enable go button
// clear all cells
for (int r = 1; r < label.length - 1; r++) {
for (int c = 1; c < label[r].length - 1; c++) {
label[r][c].clear();
}
}
// reset generation number and its label
generation = 0;
generationLabel.setText("Generation: 0");
return;
}
// the pause button
if (o == bPause) {
timer.stop(); // stop timer
gameRunning = false; // flag not running
bPause.setEnabled(false); // disable myself
bGo.setEnabled(true); // enable go button
return;
}
// the go button
if (o == bGo) {
bPause.setEnabled(true); // enable pause button
bGo.setEnabled(false); // disable myself
gameRunning = true; // flag game is running
timer.setDelay(5000 - slider.getValue());
timer.start();
return;
}
// not a JButton so it is the timer
// set the delay for the next time
timer.setDelay(5000 - slider.getValue());
// if the game is not running wait for next time
if (!gameRunning)
return;
++generation;
generationLabel.setText("Generation: " + generation);
for (int r = 0; r < label.length; r++) {
for (int c = 0; c < label[r].length; c++) {
label[r][c].checkState();
}
}
for (int r = 0; r < label.length; r++) {
for (int c = 0; c < label[r].length; c++) {
label[r][c].updateState();
}
}
}
// to start the whole thing as a Java application
public static void main(String[] arg) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GameOfLife2(30, 50);
}
});
}
// A class that extends JLabel but also check for the neigbour
// when asked to do so
class LifeLabel extends JLabel implements MouseListener {
private int state, newState;
private int nbNeighbour;
private LifeLabel[] neighbour = new LifeLabel[8];
LifeLabel() {
state = newState = 0; // Dead
setOpaque(true); // so color will be showed
setBackground(color[0]);
addMouseListener(this); // to select new LIVE cells
this.setPreferredSize(dim);
}
// to add a neibour
void addNeighbour(LifeLabel n) {
neighbour[nbNeighbour++] = n;
}
// to see if I should live or not
void checkState() {
// number alive around
int nbAlive = 0;
// see the state of my neighbour
for (int i = 0; i < nbNeighbour; i++)
nbAlive += neighbour[i].state;
// newState
if (state == 1) { // if alive
if (nbAlive < 2) // 1.Any live cell with fewer than two live
// neighbours dies
newState = 0;
if (nbAlive > 3) // 2.Any live cell with more than three live
// neighbours dies
newState = 0;
} else {
if (nbAlive == 3) // 4.Any dead cell with exactly three live
// neighbours becomes a live cell
newState = 1;
}
}
// after the run switch the state to new state
void updateState() {
if (state != newState) { // do the test to avoid re-setting same
// color for nothing
state = newState;
setBackground(color[state]);
}
}
// called when the game is reset/clear
void clear() {
if (state == 1 || newState == 1) {
state = newState = 0;
setBackground(color[state]);
}
}
@Override
public void mouseClicked(MouseEvent arg0) {
}
// if the mouse enter a cell and it is down we make the cell alive
public void mouseEntered(MouseEvent arg0) {
if (mouseDown) {
state = newState = 1;
setBackground(color[1]);
}
}
@Override
public void mouseExited(MouseEvent arg0) {
}
// if the mouse is pressed on a cell you register the fact that it is
// down
// and make that cell alive
public void mousePressed(MouseEvent arg0) {
mouseDown = true;
state = newState = 1;
setBackground(color[1]);
}
// turn off the fact that the cell is down
public void mouseReleased(MouseEvent arg0) {
mouseDown = false;
}
}
}
我从来没有非常擅长使我的程序面向对象并且通常坚持一个类,但我目前被迫使这个程序面向对象。
如果你不仅可以帮助我将这个程序改为OOP,而且还可以给我一些关于如何使用非OOP程序并使其成为那样的程序的提示,那将是非常棒的。
答案 0 :(得分:3)
只有一种方法可以真正进入OO:练习。想出要解决的问题的表示,在您看到的元素中寻找可辨别的实体,并设计表示这些元素的类。规划这些元素之间的互动和关系。
然后实施,看看哪些有效,哪些无效。即使你选择不好,你也会学到它,即使它只是一个特定的选择效果不佳。
首先,想象生命游戏,如果它是一个真实的,物理世界在你眼前。不同的实体应该是容易接近的,这是设计的良好开端。
当然,我们可以建议你将这个和那个抽象成一个或另一个对象,但如果你自己不做这项工作,那么很多选择对你来说将永远是个谜。只有实际做出自己的选择,你才能真正学到一些东西。
答案 1 :(得分:1)
OOP是关于对象(顾名思义:))。因此,为了改进您的OOP编程,首先要考虑游戏中组件之间的共同属性。
你已经为lifeLabel做了这件事。已被设置为邻居。而不是这种方法,每个邻居应该是一个对象,你可以有一个List。然后,可以最小化并更容易理解更新状态和检查状态。
使您的代码OOP
没有太多变化