gpt4 book ai didi

java - 游戏面板实例的鼠标监听器

转载 作者:行者123 更新时间:2023-12-02 08:39:30 24 4
gpt4 key购买 nike

我正在创建一个 Tic Tac Toe 游戏,其中使用 MouseListener 向我的游戏面板添加功能。当用户单击其中一个单元格时,它会根据轮到的人生成一个 X 或 O 图形。我尝试将 MouseListener 添加到 Pane 中,但是当我运行它时,单击时没有任何反应。关于如何解决这个问题有什么想法吗?

这是我的游戏面板:

public GameMain() {
Handler handler = new Handler();
this.addMouseListener(handler);

// setup JLabel
label = new JLabel(" ");
label.setBorder(BorderFactory.createEmptyBorder(2, 5, 4, 5));
label.setOpaque(true);
label.setBackground(Color.LIGHT_GRAY);

setLayout(new BorderLayout());
add(label, BorderLayout.SOUTH);
setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT + 30));
board = new Board();
initGame();

}
}

这是我的 Handler 类,其中包含应该运行的 mouseClick() 方法:

public class Handler extends MouseAdapter {
public void mouseClick(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();

// Get the row and column clicked
int rowSelected = mouseY / CELL_SIZE;
int colSelected = mouseX / CELL_SIZE;

if (currentState == GameState.PLAYING) {
if (rowSelected >= 0 && rowSelected < board.cells.length && colSelected >= 0 && colSelected < board.cells.length &&
board.cells[rowSelected][colSelected].content == Seed.EMPTY) {
board.cells[rowSelected][colSelected].content = currentPlayer; // move
updateGame(currentPlayer, rowSelected, colSelected); // update currentState
currentPlayer = (currentPlayer == Seed.X) ? Seed.O : Seed.X;
}
} else {
initGame();
}

repaint();
}

public void handleButtonPress(Object o) {
if (o == singlePlayer) {
singlePlayerGame();
}
if (o == multiPlayer) {
multiPlayerGame();
}
}
}

最佳答案

你的问题激励我接受编写井字棋游戏的挑战,因为我在处理自定义绘画方面没有太多经验。下面的代码有很多注释,所以我希望这些注释能够很好地解释代码。

我假设比我更有经验的人会发现下面的代码中的缺陷,这是可以预料的,因为正如我已经提到的,我在这种编程方面没有很多经验。尽管如此,我希望它足够好,能够对您有所帮助。

请注意,以下代码使用了 JDK 14 中引入的新 Java 功能,即 Records 。因此,作为如何将 java 记录集成到他们的代码中的简单示例,它也可能对人们有所帮助。如果您没有使用 JDK 14 或者使用但尚未启用 preview features ,您可以简单地用一个简单的类替换记录定义。只需将单词 record 替换为 class 并在代码中添加构造函数和“getter”方法即可。默认情况下,记录中“getter”方法的名称只是字段的名称,例如对于记录 Square 中的成员 minX(在下面的代码中),“getter”方法是 minX()

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

/**
* A simple tic-tac-toe (a.k.a. noughts and crosses) game. User clicks mouse on an empty square of
* the game board and either a nought or a cross is drawn in that square, depending on whose turn
* it is. Each square has an index as shown below.
* <pre>
* 0 1 2
*
* 3 4 5
*
* 6 7 8
* </pre>
* See <a href="https://en.wikipedia.org/wiki/Tic-tac-toe">Tic-tac-toe</a> on <i>Wikipedia</i>.
*/
public class GameMain extends JPanel implements ActionListener, MouseListener, Runnable {

/** For serializing instances of this class. */
private static final long serialVersionUID = 7014608855599083001L;

/** A cross. */
private static final char CROSS = 'X';

/** A nought. */
private static final char NOUGHT = 'O';

/** Dimension of each square in tic-tac-toe board. */
private static final int SQUARE_DIMENSION = 80;

/** Number of consecutive squares required for a win. */
private static final int REQUIRED_SQUARES = 3;

/** Total number of squares in tic-tac-toe board. */
private static final int TOTAL_SQUARES = 9;

/** Each of the 9 squares in tic-tac-toe board. */
private final Square[] SQUARES = new Square[]{new Square(1, 1, 99, 99),
new Square(101, 1, 199, 99),
new Square(201, 1, 299, 99),

new Square(1, 101, 99, 199),
new Square(101, 101, 199, 199),
new Square(201, 101, 299, 199),

new Square(1, 201, 99, 299),
new Square(101, 201, 199, 299),
new Square(201, 201, 299, 299)};

/** Text for {@link #turnLabel} at start of a new tic-tac-toe game. */
private static final String FIRST_MOVE = "X goes first";

/** Text for <i>new game</i>. button. */
private static final String NEW_GAME = "New Game";

/** Indicates start of a new game. */
private boolean newGame;

/** <tt>true</tt> means O turn and <tt>false</tt> means X turn. */
private boolean oTurn;

/** Records occupied squares, either &apos;O&apos; or &apos;X&apos; */
private char[] occupied = new char[TOTAL_SQUARES];

/** Number of unoccupied squares in tic-tac-toe board. */
private int freeCount;

/** Displays whose turn it currently is. */
private JLabel turnLabel;

/** Location of last mouse click. */
private Point clickPoint;

/**
* Creates and returns instance of this class.
*/
public GameMain() {
setPreferredSize(new Dimension(300, 300));
addMouseListener(this);
freeCount = TOTAL_SQUARES;
}

private static boolean isValidRequirement(int index) {
return index >= 0 && index < REQUIRED_SQUARES;
}

/**
* Determines whether <var>square</var> is a valid index of a square in tic-tac-toe board.
*
* @param square - will be validated.
*
* @return <tt>true</tt> if <var>square</var> is valid.
*/
private static boolean isValidSquare(int square) {
return square >= 0 && square < TOTAL_SQUARES;
}

@Override // java.awt.event.ActionEvent
public void actionPerformed(ActionEvent actnEvnt) {
String actionCommand = actnEvnt.getActionCommand();
switch (actionCommand) {
case NEW_GAME:
startNewGame();
break;
default:
JOptionPane.showMessageDialog(this,
actionCommand,
"Unhandled",
JOptionPane.WARNING_MESSAGE);
}
}

@Override // java.awt.event.MouseListener
public void mouseClicked(MouseEvent mousEvnt) {
// Do nothing.
}

@Override // java.awt.event.MouseListener
public void mouseEntered(MouseEvent mousEvnt) {
// Do nothing.
}

@Override // java.awt.event.MouseListener
public void mouseExited(MouseEvent mousEvnt) {
// Do nothing.
}

@Override // java.awt.event.MouseListener
public void mousePressed(MouseEvent mousEvnt) {
// Do nothing.
}

@Override // java.awt.event.MouseListener
public void mouseReleased(MouseEvent mousEvnt) {
System.out.println("mouse clicked");
clickPoint = mousEvnt.getPoint();
repaint();
EventQueue.invokeLater(() -> {
String text;
if (isWinner()) {
text = oTurn ? "O has won!" : "X has won!";
removeMouseListener(this);
JOptionPane.showMessageDialog(this,
text,
"Winner",
JOptionPane.PLAIN_MESSAGE);
}
else if (freeCount <= 0) {
text = "Drawn game.";
removeMouseListener(this);
JOptionPane.showMessageDialog(this,
text,
"Draw",
JOptionPane.PLAIN_MESSAGE);
}
else {
oTurn = !oTurn;
text = oTurn ? "O's turn" : "X's turn";
}
turnLabel.setText(text);
});
}

@Override // java.lang.Runnable
public void run() {
createAndShowGui();
}

@Override // javax.swing.JComponent
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawLine(100, 0, 100, 300);
g2d.drawLine(200, 0, 200, 300);
g2d.drawLine(0, 100, 300, 100);
g2d.drawLine(0, 200, 300, 200);
if (!newGame) {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(3));
for (int i = 0; i < TOTAL_SQUARES; i++) {
if (occupied[i] == NOUGHT) {
drawNought(i, g2d);
}
else if (occupied[i] == CROSS) {
drawCross(i, g2d);
}
}
int square = getSquare(clickPoint);
if (isFreeSquare(square)) {
if (oTurn) {
drawNought(square, g2d);
occupied[square] = NOUGHT;
}
else {
drawCross(square, g2d);
occupied[square] = CROSS;
}
freeCount--;
}
}
else {
newGame = false;
}
}

private void createAndShowGui() {
JFrame frame = new JFrame("O & X");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.add(createTurnPanel(), BorderLayout.PAGE_START);
frame.add(this, BorderLayout.CENTER);
frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

private JButton createButton(String text, int mnemonic, String tooltip) {
JButton button = new JButton(text);
if (mnemonic > 0) {
button.setMnemonic(mnemonic);
}
if (tooltip != null && !tooltip.isBlank()) {
button.setToolTipText(tooltip);
}
button.addActionListener(this);
return button;
}

private JPanel createButtonsPanel() {
JPanel buttonsPanel = new JPanel();
buttonsPanel.setBorder(BorderFactory.createMatteBorder(2, 0, 0, 0, Color.GRAY));
buttonsPanel.add(createButton(NEW_GAME, KeyEvent.VK_N, "Start a new game."));
return buttonsPanel;
}

private JPanel createTurnPanel() {
JPanel turnPanel = new JPanel();
turnPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 2, 0, Color.GRAY));
turnLabel = new JLabel(FIRST_MOVE);
turnPanel.add(turnLabel);
return turnPanel;
}

/**
* Draws a {@link #CROSS} in <var>square</var> of tic-tac-toe board.
*
* @param square - index of square in tic-tac-toe board.
* @param g2d - facilitates drawing.
*/
private void drawCross(int square, Graphics2D g2d) {
if (isValidSquare(square) && g2d != null) {
g2d.setColor(Color.BLUE);
g2d.drawLine(SQUARES[square].minX() + 10,
SQUARES[square].minY() + 10,
SQUARES[square].maxX() - 10,
SQUARES[square].maxY() - 10);
g2d.drawLine(SQUARES[square].maxX() - 10,
SQUARES[square].minY() + 10,
SQUARES[square].minX() + 10,
SQUARES[square].maxY() - 10);
}
}

/**
* Draws a {@link #NOUGHT} in <var>square</var> of tic-tac-toe board.
*
* @param square - index of square in tic-tac-toe board.
* @param g2d - facilitates drawing.
*/
private void drawNought(int square, Graphics2D g2d) {
if (isValidSquare(square) && g2d != null) {
g2d.setColor(Color.RED);
g2d.drawOval(SQUARES[square].minX() + 10,
SQUARES[square].minY() + 10,
SQUARE_DIMENSION,
SQUARE_DIMENSION);
}
}

/**
* Returns the square of the tic-tac-toe board that contains <var>pt</var>.
*
* @param pt - point on tic-tac-toe board.
*
* @return index of square in tic-tac-toe board containing <var>pt</var> or -1 (negative one)
* if <var>pt</var> not in tic-tac-toe board.
*
* @see Square#contains(int, int)
*/
private int getSquare(Point pt) {
int ndx = -1;
if (pt != null) {
for (int i = 0; i < 9; i++) {
if (SQUARES[i].contains(pt.x, pt.y)) {
ndx = i;
break;
}
}
}
return ndx;
}

/**
* Determines whether <var>column</var> of tic-tac-toe board contains all {@link #CROSS} or all
* {@link #NOUGHT}.
*
* @param column - index of column in tic-tac-toe board.
*
* @return <tt>true</tt> if <var>column</var> contains all {@link #CROSS} or all {@link #NOUGHT}.
*
* @see #isValidRequirement(int)
*/
private boolean isColumnWin(int column) {
boolean isWin = false;
if (isValidRequirement(column)) {
isWin = isOccupied(column) &&
occupied[column] == occupied[column + REQUIRED_SQUARES] &&
occupied[column] == occupied[column + (REQUIRED_SQUARES * 2)];
}
return isWin;
}

/**
* Determines whether diagonal of tic-tac-toe board contains all {@link #CROSS} or all
* {@link #NOUGHT}. The board contains precisely two diagonals where each one includes the
* board&apos;s center square, i.e. the square with index 4. The other squares that constitute
* diagonals are the corner squares, including the indexes 0 (zero), 2, 6 and 8.
*
* @return <tt>true</tt> if one of the tic-tac-toe board diagonals contains all {@link #CROSS}
* or all {@link #NOUGHT}.
*
* @see #isValidRequirement(int)
*/
private boolean isDiagonalWin() {
boolean isWin = false;
isWin = (isOccupied(0) &&
occupied[0] == occupied[4] &&
occupied[0] == occupied[8])
||
(isOccupied(2) &&
occupied[2] == occupied[4] &&
occupied[2] == occupied[6]);
return isWin;
}

/**
* Determines whether <var>square</var> in tic-tac-toe board does not contain a {@link #CROSS}
* nor a {@link #NOUGHT}.
*
* @param square - index of square in tic-tac-toe board.
*
* @return <tt>true</tt> if <var>square</var> does not contain a {@link #CROSS} nor a {@link
* #NOUGHT}.
*/
private boolean isFreeSquare(int square) {
boolean freeSquare = false;
if (isValidSquare(square)) {
freeSquare = occupied[square] != CROSS && occupied[square] != NOUGHT;
}
return freeSquare;
}

/**
* Determines whether <var>row</var> of tic-tac-toe board contains all {@link #CROSS} or all
* {@link #NOUGHT}.
*
* @param row - index of row in tic-tac-toe board.
*
* @return <tt>true</tt> if <var>row</var> contains all {@link #CROSS} or all {@link #NOUGHT}.
*
* @see #isValidRequirement(int)
*/
private boolean isLineWin(int row) {
boolean isWin = false;
if (isValidRequirement(row)) {
int index = row * REQUIRED_SQUARES;
isWin = isOccupied(index) &&
occupied[index] == occupied[index + 1] &&
occupied[index] == occupied[index + 2];
}
return isWin;
}

/**
* Determines whether square at <var>index</var> in tic-tac-toe board contains either a {@link
* #CROSS} or a {@link #NOUGHT}.
*
* @param index - index of square in tic-tac-toe board.
*
* @return <tt>true</tt> if square at <var>index</var> in tic-tac-toe board contains either a
* {@link #CROSS} or a {@link #NOUGHT}.
*
* @see #isValidSquare(int)
*/
private boolean isOccupied(int index) {
boolean occupied = false;
if (isValidSquare(index)) {
occupied = this.occupied[index] == CROSS || this.occupied[index] == NOUGHT;
}
return occupied;
}

/**
* Determines if there is a winner.
*
* @return <tt>true</tt> if someone has won the game.
*
* @see #isColumnWin(int)
* @see #isDiagonalWin()
* @see #isLineWin(int)
*/
private boolean isWinner() {
return isLineWin(0) ||
isLineWin(1) ||
isLineWin(2) ||
isColumnWin(0) ||
isColumnWin(1) ||
isColumnWin(2) ||
isDiagonalWin();
}

/**
* Initializes the GUI in order to start a new game.
*/
private void startNewGame() {
freeCount = TOTAL_SQUARES;
newGame = true;
oTurn = false;
occupied = new char[TOTAL_SQUARES];
repaint();
EventQueue.invokeLater(() -> {
removeMouseListener(this);
addMouseListener(this);
turnLabel.setText(FIRST_MOVE);
});
}

/**
* This method is the first one called when this class is launched via the <tt>java</tt>
* command. It ignores the method parameter <var>args</var>.
*
* @param args - <tt>java</tt> command arguments.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new GameMain());
}
}

/**
* Represents the geometrical shape known as a square. For the purposes of this {@code record}, a
* square is defined by two points that indicate its top, left corner and its bottom, right corner.
*/
record Square (int minX, int minY, int maxX, int maxY) {

/**
* Determines whether the supplied point lies within this square.
*
* @param x - x coordinate of a point.
* @param y - y coordinate of same point (as x).
*
* @return <tt>true</tt> if supplied point lies within this square.
*/
public boolean contains(int x, int y) {
return minX <= x && x <= maxX && minY <= y && y <= maxY;
}
}

关于java - 游戏面板实例的鼠标监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61465380/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com