- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在创建一个 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 'O' or 'X' */
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'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/
我有一个 Bootstrap 面板,里面有另一个面板。两者在面板标题中都有一个字形图标。默认情况下,面板是折叠的。当面板折叠时,将设置 glyphicon-unchecked。当我点击这个字形图标时,
使用 Grafana 时,我们会在某些电视上使用它。有谁知道制作它的方法,如果有人添加面板,更改布局等,它不仅会自动刷新数据,还会自动刷新实际仪表板? 我们真的厌倦了不断要求具有远程访问权限的人登录并
基本上,我试图让屏幕底部有 3 个按钮,然后在屏幕中间有一个包含文字的标签。但是,我似乎无法同时在 GUI 中同时拥有按钮和标签。我是一名初学者,对布局了解不多(即使我已经阅读过它们),因此任何帮助/
作为学校的类(class)作业,我们必须提出一个自定义项目,我选择了一个原本打算在 ActionScript 上编写的游戏创意,但决定在 Java 上插入它。最初进展顺利,游戏代码正常运行, Spri
我正在尝试使用 Java Graphics 制作一个生命模拟游戏,但是当运行我的代码时,屏幕的左侧三分之一是灰色的。我希望整个屏幕是白色的,黑色方 block 代表生命方 block 。我对所有 ja
下面是动态驱动的一个不错的“下拉面板”。 http://www.dynamicdrive.com/dynamicindex17/dddropdownpanel.htm 如您所见,它是一个面板,在打开时
所以我有这个函数 onDisplayError ,如果请求失败,每次都会调用它。这意味着如果用户按下保存按钮并且 3 个请求失败,我当前会收到 3 个弹出消息。我的目标是此函数检查我的弹出窗口是否已打
我正在尝试为我的一个类(class)制作一款游戏,但在实现一些我想做的事情时遇到了麻烦。本质上,我希望在同一个图形用户界面窗口中包含多个不同的部分。 据我了解,我会使用 JPanel 来创建这些不同的
我目前正在测试这种类型的面板 jquery: http://codyhouse.co/gem/css-slide-in-panel/ 但是当我想检测从顶部滚动以显示一个 div 时:没办法:( 一种检
我可能正在搜索错误的问题,但我找不到这个问题的答案。 我有一个 AutoScroll 设置为 true 的面板。控件动态添加到面板。我需要在滚动条可见时触发一个事件,但我找不到这样的事件。 如有任何建
我有一堆 Bootstrap 面板,其中一些是相互关联的。有点像 Panel A -> Panel B -> Panel C 当用户单击面板 B 时,将显示面板 C,当单击面板 C 时,将显示面板 D
我正在尝试开发一种带有指标的下拉列表,并相应地针对应该出现在仪表板上的选定指标特定面板。反之亦然,如果未选择指标,则面板应隐藏。 我找到了链接 http://search-devops.com/m/k
我有一个窗口,窗口里面有面板。我动态地向面板添加组件。这些组件采用“hbox”布局,以便它们水平排列。单击按钮后,我将在“hbox”布局中再向面板添加一行类似组件。这里的问题是我想在第一行下面添加第二
我使用 jQuery Accordion 将表单拆分为多个面板,并使用 jQuery 验证来检查所需字段。只要验证字段位于打开的面板中,它就可以很好地显示已验证字段中的错误。 举个例子。假设我有三个
我正在尝试检查我的面板是打开还是关闭。 我尝试过这样的: $(document).on('open', '.ui-panel', function(){ console.log('open');
我有一个面板,我想将其 float 在所有窗口之上并出现在所有空间中。这可以通过 轻松完成 [self.panel setLevel:kCGUtilityWindowLevel]; [self.win
我想在格子中的单个面板上叠加多个组,并且想要独立的回归线。 获得多个面板相当容易,每个面板都有一条使用条件因子的回归线: xyplot( Petal.Width ~ Petal.Length |
Delphi 有滑动(动画)面板组件吗? 例如可以在 Raize Components 中找到它(带有“热点”或隐藏/显示按钮的左侧面板)。 我不需要一个可调整大小的面板,而是一个可以从左向右水平平滑
我有一个 Bootstrap Accordion : 我想禁用非事件面板中的所有输入控件。仅验证事件面板。 我有一个检测事件选项卡的功能: $(".panel").on("show.bs.collap
我正在尝试将组件放入不同尺寸的面板中。但是,我意识到 GridLayout 将大小相同的部分分开。如何实现如下图所示 enter image description here import java.
我是一名优秀的程序员,十分优秀!