使用图形和java OOP的类似于Tic Tac Toe的游戏的问题

使用图形和java OOP的类似于Tic Tac Toe的游戏的问题,java,swing,oop,graphics,Java,Swing,Oop,Graphics,我正在做一个我的朋友发明的游戏——tic-tac-toe的一个小变化:使用4x4板,一个玩家(x)需要以特定的方式获得3个x,而另一个玩家可以每回合放置一个“z”和一个“o”,并且需要填充整个板。我的问题不在于规则和算法,而在于图形:我对图形没有太多的经验,只是无法让我的电路板正常工作(即使没有任何规则-只要根据需要显示) 我有一个Board类,它代表一个Board。电路板具有二维单元阵列。每个单元格(Cell=我的另一个类)也是一个JButton,我希望每次单击按钮时,他的图像都会发生变化——

我正在做一个我的朋友发明的游戏——tic-tac-toe的一个小变化:使用4x4板,一个玩家(x)需要以特定的方式获得3个x,而另一个玩家可以每回合放置一个“z”和一个“o”,并且需要填充整个板。我的问题不在于规则和算法,而在于图形:我对图形没有太多的经验,只是无法让我的电路板正常工作(即使没有任何规则-只要根据需要显示)

我有一个Board类,它代表一个Board。电路板具有二维单元阵列。每个单元格(Cell=我的另一个类)也是一个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();
            }
        }
    }
}
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];
    }
}
Turn.java:

public enum Turn {
    X, O, Z;

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

提前谢谢

因此,在运行它之后,您将在
Board
类的绘制方法的这一行获得
ArrayIndexOutOfBoundsException

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

GameMain
中,您似乎没有对
paintComponent
执行任何操作。您应该在该类中完全去掉
paintComponent
方法。而不是试图调用
board.paint(g)
,尝试在鼠标侦听器中调用
board.repaint()
,而不是尝试重新绘制主游戏面板。在
board
类中,也可以使用
paintComponent
而不是
paint
。别忘了打电话给super.paintComponent谢谢你的快速回复!我改了,但面板还是无法加载!需要注意的是,目前我更关心的是让电路板显示在屏幕上,而不是让整个程序根据需要运行,因此有些事情没有完成(例如,wonX返回false,因为我稍后会更新它,现在我只想加载电路板,以便我可以继续)。如果您可以访问
单元格
,使用
单元格.length
单元格[i].length
…挑剔;)不是更好吗@是的老兄,我为错过这个感到羞愧。这是因为一开始我想把电路板做成5x5。非常感谢你们!我按照您所说的做了修复+成功地解决了ImageIcon的一些问题(通过读取堆栈跟踪),现在板已经启动并运行-现在剩下的就是让规则正常工作:)现在我可以给+1;)1+但是@Trouble也覆盖了
paint(…)
而不是
paintComponent(…)
,并且没有调用任何超级绘制方法,这是一种为麻烦设置的方法。
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j < 5; j++) {
            _cells[i][j].draw();       <==========
        }
    }
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            _cells[i][j].draw();
        }
    }
for (int i = 0; i < cells.length; i++) {
    for (int j = 0; j < cells[i].length; j++) {
        _cells[i][j].draw();
    }
}