java - 如何解决这个无限 while 循环?

标签 java javafx while-loop scenebuilder

这是我之前提出的问题的延续,但我需要这个小型冒险游戏的部分帮助,我一直在为我的 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 也有些陌生,所以如果您需要更多信息或其他任何内容来帮助我获得更好的建议,请告诉我,我们将不胜感激。
另外,请不要在没有至少告诉我原因的情况下投反对票,我想在这类事情上做得更好。
我还应该提到,我为此使用 JavaFXtextTextAreainputText文本字段

最佳答案

您似乎误解了代码的执行方式。您将输入处理代码(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/

相关文章:

java - 使用 jmagick 从图像中删除元数据

java - Ecore 建模生成一个 HashMap dto 持有一个 HashMap

java - 将 DateTimePicker 添加到按钮

JavaFX(部分)在网格 Pane 外隐藏图像

css - JavaFX:使用 CSS 选择器的样式化应用程序

java - 如果添加到 Jpanel,则无法使用 PaintComponent 进行绘制,但在 JFrame 中工作正常

java - 在 iOS 上生成匹配的 RSAPublicKey 以匹配来自 Android 的共享 RSAPublicKey(或组件)

c - 我在 C 中的开关(在 while 循环内)在正常运行之前直接进入默认状态

java - 继续做事直到输入空行

javascript - Javascript 中的 If/Else 嵌套在 While 循环中不循环