如何修复此无限循环?

时间:2016-05-23 14:08:52

标签: java javafx while-loop scenebuilder

这是我之前提出的一个问题的延续,但我需要帮助解决这个小型冒险游戏的一部分,我将其作为AP Java Class的最终项目。 在我的冒险中,我有一个功能,允许玩家在各个怪物的战斗中,如果他们在一个给定的位置。我的问题是,一旦我到达我的程序中的这个位置,程序就会停止响应 在做了一些调试之后,我发现它是一个 while循环我在doBattle()方法中执行了所有操作player.isAliveenemy.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 ,而文本TextArea inputText 是{{1} }

1 个答案:

答案 0 :(得分:2)

您似乎误解了代码的执行方式。您将输入处理代码(inputText.setOnAction)放在循环中,您似乎认为这意味着它将在那时执行。但这不正确;处理程序是异步的,将在事件发生时执行。循环中实际发生的事情是处理程序被设置,设置,设置,设置和设置,直到永恒。 (不确定Swing的线程安全性,但我猜测处理程序甚至没有设置,因为你没有给事件线程同步的机会)

您真正想要的是您的代码在输入事件发生时实际继续。这意味着所有的延续逻辑应该 in 处理程序,而不是它周围。

所以我认为有三种方法可以继续:

  • 采用简化的工作方式,改为使用控制台(代码更改最少)。这可以工作,因为控制台读取是阻塞的(你不会使用事件处理程序而是简单的读取)
  • 将此代码移动到单独的线程中,在设置处理程序后阻止当前线程(wait),并在事件发生时阻止notify
  • 完全拆分逻辑,以便任何延续都由事件驱动。这意味着更多地转向状态机的工作方式。

第二种方法的缺点是它涉及线程和同步。要做对,这是一种痛苦。但是你的游戏逻辑仍然会“阅读”。像一个整体。如果你很好地将线程处理程序封装到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
}