Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by devstudents · Sep 26, 2014 at 01:35 AM · if-statementsmethods

question about if statement order of execution

I think my understanding of how if statements function is incorrect. The code attached below may highlight my misconception.

I thought that if a condition was true, then the program will run through the if block until the condition is no longer true. At that point, it will move down the block and see if the next if statement is true. If this is not true, it will go back to the beginning again if the main if statement is still true. At this point, a new bool value will be assigned based on the method Initiative() and the code will move down again.

With the code, I am trying to create a very basic combat initiative system. If the player gets a higher initiative roll, then player attacks. If not, player blocks. The attacking and blocking should last for as long as the attackTimer is > than 0. The problem is that the player just stands there and jitters as the code rapidly alternates between true and false.

I suspect the problem has something to do with where I put the bool "value" but I'm not sure how to fix it. It's as if the program doesn't just move politely down the block once value has been initialized, but jumps up again constantly to see if value has changed and, since value is established randomly, when the program goes to see if value has changed, it has!

 private void AttackEnemy()
     {
         if(Vector3.Distance(playerTransform.position, enemyTarget.transform.position) < attackRange)
         {
             bool value = Initiative(); 
             attackTimer = 21;
             attacking = true; 
         
             if(value == true && attacking == true) 
             {
                 Debug.Log(value + " Should be true"); 
                 animation.Play(attack.name); 
             
                 while (attackTimer > 0 && attacking == true) 
                 {
                     attackTimer -= Time.deltaTime; 
                     
                     if(attackTimer < 0)
                     {
                         attackTimer = 0; 
                     }
                     if(attackTimer == 0)
                     {
                         enemyVitals.AdjustCurrentBeastHealth(-damage); 
                         attacking = false; 
                     }
                 }
             }
             else if(value == false && attacking == true)
             {
                 Debug.Log(value + " Should be false"); 
                 animation.Play(playerBlock.name); 
 
                 while (attackTimer > 0 && attacking == true) 
                 {
                     attackTimer -= Time.deltaTime; 
                     
                     if(attackTimer < 0)
                     {
                         attackTimer = 0; 
                     }
                     if(attackTimer == 0)
                     {
                         enemyVitals.AdjustCurrentBeastHealth(0); 
                         attacking = false; 
                     }
                 }
             }        
         }
     }
 
     public bool Initiative()
     {
         int playerRoll = Random.Range(1,20);
         int enemyRoll =  Random.Range(1,20); 
         if(playerRoll > enemyRoll)
         {
             return true; 
         }
         else
         {
             return false; 
         }
     }
Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Eric5h5 · Sep 26, 2014 at 01:38 AM 0
Share

I would recommend using coroutines ins$$anonymous$$d, which makes ordering sequences of events far simpler.

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Kiwasi · Sep 26, 2014 at 02:05 AM

Code executes from top to bottom. Anything inside an if will only execute if the conditions are true. Then execution goes to the very next statement after the end of the if {}.

while works slightly differently. In a while loop the code inside is executed continually until the condition is true. Its quite common to see infinite while loops, where the condition is not changed by the code inside the braces. Unity will "freeze" without any error messages.

This is all complicated by the system being run by Unity. So everything listed above happens each frame. Your entire while loop executes in a single frame

To solve this you should convert it to a coroutine. Coroutines are Unity's way of running a function across multiple frames. Here is some pseudo code

 void Update (){
     if(...){
         StartCoroutine(AttackEnemy());
     }
 }
 
 IEnumerator AttackEnemy(){
     while (playerHasInitiative) {
         performPlayerAttack;
         yield return null
     }
     while (enemyHasInitiative) {
         performEnemyAttack;
         yield return null
     }
 }

The code is heavy pseudo code. But the general idea is to put a yield inside a while loop to allow the while loop to execute across multiple frames.

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image devstudents · Sep 26, 2014 at 07:12 AM 0
Share

Ok, I've spent sometime researching coroutines and I fear that I've come to exactly the same result! I may not have followed your pseudo code very well but I was basing the structure I used on a Unity tutorial. Can you see why my code is still making my player rapidly oscillate between true and false?`

     private void AttackEnemy()
     {
         if(Vector3.Distance(playerTransform.position, enemyTarget.transform.position) < attackRange)
         {
             bool value = Initiative(); 
 
             if(value == true)
             {
                 StartCoroutine(Fight());
             }
             else if(value == false)
             {
                 StartCoroutine(Defend()); 
             }
         }
     }
 
     public bool Initiative()
     {
         int playerRoll = Random.Range(1,20);
         int enemyRoll =  Random.Range(1,20); 
         if(playerRoll > enemyRoll)
         {
             return true; 
         }
         else
         {
             return false; 
         }
     }
 
     public IEnumerator Fight()
     {
         float startTime = Time.time; 
         while(Time.time < startTime + 2)
         {
             animation.Play(attack.name); 
             yield return new WaitForEndOfFrame(); 
         }
     }
 
     public IEnumerator Defend()
     {
         float startTime = Time.time; 
         while(Time.time < startTime + 2)
         {
             animation.Play(playerBlock.name); 
             yield return new  WaitForEndOfFrame(); 
         }
     }
avatar image Kiwasi · Sep 26, 2014 at 10:33 AM 0
Share

Almost there. But you are still calling AttackEnemy every frame. Hence starting a new coroutine every frame.

$$anonymous$$ey points to note

  • Only call StartCoroutine once.

  • $$anonymous$$ake AttackEnemy a coroutine. It should yield the result of the Fight and Defend coroutines.

  • Initiative should only be called after the fight and defend are finished.

avatar image
0

Answer by devstudents · Sep 27, 2014 at 09:52 AM

I finally realised what I was doing wrong with the if statement. The Initiative() method had to be called in the if statements when the timer reached zero. This is the only way I could change the value of "value" in Update without it messing up the if statements. The only problem is that value needs to be initialised elsewhere which means the very first attack or defend is not randomly determined. Here is the fixed code:

     public bool value; 
     public float attackTimer; 
     public float attackLength; 
     public AnimationClip attack; 
     public AnimationClip playerBlock; 
 
     void Start()
     {
         attackTimer = 1;
         attackLength = 1;
     }
 
     void Update () 
     {
         AttackEnemy(); 
     }
     
     private void AttackEnemy()
     {
         if(value == true && attackTimer >= 0)
         {
             attackTimer -= Time.deltaTime;
             animation.Play(attack.name); 
             if(attackTimer <= 0)
             {
                 value = Initiative();
                 attackTimer = attackLength;
             }
         }
         else if(value == false && attackTimer >= 0)
         {
             attackTimer -= Time.deltaTime;
             animation.Play (playerBlock.name); 
             if(attackTimer <= 0)
             {
                 value = Initiative();
                 attackTimer = attackLength;
             }
         }
     }
     
     public bool Initiative()
     {
         int playerRoll = Random.Range(1,20);
         int enemyRoll = Random.Range(1,20);
         if(playerRoll > enemyRoll)
         {
             return true;
         }
         else
         {
             return false;
         }
     }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

3 People are following this question.

avatar image avatar image avatar image

Related Questions

The name 'Joystick' does not denote a valid type ('not found') 2 Answers

How to use the Regex class to check for string with case insensitive? 1 Answer

Remove GUI Buttons in Prime 31 Touch kit. 1 Answer

conditional spawning 1 Answer

Blocking one button's function when other pressed 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges