【问题标题】:Problems with a game similar to Tic Tac Toe using graphics and java OOP使用图形和 java OOP 的类似于井字游戏的问题
【发布时间】:2014-10-12 09:17:23
【问题描述】:

我正在开发我的朋友们发明的游戏 - 井字游戏的一些变化:使用 4x4 棋盘,一个玩家 (x) 需要以特定方式获得 3 个 x,而另一个玩家可以放置一个“z”每转一个“o”,需要填满整个棋盘。我的问题不在于规则和算法,而在于图形:我在图形方面没有很多经验,只是无法让我的电路板工作(即使没有任何规则 - 只是根据需要显示)。

我有一个代表板的 Board 类。一块板有一个二维的单元阵列。每个单元格(单元格 = 我的另一类)也是一个 JButton,我希望每次单击按钮时他的图像都会改变 - 所以我决定使用 ImageIcon。我还有一个 GameMain 类来控制游戏和一个 Tools 类来添加两个按钮 - “退出”和“重置”。

如果您能通过建议方法让我的电路板正确加载来帮助我,我将不胜感激。目前该板根本不显示,如果我稍微调整一下代码,它会显示但按钮根本不会显示。

代码如下:GameMain.java:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class GameMain extends JPanel {
    private Turn _turn;
    Board _board;
    private Tools _buttons;
    private boolean isOver = false;

    public enum GameState {PLAYING, xWON, oWON};

    private GameState _currentState;

    // Name-constants for the various dimensions used for graphics drawing
    public static final int CELL_SIZE = 100; // cell width and height (square)
    public static final int CANVAS_WIDTH = CELL_SIZE * 4;  // the drawing canvas
    public static final int CANVAS_HEIGHT = CELL_SIZE * 4;
    public static final int GRID_WIDTH = 8;  // Grid-line's width
    public static final int GRID_WIDTH_HALF = GRID_WIDTH / 2; // Grid-line's half-width

    public GameMain() {
        this.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                if (_currentState == GameState.PLAYING) {
                    updateGame();
                } else {
                    initGame(); //game over, restart
                }
                repaint();
            }
        });

        setLayout(new BorderLayout());
        setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT + 30));
        _board = new Board();
        _buttons = new Tools();
        initGame();
        _buttons.SetObject(_board);

        add(_board, BorderLayout.CENTER);
        add(_buttons, BorderLayout.SOUTH);
    }

    public void initGame() {
        _turn = Turn.X;
        _board.init();
        _currentState = GameState.PLAYING;
    }

    public void updateGame() {
        if (_board.hasWonX()) {
            _currentState = GameState.xWON;
        } else if (_board.hasWonO()) {
            _currentState = GameState.oWON;
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        setBackground(Color.WHITE);

        _board.paint(g);
    }


    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("xBlock");
                frame.setSize(500, 500);
                // Set the content-pane of the JFrame to an instance of main JPanel
                frame.setContentPane(new GameMain());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null); // center the application window
                frame.setVisible(true);            // show it
            }
        });
    }
}

董事会:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class Board extends JPanel implements ActionListener {
    private Cell[][] _cells;
    private Turn _turn;

    public Board() {
        setLayout(new GridLayout(4, 4));

        _cells = new Cell[4][4];
        _turn = Turn.X;

        for (int i = 0; i < _cells.length; i++) {
            for (int j = 0; j < _cells[0].length; j++) {
                _cells[i][j] = new Cell(i, j);
                _cells[i][j].addActionListener(this);
                add(_cells[i][j]);
            }
        }
    }

    //initiate board
    public void init() {
        _turn = Turn.X;
        for (int i = 0; i < _cells.length; i++) {
            for (int j = 0; j < _cells[0].length; j++) {
                _cells[i][j].setState(State.EMPTY);
            }
        }

    }

    public void fillCell(Cell c) {
        if (c.getState() == State.EMPTY) {
            c.setState(_turn.ordinal());
            c.setEnabled(false);
            c.draw();
            _turn = _turn.getNext();
        }
    }

    public void checkCellsAround(Cell c) {
        State state = c.getState();
        State right, left, up, down;

        if (c.getJ() < 3 && c.getJ() > 0) {
            right = _cells[c.getI()][c.getJ() + 1].getState();
            left = _cells[c.getI()][c.getJ() - 1].getState();
        } else if (c.getJ() == 0) {
            right = _cells[c.getI()][c.getJ() + 1].getState();
            left = State.EMPTY;
        } else {
            right = State.EMPTY;
            left = _cells[c.getI()][c.getJ() - 1].getState();
        }

        if (c.getI() < 3 && c.getI() > 0) {
            up = _cells[c.getI() - 1][c.getJ()].getState();
            down = _cells[c.getI() + 1][c.getJ()].getState();
        } else if (c.getI() == 0) {
            up = State.EMPTY;
            down = _cells[c.getI() + 1][c.getJ()].getState();
        } else {
            up = _cells[c.getI() - 1][c.getJ()].getState();
            down = State.EMPTY;
        }

        switch (state) {
            case EMPTY:
                break;
            case X:
                if ((left == State.O && right == State.O) || (up == State.O && down == State.O) || (left == State.Z && right == State.Z) || (up == State.Z && down == State.Z)) {
                    c.setState(State.HOURGLASS);
                }
                break;
            case O:
                if ((left == State.X && right == State.X) || (up == State.X && down == State.X)) {
                    c.setState(State.EMPTY);
                }
                break;
            case Z:
                if ((left == State.X && right == State.X) || (up == State.X && down == State.X)) {
                    c.setState(State.HOURGLASS);
                }
                break;
            case HOURGLASS:
                break;
            case SCRIBBLE:
                break;
        }

    }

    public void actionPerformed(ActionEvent E) {
        Cell c = (Cell) E.getSource();
        fillCell(_cells[c.getI()][c.getJ()]);
    }

    public boolean hasWonO() {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (_cells[i][j].getState() == State.EMPTY) {
                    return false;
                }
            }
        }
        return true;
    }

    public boolean hasWonX() {
        return false;
    }


    public void paint(Graphics g) {
        g.setColor(Color.GRAY);
        for (int i = 1; i < 4; i++) {
            g.fillRoundRect(0, GameMain.CELL_SIZE * i - GameMain.GRID_WIDTH_HALF,
                    GameMain.CANVAS_WIDTH - 1, GameMain.GRID_WIDTH,
                    GameMain.GRID_WIDTH, GameMain.GRID_WIDTH);
        }
        for (int j = 1; j < 4; j++) {
            g.fillRoundRect(GameMain.CELL_SIZE * j - GameMain.GRID_WIDTH_HALF, 0,
                    GameMain.GRID_WIDTH, GameMain.CANVAS_HEIGHT - 1,
                    GameMain.GRID_WIDTH, GameMain.GRID_WIDTH);
        }
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                _cells[i][j].draw();
            }
        }
    }
}

Cell.java:

    import javax.swing.ImageIcon;
import javax.swing.JButton;

public class Cell extends JButton {
    private int _i, _j;
    private State _state;

    ImageIcon X = new ImageIcon(this.getClass().getResource("x-icon.png"));
    ImageIcon O = new ImageIcon(this.getClass().getResource("o-icon.png"));
    ImageIcon Z = new ImageIcon(this.getClass().getResource("z-icon.png"));
    ImageIcon Hourglass = new ImageIcon(this.getClass().getResource("hourglass-icon.png"));
    ImageIcon Scribble = new ImageIcon(this.getClass().getResource("scribble-icon.png"));

    public Cell() {
        this.setEnabled(true);
        _i = 0;
        _j = 0;
        _state = State.EMPTY;

    }

    public Cell(int i, int j) {
        this.setEnabled(true);
        _i = i;
        _j = j;
        _state = State.EMPTY;
    }

    public int getI() {
        return _i;
    }

    public int getJ() {
        return _j;
    }

    public void setState(State state) {
        _state = state;
        if (state == State.EMPTY) {
            this.setEnabled(true);
        }
    }

    public void setState(int index) {
        _state = State.values()[index];
    }

    public State getState() {
        return _state;
    }

    public void draw() {
        switch (_state) {
            case EMPTY:
                this.setIcon(null);
                break;

            case X:
                this.setIcon(X);
                break;

            case O:
                this.setIcon(X);
                break;

            case Z:
                this.setIcon(X);
                break;

            case HOURGLASS:
                this.setIcon(X);
                break;

            case SCRIBBLE:
                this.setIcon(X);
                break;
        }
    }

    public void highlight() {
    }
}

Tools.java:

 import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class Tools extends JPanel {

    private JButton _exit, _reset;
    private Board _board;

    Tools() {
        setLayout(new FlowLayout());

        _exit = new JButton("Exit");
        _reset = new JButton("Reset");

        _exit.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                System.exit(0);
            }
        });

        _reset.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                _board.init();
            }
        });
        add(_exit);
        add(_reset);
    }

    public void SetObject(Board b) {
        _board = b;
    }

}

State.java:

public enum State {
    EMPTY, X, O, Z, HOURGLASS, SCRIBBLE;


    public State getNext() {
        return State.values()[(this.ordinal() + 1) % State.values().length];
    }
}

转.java:

public enum Turn {
    X, O, Z;

    public Turn getNext() {
        return Turn.values()[(this.ordinal() + 1) % Turn.values().length];
    }
}

提前致谢!

【问题讨论】:

  • 您似乎没有对GameMain 中的paintComponent 执行任何操作。您应该在该类中完全摆脱 paintComponent 方法。不要尝试调用board.paint(g);,而是尝试在鼠标侦听器中仅调用board.repaint(),而不是尝试重新绘制主游戏面板。
  • 同样在Board 类中使用paintComponent 而不是paint。别忘了打电话给super.paintComponent
  • 感谢您的快速回答!我更改了它,但面板仍然无法加载!应该注意的是,目前我更关心的是让板子出现在屏幕上,而不是让整个程序根据需要运行,因此有些事情还没有完成(即 wonX 返回 false,因为我稍后会更新它,现在我只想加载板子,这样我就可以进步了)。

标签: java swing oop graphics


【解决方案1】:

所以在运行之后,你会在Board类的paint方法的这一行得到一个ArrayIndexOutOfBoundsException

    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            _cells[i][j].draw();       <==========
        }
    }

不确定您的游戏是如何运行的,但通过查看之前的循环,您只能访问索引 3 (for (int j = 1; j &lt; 4; j++) {)。因此,如果您将循环最大值更改为 4,它会启动并运行游戏。

    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            _cells[i][j].draw();
        }
    }

学习阅读异常和堆栈跟踪非常重要。它将为您省去很多未来的麻烦。花点时间阅读What is a stack trace, and how can I use it to debug my application errors?


就像我在我的 cmets 中所说的,

您似乎没有对GameMain 中的paintComponent 执行任何操作。您应该在该类中完全摆脱 paintComponent 方法。不要尝试调用board.paint(g);,而是尝试在鼠标侦听器中调用board.repaint(),而不是尝试重新绘制主游戏面板。并且只需在GameMain 的构造函数中设置背景,而不是在paintComponent 方法中。

同样在 Board 类中使用 paintComponent 而不是 paint。并且不要忘记在paintComponent 方法中调用super.paintComponent

解决以上所有问题,让它工作(我猜)。


更新

正如 MadMan 在下面的评论中指出的那样,最好使用 _cells.length 来避免依赖幻数。这样你就可以确保不会访问不存在的索引

for (int i = 0; i < cells.length; i++) {
    for (int j = 0; j < cells[i].length; j++) {
        _cells[i][j].draw();
    }
}

【讨论】:

  • 如果您可以访问cells,使用cells.lengthcells[i].length 会不会更好......挑剔;)
  • @MadProgrammer 是的。 :P
  • 哦,孩子,我为错过这一点而感到羞愧。这是因为一开始我想把板子做成 5x5。非常感谢你们!我按照您所说的进行了修复 + 设法修复了 ImageIcon 的一些问题(通过读取堆栈跟踪),并且电路板现在已启动并正在运行 - 现在剩下的就是使规则起作用:)
  • 现在我可以给 +1 了 ;)
  • 1+ 但@Trouble 也覆盖了paint(...) 而不是paintComponent(...) 并且没有调用任何超级绘画方法,这是为Trouble 设置的麻烦。
猜你喜欢
  • 2017-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多