这是我之前提出的问题的延续,但我需要这个小型冒险游戏的部分帮助,我一直在为我的 AP Java 类(class)制作该游戏的最终项目。
在我的冒险中,我有一个功能,允许玩家在给定位置与各种怪物战斗。我的问题是,一旦我到达程序中的这个位置,程序就会停止响应。
经过一些调试后,我发现这是一个 while 循环,它在 doBattle()
方法中执行所有操作,而 player.isAlive
和enemy.isAlive。唯一的问题是,一旦我删除 while 循环,程序就会直接跳到怪物死了或玩家死后,而它应该让你选择是否攻击怪物怪物或不重复,直到任一实体死亡。
这是 doBattle() 方法的代码:
public void doBattle(Monster enemy)
{
//boolean fled = false;
//Greets player into battle by telling what monster they are fighting
text.appendText("\n" + "A wild " + enemy.getName() + " has appeared!" + "\n" );
mobImagePane.setImage(enemy.getImage());
//System.out.print("THIS RAN"); //debug
while ( p.getHealth() > 0 && enemy.getHealth() > 0 ) //while enemy and player are alive
{
//Prompts user to attack or run
text.appendText("Attack " + enemy.getName() + "? (Y/N) " + "\n");
inputText.setOnAction(event ->
{
String fightChoice = inputText.getText();
fightChoice = fightChoice.toUpperCase();
//String fightChoice = this.choice;
if (fightChoice.equals("Y"))//if they want to fight
{
//Player turn
enemy.setHealth(enemy.getHealth() - p.getDamage()); //Sets the monsters health as their current health minus the players damage
text.appendText("You attack " + enemy.getName() + " for " + p.getDamage() + " damage!" + "\n" + "Enemy health is " + enemy.getHealth() + "\n");
//Monster turn
p.setHealth(p.getHealth() - enemy.getDamage()); //Sets the players health as their current health minus the monsters damage
text.appendText("The " + enemy.getName() + " hit you for " + enemy.getDamage() + " damage!" + "\n" + "Your health is " + p.getHealth() + "\n"); //prints how much damage the monster does to the player
if (p.health < 20.0) {
text.appendText("Your health is low, you should return home and restore health!" + "\n");
}
//checks if the player or monster is dead
this.checkLife();
enemy.checkLife();
} else {
if (fightChoice.equals("N")) // if they don't want to fight
{
mobImagePane.setImage(null);
text.appendText("You fled from the fight!" + "\n");
this.setNewLoc("TOWN"); // brings you back to town
fled = true;
//JOptionPane.showMessageDialog(null, "You are now in " + this.currentLoc.getName() + "\n" + this.currentLoc.getDescription());
//String move2 = JOptionPane.showInputDialog(null,"Which way do you want to go? (N, E, S, W)");
//makeMove(move2);
//break;
} else // they don't make any sense
{
text.appendText("Unrecognized command" + "\n");
}
}
//}
//when someone dies
if (!fled) {
if (p.alive) // if you are still standing
{
//print results (money earned, health remaining)
mobImagePane.setImage(null);
p.wallet += enemy.getLoot();
playerInfo.setText(p.getPlayerName() + "\n" + "Health: " + p.getHealth() + "\n" + "Wallet: " + p.getWallet() + "\n");
text.setText("You shrekt the " + enemy.getName() + "\n" + "You got $" + enemy.getLoot() + " for winning!" + "\n" + "You now have $" + p.wallet + "\nYour health is " + p.getHealth() + "\n");
} else //if you died
{
mobImagePane.setImage(null);
text.setText("You have been shrekt by the " + enemy.getName() + "\n" + "GAME OVER" + "\n");
text.appendText("\nPlay again? (Y/N)" + "\n");
inputText.setOnAction(event2 -> {
String answer = inputText.getText();
answer.toUpperCase();
//String answer = this.choice;
if (answer.equals("Y")) //if they want to play again
{
text.appendText("Alright! Let's go!" + "\n");
this.reset();
} else //if they want to quit
{
text.appendText("Wow. What a skrub, okay bye." + "\n");
System.out.close();
}
});
}
}
});
}
} //end doBattle
请记住,我是这个网站的新手,对 java 也有些陌生,所以如果您需要更多信息或其他任何内容来帮助我获得更好的建议,请告诉我,我们将不胜感激。
另外,请不要在没有至少告诉我原因的情况下投反对票,我想在这类事情上做得更好。
我还应该提到,我为此使用 JavaFX ,text 是 TextArea
,inputText 是 文本字段
最佳答案
您似乎误解了代码的执行方式。您将输入处理代码(inputText.setOnAction
)放入循环中,并且您似乎认为这意味着它将在那时执行。但这是不正确的;该处理程序是异步的,将在事件发生时执行。在循环中实际发生的是处理程序被设置、设置、设置、设置、设置,直到永恒。 (不确定 Swing 的线程安全性,但我猜想处理程序甚至从未设置过,因为您没有给事件线程同步的机会)
您真正想要的是当输入事件发生时您的代码实际上继续运行。这意味着所有延续逻辑都应该位于处理程序中,而不是围绕它。
所以我认为您可以通过三种方式继续:
- 转向更简单的工作方式并使用控制台(最少的代码更改)。这是可行的,因为控制台读取是阻塞的(您不会使用事件处理程序,而是使用简单的读取)
- 将此代码移动到单独的线程中,在设置处理程序后阻塞当前线程(
wait
),并在事件发生时通知
它 - 完全分割逻辑,以便任何延续都由事件驱动。这意味着更多地采用状态机工作方式。
第二种方法的缺点是它涉及线程和同步。想要正确是很痛苦的。但你的游戏逻辑仍然会像一个整体一样“阅读”。如果您很好地将线程处理程序封装到 UserInput
类中,您可能可以使其易于管理(但我认为您还没有达到那个级别)
第三种方法的缺点是你的逻辑最终会分散到各处。
就您的初学者水平而言,我能给您的最务实的建议是采用方法#1,并改为基于控制台。
对于方法#2
关于第二种方法的一些细节——请注意,这是伪代码。我也不是说这将是一个理想的设计或代码库。但这是对代码的快速修复,还可以。
// this should not run on the event handling thread of javafx
Holder<String> inputReceived = new Holder<String>(); //Holder is an often used hack to set values from a closure. It's not builtin, but you'll find hundreds of examples.
inputText.setHandler(e->{
inputReceived.set(inputText.getText());
});
while (player.isAlive() && monster.isAlive()){
// wait for input
while (!isValidInput(inputReceived.get())){
Thread.sleep(200);
}
... do your code based on the value in inputReceived
}
关于java - 如何解决这个无限 while 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37393307/