2016-05-23 3 views
1

Это своего рода продолжение из предыдущего вопроса, который я задал, но мне нужна помощь в части этой маленькой приключенческой игры, которую я делаю в качестве окончательного проекта для своего AP Java Class.
В моем приключении у меня есть функция, которая позволяет игроку сражаться с различными монстрами, если они находятся в определенном месте. Моя проблема в том, что как только я доберусь до этого места в своей программе, программа перестает отвечать на запросы.
После выполнения отладки я выяснил, что это был while loop У меня было все, что делалось в методе doBattle(), а player.isAlive и enemy.isAlive. Единственная проблема заключается в том, что, как только я удаляю во время цикла, программа просто прыгает прямо после того, как монстр мертв или игрок мертв, тогда как он должен дать вам выбор: нападать ли монстр или нет, пока либо сущности мертвы.Как я могу исправить эту бесконечную петлю?

Вот код метода 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 является TextField

+1

Я думаю, что это поможет получить журнал игрового процесса. Что и ожидалось, и что вы получили. – UDKOX

+1

У меня есть подозрение: вы вводите цикл и ** внутри ** вы устанавливаете обработчик событий ввода для выполнения своего «игрового процесса». Это приводит к очень маленькому быстро выполняющемуся циклу, который выглядит как заторможенный интерфейс. – Fildor

+0

@ Fildor @UDKOX Согласовано и '.toString();' игрока и монстра, чтобы установить переменные по мере их развития. Этот код трудно читать и довольно дезорганизован. Почувствуйте, что это должен быть небольшой цикл while и несколько методов обработки. Возможно, если он реорганизовал его и очистил, он мог бы найти ошибку естественным образом. ... Fildor хороший улов! Где я не вижу блокировки цикла, ожидания или фиксации? Код события ДОЛЖЕН быть перемещен за пределы цикла while, регистрация событий не должна повторяться снова и снова. – Underbalanced

ответ

2

Вы, кажется, непонимание, как выполняется ваш код. Вы помещаете свой код обработки ввода (inputText.setOnAction) внутри своего цикла, и вы, кажется, думаете, что это означает, что он будет выполнен в то время. Но это неверно; обработчик является асинхронным и будет выполняться при возникновении события. То, что на самом деле происходит в вашем цикле, состоит в том, что обработчик задан, установлен и установлен, установлен и задан до вечности. (не уверен в безопасности потоков Swing, но я бы предположил, что обработчик даже никогда не был установлен, потому что вы не даете случайной нить возможность синхронизировать)

Что вы действительно хотите, так это для вашего кода на самом деле продолжайте, когда произойдет входное событие. Это означает, что вся логика продолжения должна быть в обработчиком, а не вокруг него.

Так я вижу три способа для вас, чтобы продолжить:

  • перейти к simpeler способ работы и использования консоли вместо (наименьшее количество изменений кода). Это будет работать, потому что чтение в консоли блокируется (вы не будете использовать обработчик событий, кроме простого чтения)
  • переместите этот код в отдельный поток, заблокируйте текущий поток (wait) после того, как обработчик установлен, и notify it когда происходит событие
  • полностью разделяет логику так, что любое продолжение управляется событиями. Это означало бы переезд в режим работы государственной машины.

Недостатком второго подхода является то, что он включает в себя потоки и синхронизацию. Это боль, чтобы поправиться. Но ваша игровая логика будет «читать» как целое.Если вы красиво инкапсулируете обработчик потока в класс 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 
} 
+0

Я использую приложение JavaFX, которое я создал в Scene Builder для этого, я не знаю, если это изменит все, что вы предложили, хотя –

+0

точно такая же проблема :) –

+0

@AndrewBrook Я сделал редактирование, дающее намек на то, как он мог выглядеть. Пожалуйста, проверьте, не вдохновляет ли он вас. –

Смежные вопросы