我正在制作一个蛇游戏( for those who don't know ),其中蛇由人工智能使用不同的算法来控制以捕捉食物。与常规游戏的不同之处在于,除非 AI 发出命令,否则蛇不会移动。
我的问题是,一旦我运行人工智能,人工智能就会创建一堆要执行的命令来捕获食物,但我的 GUI 只是卡住;可能是因为它无法跟上移动堆栈导致的重绘量。通过控制台日志,我可以看到AI和游戏逻辑仍在运行。
我尝试在每次移动后执行Thread.sleep()
,但我想这只会使包括 GUI 在内的整个程序 hibernate 。我的 paintComponent
也有一个 Timer
,但这似乎没有改变任何东西。
如何让程序 hibernate ,以便 GUI 能够跟上正在发生的事情?
编辑:
好的,伙计们,我尝试了您的解决方案,但它仍然无法正常工作。我真的不想把代码扔在这里,但我真的迷路了。我有一个计时器,应该以 140 毫秒的间隔重新绘制(这是 DELAY 的值),命令在不同的线程上发送,该线程在每次按键 1000 毫秒后进入休眠状态,并且在每次调用 move 后调用 repaint() ()...以下是相关代码(未经我修改的原始代码 here ):
private void initGame() {
dots = 5;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z * 10;
y[z] = 50;
}
locateApple();
for (int k = blockNb - 1; k > 0; k--) {
locateBlock(k, apple_x, apple_y);
}
if (blocks) {
locateBlock(0, apple_x, apple_y);
}
timer = new Timer(DELAY, this);
timer.start();
startAi();
}
// AI CONTROLLER
public void startAi() {
Ai theAi = new Ai();
String move = "";
switch (ai) {
case "BFS":
move = theAi.bfs(this);
break;
}
//AI returns a string where each char is a move command
autoMove(move);
}
public void autoMove(String move) {
try {
Robot robot = new Robot();
System.out.println(move);
if (move != "#No") {
Thread thread = new Thread(new Runnable() {
public void run() {
for (int j = 0; j < move.length(); j++) {
if (move.charAt(j) == 'l') {
robot.keyPress(KeyEvent.VK_LEFT);
robot.keyRelease(KeyEvent.VK_LEFT);
}
if (move.charAt(j) == 'r') {
robot.keyPress(KeyEvent.VK_RIGHT);
robot.keyRelease(KeyEvent.VK_RIGHT);
}
if (move.charAt(j) == 'u') {
robot.keyPress(KeyEvent.VK_UP);
robot.keyRelease(KeyEvent.VK_UP);
}
if (move.charAt(j) == 'd') {
robot.keyPress(KeyEvent.VK_DOWN);
robot.keyRelease(KeyEvent.VK_DOWN);
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
thread.run();
}
} catch (AWTException e) {
e.printStackTrace();
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
doDrawing(g);
}
private void doDrawing(Graphics g) {
if (inGame) {
g.drawImage(apple, apple_x, apple_y, this);
for (int j = 0; j < blockNb; j++) {
g.drawImage(block, block_x[j], block_y[j], this);
}
for (int z = 0; z < dots; z++) {
if (z == 0) {
g.drawImage(head, x[z], y[z], this);
} else {
g.drawImage(ball, x[z], y[z], this);
}
}
Toolkit.getDefaultToolkit().sync();
} else {
// gameOver(g);
}
}
private void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (leftDirection) {
x[0] -= DOT_SIZE;
}
if (rightDirection) {
x[0] += DOT_SIZE;
}
if (upDirection) {
y[0] -= DOT_SIZE;
}
if (downDirection) {
y[0] += DOT_SIZE;
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (inGame) {
repaint();
}
}
private class TAdapter extends KeyAdapter {
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!rightDirection)) {
leftDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_RIGHT) && (!leftDirection)) {
rightDirection = true;
upDirection = false;
downDirection = false;
}
if ((key == KeyEvent.VK_UP) && (!downDirection)) {
upDirection = true;
rightDirection = false;
leftDirection = false;
}
if ((key == KeyEvent.VK_DOWN) && (!upDirection)) {
downDirection = true;
rightDirection = false;
leftDirection = false;
}
move();
checkApple();
checkCollision();
repaint();
}
}
编辑2:另外,我只是想指出,我尝试在不依赖机器人的情况下移动,但没有成功。
最佳答案
第 1 部分:
Thread.sleep 之间的区别:
当你在主线程(java用来运行程序的线程)中使用它时
然后你的整个程序就会因为这个原因卡住。
例如当您使用线程时(遵循代码)
new Thread(new Runnable(){ public void run(){ //do something... while(flag==false) Thread.sleep(a given time) //it need and try catch else //do your move });
然后只有这个线程卡住(在给定时间内)或(无论您将其转换为卡住什么)。
在您的情况下,您可以使用标志,以便每次用户点击命令时
标志变为 true,然后再次变为 false 以保持停止部分
你想要的游戏,但你的程序需要运行的主线程仍然可以运行 (如果它是 window 或任何东西......)
第 2 部分:(线程的基本形式)(我使用的标志必须被所有方法看到)(公共(public)或私有(private))
new Thread(new Runnable() { public void run() { flag=true; while(flag==true){ if(move.equals("yes")){ //your code move="no"; }else Thread.sleep(20); //Sleep For a While(and then check again) } //That means that your Thread will run all over your game //until game over (when game over just do the flag=false;) //and The Thread will stop-exit }});
*关于Repaint方法(不要太快调用repaint方法) 仅当玩家移动时才调用它(这是帧发生的时间) 需要重新绘制[好吧,如果你的游戏中有 .gif 图像,只是看不到这个]
第 3 部分:(当我制作类似游戏时我所做的) 几个月前,我尝试了一款类似的游戏。基本想法是玩家必须通过迷宫,所以......
对于每个级别,我都有一个这样的类(class)......
public abstarct class Level2(){ //The game was into a panel like your. //Here i added .setFocusable and .addKeyListener to panel //Here it was an public void actionListener(){ //The actionListener checked if the player found the door(for next level) //Here it was the repaint so every time something happened repaint() repaint(); }//End of Action Listener //Use the paint or paintComponent what you need.. public void paint[or paintComponent](Graphics g){ //the 'squares' and the icons the had to be *repainted* again } //Here i had an extra class into this for the KeyListeners //And I added the KeyListener like your game(up,down,left,right) //I i said before i added this KeyListener to the panel private class TAdapter extends KeyAdapter { //KeyPressed,Released...etc } }
我认为这就是你的游戏的基本思想。 线程是一个额外的选项,我无法提供更多帮助,您必须找到方法...
关于java - 如何让程序 hibernate 以便 GUI 能够跟上正在发生的事情?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28162551/