我正在制作一个游戏,并且想在游戏结束并单击“休息”按钮后重置游戏板。目前,该游戏的首次运行效果不错。
我认为问题出在重置方法“ this.play()”中。有人可以给我解释一下这是怎么回事。
使用“ this.play()”时,GUI不会重置,游戏也不会播放。没有“ this.play()”,GUI会重置,但游戏无法正常工作。
我还想在每次单击按钮后而不是循环后运行check方法。我不断收到错误消息,指出不能从静态上下文中引用非静态方法。我一直在把check方法放在按钮类的actionPerformed方法中
这是我的代码...
董事会课程...
public class ticTacBoard extends JFrame implements ActionListener
{
Toebuttons toe[] = new Toebuttons[9];
JFrame over = new JFrame("Game Over");
JPanel panel = new JPanel();
JLabel winner = new JLabel("");
static boolean win = false;
public static void start()
{
ticTacBoard b = new ticTacBoard();
b.play();
}
public void play()
{
//ticTacBoard one = new ticTacBoard();
while(!win && Toebuttons.count < 9)
{
this.check();
}
endFrame();
}
public ticTacBoard()
{
super("Tic tac board");
toFront();
setSize(500,500);
setLayout(new GridLayout(3,3));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
for(int i = 0; i<toe.length; i++)
{
toe[i] = new Toebuttons();
add(toe[i]);
}
setVisible(true);
}
public void check()
{
checkRow();
checkDiagonal();
checkColumn();
}
public void checkRow()
{
if((toe[0].getText().equals("X")||toe[0].getText().equals("O"))&&(toe[0].getText().equals(toe[1].getText()) && toe[1].getText().equals(toe[2].getText())))
{
winner.setText(toe[2].getText()+" WINS!!!\nROW");
win = true;
}
if((toe[3].getText().equals("X")||toe[3].getText().equals("O"))&&(toe[3].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[5].getText())))
{
winner.setText(toe[3].getText()+" WINS!!!\nROW");
win = true;
}
if((toe[6].getText().equals("X")||toe[6].getText().equals("O"))&&(toe[6].getText().equals(toe[7].getText()) && toe[7].getText().equals(toe[8].getText())))
{
winner.setText(toe[6].getText()+" WINS!!!\nROW");
win = true;
}
}
public void checkDiagonal()
{
if((toe[0].getText().equals("X")||toe[0].getText().equals("O"))&&(toe[0].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[8].getText())))
{
winner.setText(toe[0].getText()+" WINS!!!\nDIAGONAL");
win = true;
}
if((toe[2].getText().equals("X")||toe[2].getText().equals("O"))&&(toe[2].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[6].getText())))
{
winner.setText(toe[0].getText()+" WINS!!!\nDIAGONAL");
win = true;
}
}
public void checkColumn()
{
if((toe[0].getText().equals("X")||toe[0].getText().equals("O"))&&(toe[0].getText().equals(toe[3].getText()) && toe[3].getText().equals(toe[6].getText())))
{
winner.setText(toe[0].getText()+" WINS!!!\nCOLUMN");
win = true;
}
if((toe[1].getText().equals("X")||toe[1].getText().equals("O"))&&(toe[1].getText().equals(toe[4].getText()) && toe[4].getText().equals(toe[7].getText())))
{
winner.setText(toe[1].getText()+" WINS!!!\nCOLUMN");
win = true;
}
if((toe[2].getText().equals("X")||toe[2].getText().equals("O"))&&(toe[2].getText().equals(toe[5].getText()) && toe[5].getText().equals(toe[8].getText())))
{
winner.setText(toe[2].getText()+" WINS!!!\nCOLUMN");
win = true;
}
}
public void endFrame()
{
System.out.println("2222");
over.setLocationRelativeTo(null);
panel.setLayout(new FlowLayout());
over.setLayout(new FlowLayout());
panel.add(winner);
panel.repaint();
over.add(panel);
over.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
over.setSize(500,100);
JButton r = new JButton("Reset");
JPanel p = new JPanel();
p.add(r);
over.add(p);
r.addActionListener(this);
over.repaint();
over.setVisible(true);
}
public void reset()
{
Toebuttons.x = true;
for(int i = 0; i<toe.length;i++)
{
toe[i].setText("blank");
}
win = false;
Toebuttons.count = 0;
this.play();
}
public void actionPerformed(ActionEvent e)
{
over.hide();
reset();
}
}
按钮类...
public class Toebuttons extends JButton implements ActionListener
{
static boolean x = true;// if true x's turn if false o's turn
public static int count = 0;
public Toebuttons()
{
super("blank");
this.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
if(this.x == true && getText().equals("blank") && !ticTacBoard.win)
{
count++;
System.out.println(count);
setText("X");
this.x = false;
}
else if(this.x == false && getText().equals("blank")&& !ticTacBoard.win)
{
count++;
System.out.println(count);
setText("O");
this.x = true;
}
}
}
答案 0 :(得分:1)
使用“ this.play()”时,GUI不会重置,游戏也不会播放。没有“ this.play()”,GUI会重置,但游戏无法正常工作。
问题是,您正在阻止事件调度线程...
public void play()
{
//ticTacBoard one = new ticTacBoard();
while(!win && Toebuttons.count < 9)
{
this.check();
}
endFrame();
}
这正在创建一个无限循环,该循环将阻止事件调度线程处理事件队列。
但是为什么它第一次起作用?
因为您实际上违反了GUI开发的基本规则之一。 main
被调用,通常称为“主线程”。这意味着,第一次调用play
时,您正在运行与事件调度线程不同的线程。但是,第二次调用它时,在EDT上下文中调用了reset
,这将导致play
对其进行阻止。
GUI开发的一些基本规则:
这是一个很大的主题,有些复杂,但是,您可以先通读Concurrency in Swing
那么,解决方案是什么?
UI是事件驱动的,您应该使用此机制来监视按钮状态何时更改,然后执行更新检查。
首先,摆脱play
第二,在板上的所有按钮上附加一个ActionListener
。作为“操作”的一部分,您应该检查剧本的状态,并决定应该做什么。
而且,不,我不是说将支票添加到Toebuttons#actionPerformed
中,我的意思是ticTacBoard
应该在ActionListener
上注册自己的Toebuttons
并在触发时检查游戏状态-请注意,ActionListener
的顺序称为我的效果,即您的决策过程,这就是为什么最好将UI状态与游戏状态分开的原因-但这就是另一个主题
这是一个概念性示例,它引入了将UI与游戏状态分离的概念,并使UI仅负责显示游戏状态。
请参阅:
浏览它,放入一些System.out.println
语句,然后对代码运行调试器。返回链接的教程,并扩展您对提出的概念的理解
虽然有些人可能认为它是“高级的”,但从概念上讲,它引入了您需要理解的核心概念,以便与一般的Swing和GUI一起使用
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TicTac {
public static void main(String[] args) {
new TicTac();
}
public TicTac() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TicTacToePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public enum Player {
X, O, NONE;
}
public interface TicTacToeModelListener {
public void ticTacToeGameWon(TicTacToeModel model);
}
public class TicTacToeModel {
private Player[] board;
private Player turn;
private Player winner;
private List<TicTacToeModelListener> listeners;
public TicTacToeModel() {
board = new Player[3 * 3];
listeners = new ArrayList<>(25);
reset();
}
public boolean isX() {
return turn == Player.X;
}
public void nextTurn() {
if (isX()) {
turn = Player.O;
} else {
turn = Player.X;
}
}
public Player getTurn() {
return turn;
}
public Player getWinner() {
return winner;
}
public void reset() {
for (int index = 0; index < board.length; index++) {
board[index] = Player.NONE;
}
turn = Player.X;
winner = Player.NONE;
}
public void set(int col, int row) {
int index = (row * 3) + col;
if (board[index] == Player.NONE) {
board[index] = turn;
} else {
System.out.println("!! Spot already occupied");
}
check();
}
public void check() {
checkRow();
checkDiagonal();
checkColumn();
if (winner != Player.NONE) {
fireGameWon();
}
}
public void addModelListener(TicTacToeModelListener listener) {
listeners.add(listener);
}
public void removeModelListener(TicTacToeModelListener listener) {
listeners.remove(listener);
}
protected void fireGameWon() {
for (TicTacToeModelListener listener : listeners) {
listener.ticTacToeGameWon(this);
}
}
public void checkRow() {
if ((board[0] == Player.X || board[0] == Player.O) && (board[0] == board[1] && board[1] == board[2])) {
winner = turn;
}
if ((board[3] == Player.X || board[3] == Player.O) && (board[3] == board[4] && board[4] == board[5])) {
winner = turn;
}
if ((board[6] == Player.X || board[6] == Player.O) && (board[6] == board[7] && board[7] == board[8])) {
winner = turn;
}
}
public void checkDiagonal() {
if ((board[0] == Player.X || board[0] == Player.O) && (board[0] == (board[4]) && board[4] == (board[8]))) {
winner = turn;
}
if ((board[2] == Player.X || board[2] == Player.O) && (board[2] == (board[4]) && board[4] == (board[6]))) {
winner = turn;
}
}
public void checkColumn() {
if ((board[0] == Player.X || board[0] == Player.O) && (board[0] == (board[3]) && board[3] == (board[6]))) {
winner = turn;
}
if ((board[1] == Player.X || board[1] == Player.O) && (board[1] == (board[4]) && board[4] == (board[7]))) {
winner = turn;
}
if ((board[2] == Player.X || board[2] == Player.O) && (board[2] == (board[5]) && board[5] == (board[8]))) {
winner = turn;
}
}
}
public class TicTacToePane extends JPanel {
private TicTacToeModel model;
private GamePane gamePane;
private WinPane winPane;
public TicTacToePane() {
CardLayout cardLayout = new CardLayout();
model = new TicTacToeModel();
model.addModelListener(new TicTacToeModelListener() {
@Override
public void ticTacToeGameWon(TicTacToeModel model) {
winPane.setWinner(model.getWinner());
cardLayout.show(TicTacToePane.this, "GameOverMan");
}
});
winPane = new WinPane();
gamePane = new GamePane(model);
winPane.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals(GameActions.PLAY_AGAIN.getCommand())) {
gamePane.reset();
cardLayout.show(TicTacToePane.this, "ReadyPlayer");
} else if (e.getActionCommand().equals(GameActions.STOP_PLAYING.getCommand())) {
SwingUtilities.windowForComponent(TicTacToePane.this).dispose();
}
}
});
setLayout(cardLayout);
add(winPane, "GameOverMan");
add(gamePane, "ReadyPlayer");
cardLayout.show(this, "ReadyPlayer");
System.out.println("...");
}
}
public class GamePane extends JPanel {
private JButton board[];
private TicTacToeModel model;
public GamePane(TicTacToeModel model) {
this.model = model;
setLayout(new GridLayout(3, 3));
board = new JButton[9];
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
int index = (row * 3) + col;
System.out.println(index);
board[index] = new JButton("-"); // Icon might be better
board[index].addActionListener(new ButtonActionListener(col, row));
add(board[index]);
}
}
reset();
}
public void reset() {
model.reset();
for (int index = 0; index < board.length; index++) {
board[index].setText("-");
}
}
protected class ButtonActionListener implements ActionListener {
private int col;
private int row;
public ButtonActionListener(int col, int row) {
this.col = col;
this.row = row;
}
@Override
public void actionPerformed(ActionEvent e) {
// Normally I'd use instanceof to check the source, but
// I've deliberly limited the possible scope.
JButton btn = (JButton) e.getSource();
btn.setText(model.isX() ? "X" : "0");
model.set(col, row);
model.nextTurn();
}
}
}
public enum GameActions {
PLAY_AGAIN("playAgain"), STOP_PLAYING("stopPlaying");
private String command;
private GameActions(String command) {
this.command = command;
}
public String getCommand() {
return command;
}
}
public class WinPane extends JPanel {
private JLabel winner;
private JButton playAgain;
private JButton end;
public WinPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(8, 8, 8, 8);
winner = new JLabel("");
playAgain = new JButton("Play Again");
playAgain.setActionCommand(GameActions.PLAY_AGAIN.getCommand());
end = new JButton("Stop Playing");
end.setActionCommand(GameActions.STOP_PLAYING.getCommand());
add(new JLabel("Game Over!"), gbc);
add(new JLabel("Player"), gbc);
add(winner, gbc);
add(new JLabel("Wins!"), gbc);
JPanel buttons = new JPanel(new GridLayout(1, 0));
buttons.add(playAgain);
buttons.add(end);
add(buttons, gbc);
}
public void setWinner(Player player) {
if (player == Player.X) {
winner.setText("X");
} else if (player == Player.O) {
winner.setText("0");
} else {
winner.setText("No boby knows");
}
}
public void addActionListener(ActionListener listener) {
playAgain.addActionListener(listener);
end.addActionListener(listener);
}
public void removeActionListener(ActionListener listener) {
playAgain.removeActionListener(listener);
end.removeActionListener(listener);
}
}
}