1

所以我正在制作一款类似于 Connect 4 的游戏。真的是 Connect 4X4。

但我现在的问题是,我在 JAVA 中绘制了一个网格,当单击单元格时,它会通过绘制一块来响应,但该块绘制在错误的位置。

我将主游戏板设置为位于屏幕的右侧,它可以完美地检测到点击事件,但是当点击它时,它会绘制圆圈,就好像网格从屏幕的左上角开始一样。

我将在下面发布 GUI 代码。

我的代码基于此处找到的示例:http ://www3.ntu.edu.sg/home/ehchua/programming/java/JavaGame_TicTacToe.html

我知道我的代码非常混乱,我没有发布所有代码,但问题在于代码的 Graphics 2D 部分。而且我知道它也与那里的 x1 和 y1 坐标有关,但我就是想不通。

以防万一我没有解释自己这里有我的代码问题的视频:http ://www.youtube.com/watch?v=hjcnVl2mjQs#t=0

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

@SuppressWarnings("serial")
public class Board extends JFrame {
   // Named-constants for the game board
   public static final int ROWS = 4;  // ROWS by COLS cells
   public static final int COLS = 4;

   // Named-constants of 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 * COLS;  // the drawing canvas  
   public static final int CANVAS_HEIGHT = CELL_SIZE * ROWS;
   public static final int GRID_WIDTH = 2;                   // Grid-line's width
   public static final int GRID_WIDHT_HALF = GRID_WIDTH / 2; // Grid-line's half-width
   // Symbols (cross/nought) are displayed inside a cell, with padding from border
   public static final int CELL_PADDING = CELL_SIZE / 8;
   public static final int SYMBOL_SIZE = CELL_SIZE - CELL_PADDING * 2; // width/height
   public static final int SYMBOL_STROKE_WIDTH = 2; // pen's stroke width
                       int y;
                       int x;
   public Field[] fieldArray = new Field[16];
   Field clickedField;
   int i = 0;
   int boardScreenWidth = 400;
   int boardScreenHeight = 400;
   int boardStartX = 370;
   int boardStartY = 130;
   int mouseXPos;
   int mouseYPos;


   // Use an enumeration (inner class) to represent the various states of the game
   public enum GameState {
      PLAYING, DRAW, Demon_Won, Angel_Won
   }
   private GameState currentState;  // the current game state

   // Use an enumeration (inner class) to represent the seeds and cell contents
   public enum Seed {
      EMPTY, Angel, Demon
   }
   private Seed currentPlayer;  // the current player



   private Seed[][] board   ;

                                                    // Game board of ROWS-by-COLS cells
   private DrawCanvas canvas; // Drawing canvas (JPanel) for the game board
   private JLabel statusBar;  // Status Bar

   /** Constructor to setup the game and the GUI components */
   public Board() {
      canvas = new DrawCanvas();  // Construct a drawing canvas (a JPanel)
      canvas.setPreferredSize(new Dimension(800, 600));

      // The canvas (JPanel) fires a MouseEvent upon mouse-click
      canvas.addMouseListener(new MouseAdapter() {
         @Override
         public void mouseClicked(MouseEvent e) {  // mouse-clicked handler
            int mouseX = e.getX();
            int mouseY = e.getY();


                if (mouseX < boardStartX || mouseX >= boardStartX + boardScreenWidth)
                    return;


                if (mouseY < boardStartY || mouseY >= boardStartY + boardScreenWidth)
                    return;



                //int mouseX = 320; // user clicked at x=320
                    mouseX = mouseX - boardStartX; // adjust based on board's position
                    int boardX = mouseX / CELL_SIZE;
                    // = 310 / 50
                     // = 6

                    mouseY = mouseY - boardStartY; // adjust based on board's position
                    int boardY = mouseY / CELL_SIZE;
                    // = 310 / 50
                     // = 6






            // Get the row and column clicked
            int rowSelected = mouseY / CELL_SIZE;
            int colSelected = mouseX / CELL_SIZE;
             //System.out.println(rowSelected);
             //System.out.println(colSelected);
            if (currentState == GameState.PLAYING) {
               if (rowSelected >= 0 && rowSelected < ROWS && colSelected >= 0
                     && colSelected < COLS && board[rowSelected][colSelected] == Seed.EMPTY) {
                  board[rowSelected][colSelected] = currentPlayer; // Make a move
                  updateGame(currentPlayer, rowSelected, colSelected); // update state
                  // Switch player
                  currentPlayer = (currentPlayer == Seed.Demon) ? Seed.Angel : Seed.Demon;
               }
            } else {       // game over
               initGame(); // restart the game
            }
            // Refresh the drawing canvas
            repaint();  // Call-back paintComponent().
         }
      });

      // Setup the status bar (JLabel) to display status message
      statusBar = new JLabel("  ");
      statusBar.setFont(new Font(Font.DIALOG_INPUT, Font.BOLD, 30));
      statusBar.setBorder(BorderFactory.createEmptyBorder(2, 5, 4, 5));

      Container cp = getContentPane();
      cp.setLayout(new BorderLayout());
      cp.add(canvas, BorderLayout.CENTER);
      cp.add(statusBar, BorderLayout.PAGE_END); // same as SOUTH

      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();  // pack all the components in this JFrame
      setTitle("Angels & Demons");
      setVisible(true);  // show this JFrame


      board = new Seed[ROWS][COLS];// allocate array


      initGame(); // initialize the game board contents and game variables
   }

   /** Initialize the game-board contents and the status */
   public void initGame() {

      for (int row = 0; row < ROWS; ++row) {
         for (int col = 0; col < COLS; ++col) {
            board[row][col] = Seed.EMPTY; // all cells empty
         }
      }


      currentState = GameState.PLAYING; // ready to play
      currentPlayer = Seed.Demon;       // cross plays first
   }

   /** Update the currentState after the player with "theSeed" has placed on
       (rowSelected, colSelected). */
   public void updateGame(Seed theSeed, int rowSelected, int colSelected) {
      if (hasWon(theSeed, rowSelected, colSelected)) {  // check for win
         currentState = (theSeed == Seed.Demon) ? GameState.Demon_Won : GameState.Angel_Won;
      } else if (isDraw()) {  // check for draw
         currentState = GameState.DRAW;
      }
      // Otherwise, no change to current state (still GameState.PLAYING).
   }

   /** Return true if it is a draw (i.e., no more empty cell) */
   public boolean isDraw() {
      for (int row = 0; row < ROWS; ++row) {
         for (int col = 0; col < COLS; ++col) {
            if (board[row][col] == Seed.EMPTY) {
               return false; // an empty cell found, not draw, exit
            }
         }
      }
      return true;  // no more empty cell, it's a draw
   }

   /** Return true if the player with "theSeed" has won after placing at
       (rowSelected, colSelected) */
   public boolean hasWon(Seed theSeed, int rowSelected, int colSelected) {
      return (board[rowSelected][0] == theSeed  // 3-in-the-row
            && board[rowSelected][1] == theSeed
            && board[rowSelected][2] == theSeed
            && board[rowSelected][3] == theSeed
       || board[0][colSelected] == theSeed      // 3-in-the-column
            && board[1][colSelected] == theSeed
            && board[2][colSelected] == theSeed
            && board[3][colSelected] == theSeed
       || rowSelected == colSelected            // 3-in-the-diagonal
            && board[0][0] == theSeed
            && board[1][1] == theSeed
            && board[2][2] == theSeed
            && board[3][3] == theSeed
       || rowSelected + colSelected == 3  // 3-in-the-opposite-diagonal
            && board[0][3] == theSeed
            && board[1][2] == theSeed
            && board[2][1] == theSeed
            && board[3][0] == theSeed);
   }

   /**
    *  Inner class DrawCanvas (extends JPanel) used for custom graphics drawing.
    */
   class DrawCanvas extends JPanel {
      @Override
      public void paintComponent(Graphics g) {  // invoke via repaint()
         i=0;
         super.paintComponent(g);    // fill background
         setBackground(Color.WHITE); // set its background color
         g.setColor(Color.blue);

         //making the filled borders
         g.fillRect(30, 560, 740, 30);
         g.fillRect(285, 130, 30, 400);
         g.fillRect(30, 10, 740, 90);

         g.drawRect(30, 350, 200, 180);

         // Draw the grid-lines
        for (y=130; y<530;y+=100) {
            for(x=370; x< 770; x+=100){

            g.drawRect(x, y, 100,100);

         }  
        }

            //drawing the piece selector
        for (y=130; y<280;y+=50){ 
    for(x=30; x < 180; x+=50){

            g.drawRect(x, y, 100, 100);


        }
        }

        //populating the piece selector
        for (y=130; y<305;y+=50){ 
        for(x=30; x < 205; x+=50){

            g.fillOval(x,y, 50, 50);

        }
        }

         Graphics2D g2d = (Graphics2D)g;
         g2d.setStroke(new BasicStroke(SYMBOL_STROKE_WIDTH, BasicStroke.CAP_ROUND,
               BasicStroke.JOIN_ROUND));  // Graphics2D only



         for (int row = 0; row < ROWS; ++row) {
            for (int col = 0; col < COLS; ++col) {     

                int x1 = col * (CELL_SIZE + CELL_PADDING);
                int y1 = row * (CELL_SIZE + CELL_PADDING);

               if (board[row][col] == Seed.Demon) {
                  g2d.setColor(Color.RED);
                  g2d.fillOval(x1, y1, SYMBOL_SIZE, SYMBOL_SIZE);
               } else if (board[row][col] == Seed.Angel) {
                  g2d.setColor(Color.GREEN);
                  g2d.fillOval(x1, y1, SYMBOL_SIZE, SYMBOL_SIZE);


               }

            }
         }



         // Print status-bar message
         if (currentState == GameState.PLAYING) {
            statusBar.setForeground(Color.blue);

            if (currentPlayer == Seed.Demon) {
               statusBar.setText("Player 1's Turn");
            } else {
               statusBar.setText("Player 2's Turn");
            }
         } else if (currentState == GameState.DRAW) {
            statusBar.setForeground(Color.RED);
            statusBar.setText("It's a Draw! Click to play again.");
         } else if (currentState == GameState.Demon_Won) {
            statusBar.setForeground(Color.RED);
            statusBar.setText("'Player 1' Won! Click to play again.");
         } else if (currentState == GameState.Angel_Won) {
            statusBar.setForeground(Color.RED);
            statusBar.setText("'Player 2' Won! Click to play again.");
         }
      }
   }

   /** The entry main() method */
   public static void main(String args[]) {

      // Run GUI codes in the Event-Dispatching thread for thread safety
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            new Board(); // Let the constructor do the job
         }
      });
   }
}
4

1 回答 1

4

这不应该:

int x1 = col * (CELL_SIZE + boardStartX) + CELL_PADDING;
int y1 = row * (CELL_SIZE+ boardStartY) + CELL_PADDING;

而是:

int x1 = col * (CELL_SIZE + CELL_PADDING) + boardStartX;
int y1 = row * (CELL_SIZE + CELL_PADDING) + boardStartY;

或许

int x1 = col * (CELL_SIZE + 2 * CELL_PADDING) + boardStartX;
int y1 = row * (CELL_SIZE + 2 * CELL_PADDING) + boardStartY;

如果每个单元格的两侧都有填充。


但是话虽如此,为了便于编码,我会完全不同地构建我的游戏/GUI:

  • 创建由使用 GridLayout 的 JPanel 持有的 4 x 4 的 JLabels 网格。
  • 让每个 JLabel 保存一个适当大小的空白 ImageIcon。
  • 给每个 JLabel 一个 MouseListener 来监听 mousePressed 事件。
  • 当按下 JLabel 时,如果它包含空白 ImageIcon,则将 Icons 与适当颜色的 ImageIcon 交换。
  • 要重置网格,请将所有图标更改回空白图标。
  • 这里不需要覆盖paintComponent 或担心在错误的位置绘制。
  • 您的彩色磁盘图标很容易制作:创建一个正确大小的 BufferedImage,获取其 Graphics2D 对象,设置其渲染提示以使用抗锯齿平滑,绘制一个彩色圆圈,处理 Graphics2D 对象,并创建一个 ImageIcon使用 BufferedImage。
于 2013-11-09T17:12:10.480 回答