我有一个应用程序,其中有一个鼠标单击事件可以模拟用户在标准输入中输入特定字符串的情况,这对我来说非常方便。所以我想知道,有没有一种方法可以写成标准代码?我意识到这有点麻烦,但是对于我需要做的事情来说,它会很好地工作。
编辑(响应于Hovercraft的EDIT2):
谢谢。我了解该代码如何防止人类玩家在不该移动的情况下移动游戏。我不了解的是您如何设想主游戏循环。您介意编写代码向我展示您的想法吗?您是否只是在描绘一个忙碌的等待循环,该循环不断产生新的计算机动作并调用您的Move()
方法(在等待人类玩家移动时,大部分时间被拒绝)?像这样吗
public void gameLoop()
{
while (gameNotOver)
{
Move compMove = generateComputersNextMove();
move(blackPlayer, compMove); // where the blackPlayer is the computerPlayer
}
}
最佳答案
您声明:
基本上,我希望我的代码在某个时刻被阻塞,并等待用户单击JFrame中的特定JLabel。用户单击JLabel后,在获取被单击的JLabel的ID之后,我希望代码恢复。我不确定该怎么做。我之前所拥有的方法是,在代码中,用户只需输入一个id(Scanner的next()方法为您阻止)。
您不想阻塞程序(不是在事件驱动程序中),而只希望更改GUI的状态,并基于该状态对用户输入的响应即可。您尝试的解决方案是一种线性思维方式,不适用于Swing或其他事件驱动的GUI。
举个简单的例子,考虑给程序一个布尔变量,
private boolean labelClicked = false;
单击JLabel之后,在JLabel的MouseListener中将其更改为true。然后,如果布尔值为true,则仅响应其他用户输入。
另一个可行的解决方案:如果要在按下JLabel之后激活JButton,请禁用JButton,然后从JLabel的MouseListener中的JButton调用setEnabled(true)。
关键是考虑事件驱动编程。
在本论坛中问类似这样的问题时,另一个关键不是问我们一个特定于代码的问题,而是一个针对行为的问题。此处的真正问题不是如何编写标准,而是如何使程序暂停并等待用户输入-这是一个很大的区别。
最后,如果您需要更具体,更好的建议,请填写我们的问题详细信息,并一定要问是否有任何混淆的问题。祝你好运!
编辑1
您可能会有几个类,包括管理此应用程序的GUI和非GUI类,并且非GUI类可以包括:
玩家等级:可以是人类的也可以是计算机的
棋盘类:国际象棋棋盘的逻辑(非GUI)表示
件类:所有具体件都源自的抽象类
ChessAI课程:这是您的AI课程,该课程为计算机找出下一步的最佳举措。
游戏类:也许是本次讨论中最重要的类,因为这将控制游戏流程并确定该轮到谁。
Game类将具有包括名为
turn
的Player字段的字段,该字段将保存对轮到谁的引用。假设您的Game类包含两个Player变量,humanPlayer和computerPlayer。 turn变量将容纳这些对象中的一个或另一个,而Player的响应方式将取决于轮流持有的对象。Game类将具有各种循环,即游戏循环,该循环在告诉humanPlayer对象和computerPlayer对象其移动方向时交替进行。
所以说轮到计算机了,要计算下一个最佳动作需要一段时间。如果与此同时,人类玩家尝试在GUI上拖动棋子,则GUI会通知Game类人类尝试移动的尝试,Game类将检查是否是人类的回合(通过检查
if (turn == humanPlayer)
),如果不是,轮到人类时,Game会将此通知GUI,GUI会将棋子放回原处,并可能弹出警告消息。在计算机请求Game移动其棋子之后,Game将告诉GUI移动计算机的棋子,然后Game将set turn = humanPlayer设置,现在允许人类玩家移动。在humanPlayer尝试移动之后,GUI会告知Game该人的尝试移动。游戏将检查其是否有效,如果有效,将告知computerPlayer现在应该进行此操作。
请注意,当我说“ tell”时,是指它将在该对象上调用一个公共方法。
编辑2
我的意思是这样的:
public class Game {
private Player whitePlayer;
private Player blackPlayer;
private Player turn;
private Board board = new Board(); // non-GUI logical board
private Gui gui; // the Swing GUI that displays all
public Game(String humanPlayerName, boolean humanWhite) {
if (humanWhite) {
whitePlayer = new HumanPlayer(humanPlayerName, this);
blackPlayer = new ComputerPlayer("Computer", this);
} else {
whitePlayer = new ComputerPlayer("Computer", this);
blackPlayer = new HumanPlayer(humanPlayerName, this);
}
}
public void start() {
whitePlayer.setMyTurn(true); // tell white player to move
}
public void move(Player playerMakingMove, Move move) {
// only respond if the right player is making the move
if (turn == playerMakingMove) {
// check if its a valid move
// if so, tell GUI to make move
// check if game over
turn.setMyTurn(false); // current player's turn is over
turn = (turn == blackPlayer) ? whitePlayer : blackPlayer; // swap players
turn.setMyTurn(true); // tell other player, it's his turn
turn.makeMove(); // *** added
} else {
// send message that it's not their turn to move
}
}
}
因此,如果人类玩家尝试移动,GUI将会为人类玩家移动(...),但是Game对象将不会响应,除非实际上是人类的回合。
编辑3
makeMove()
方法已添加到播放器请注意,Game的
move(...)
方法可能是所有需要的游戏循环,尤其是如果ComputerPlayer的makeMove(...)
方法告诉AI引擎创建下一个最佳移动,然后再次调用Game的move(...)方法时:abstract class Player {
private String name;
private boolean myTurn = false;
protected Game game;
public Player(String name, Game game) {
this.name = name;
this.game = game;
}
public abstract void makeMove();
public boolean isMyTurn() {
return myTurn;
}
public void setMyTurn(boolean myTurn) {
this.myTurn = myTurn;
}
public String getName() {
return name;
}
}
class HumanPlayer extends Player {
public HumanPlayer(String name, Game game) {
super(name, game);
}
@Override
public void makeMove() {
// TODO: ask GUI to inform player that it's his turn to move and accept the move
}
}
class ComputerPlayer extends Player {
private ChessAi chessAi = new ChessAi();
public ComputerPlayer(String name, Game game) {
super(name, game);
}
@Override
public void makeMove() {
game.move(this, chessAi.calcBestMove());
}
}
双方球员都知道了移动后会呼叫
game.move(...)
,这会使游戏提示下一个玩家移动...。直到游戏结束。请注意,这不是一个正在运行的程序,并非意味着该程序,而是更多用于说明可能的游戏逻辑的模型。我还没有做过这样的事情,也许有更好,更干净的方法可以做到这一点,但我只是想了解在事件驱动的GUI程序中实现基于回合的逻辑的方法。
编辑4
编译并运行以下简单的事件驱动的GUI:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EventDrivenGui extends JPanel {
private static final Color GO_COLOR = Color.green;
private static final Color STOP_COLOR = Color.red;
private static final int SIDE = 300;
private static final int TIMER_DELAY = 4 * 1000; // change light every 4 seconds
private boolean go = false;
private JButton button = new JButton("Button");
public EventDrivenGui() {
add(button);
button.addActionListener(new ButtonListener());
new Timer(TIMER_DELAY, new TimerListener()).start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color color = go ? GO_COLOR : STOP_COLOR;
g2.setColor(color);
g2.fillOval(0, SIDE / 3, SIDE, SIDE);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(SIDE, (4 * SIDE) / 3);
}
private class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
if (go) {
JOptionPane.showMessageDialog(EventDrivenGui.this, "Button is Active");
}
}
}
private class TimerListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
// toggle go. if true, now false, and visa versa
go = !go;
repaint(); // redraw oval
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
EventDrivenGui mainPanel = new EventDrivenGui();
JFrame frame = new JFrame("EventDrivenGui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
您会看到JPanel中有一个JButton。您作为用户可以随时按按钮,但是只有在指示灯为绿色时(go布尔变量为true时),它才会响应。这是一个示例,其中按钮的行为(是否响应按下)取决于类的状态,即go是否成立。设置好GUI后-调用了构造函数,将其放置在JFrame中并显示出来,没有任何代码阻塞或类似的事情。有一个Swing Timer,其唯一的工作就是切换go的值并重新绘制JFrame,仅此而已。
关于java - Java-以标准语言编写?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10661856/