2014-10-12 53 views
2

我正在开发一个我的朋友发明的游戏 - 井字游戏的一点变化:使用4x4板,一个玩家(x)需要获得3 x的方式是特殊的,而另一方可以每转一圈放置一个'z'和一个'o',并且需要填充整个棋盘。我的问题不在于规则和算法,而在于图形:我没有很多图形方面的经验,只是无法让我的主板工作(即使没有任何规则 - 只是根据需要显示)。与使用图形和Java的井字游戏相类似的游戏的问题OOP

我有一个董事会类代表董事会。董事会有一个单元格的二维阵列。每个Cell(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(); 
      } 
     } 
    } 
} 

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]; 
    } 
} 

Turn.java:

public enum Turn { 
    X, O, Z; 

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

提前感谢!

+0

它看起来不像你在'GameMain'中用'paintComponent'做任何事情。你应该在该类中完全摆脱“paintComponent”方法。不要试图调用'board.paint(g);',只要在鼠标监听器中调用'board.repaint()',而不是试图重新绘制主游戏面板。 – 2014-10-12 09:29:23

+0

也在'Board'类中使用'paintComponent'而不是'paint'。并且不要忘记调用'super.paintComponent' – 2014-10-12 09:30:25

+0

感谢您的快速回答!我改变了它,但面板仍然无法加载!应该注意的是,目前我更关心让屏幕出现在屏幕上,而不是让整个程序根据需要运行,因此有些事情没有完成(即,wonX返回false,因为我稍后将更新它,现在我只是想要加载电路板,以便进步)。 – Trouble 2014-10-12 10:00:58

回答

5

所以它运行后,您得到的ArrayIndexOutOfBoundsException在该线路Board类的paint方法:不知道你的游戏是如何工作的,但通过看前面这一个环

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

,您只能访问索引3(for (int j = 1; j < 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?


就像我在我的评论说,

它看起来并不像你正在做与在GameMainpaintComponent什么。你应该在该课程中完全摆脱paintComponent方法。不要试图拨打board.paint(g);尝试在鼠标侦听器中调用board.repaint(),而不是尝试重新绘制主游戏面板。只需在GameMain的构造函数中设置背景,而不是在paintComponent方法中。

同样在理事会类别使用paintComponent而不是paint。不要忘记调用super.paintComponentpaintComponent方法

修复上面的所有的东西,得到它的工作(我猜)。


UPDATE

正如狂人在下面的评论中指出,这将是最好使用_cells.length以避免依赖幻数。通过这种方式,你将确保不会访问一个不存在的索引

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

如果你可以访问单元格,使用'cells.length'和'cells [i] .length' ... nit picking是不是更好?) – MadProgrammer 2014-10-12 11:00:44

+0

@MadProgrammer是的。 :P – 2014-10-12 11:05:51

+0

哦,男孩,我为丢掉那个而感到羞愧。这是因为起初我想制作5x5的棋盘。非常感谢你们!我通过做你说的话来修复它,并设法解决ImageIcon的一些问题(通过阅读堆栈跟踪),并且现在板子已经启动并运行 - 现在剩下的就是使规则工作:) – Trouble 2014-10-12 15:03:09