Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Wander movement for Enemy AI (different approach)

Discussion in '2D' started by SonilPro, Nov 28, 2019.

  1. SonilPro

    SonilPro

    Joined:
    Jan 29, 2019
    Posts:
    5
    Can this be written differently, this is working i just dont know if there is a better solution(Ps. this is a enemy wander script)
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public enum EnemyState
    7. {
    8.     Wander,
    9.  
    10.     Follow,
    11.  
    12.     Die,
    13. }
    14.  
    15. public class EnemyController : MonoBehaviour
    16. {
    17.  
    18.     GameObject player;
    19.  
    20.     private Animator anim;
    21.  
    22.     public EnemyState currState = EnemyState.Wander;
    23.  
    24.     public float range;
    25.  
    26.     public float speed;
    27.  
    28.     private bool chooseDir = false;
    29.  
    30.     public int randomDir;
    31.  
    32.     // Start is called before the first frame update
    33.     void Start()
    34.     {
    35.         player = GameObject.FindGameObjectWithTag("Player");
    36.         anim = GetComponent<Animator>();
    37.  
    38.     }
    39.  
    40.     // Update is called once per frame
    41.     void Update()
    42.     {
    43.         switch (currState)
    44.         {
    45.             case (EnemyState.Wander):
    46.                 Wander();
    47.                 break;
    48.             case (EnemyState.Follow):
    49.                 Follow();
    50.                 break;
    51.             case (EnemyState.Die):
    52.  
    53.                 break;
    54.         }
    55.  
    56.         if (IsPlayerInRange(range) && currState != EnemyState.Die)
    57.         {
    58.             currState = EnemyState.Follow;
    59.         }
    60.         else if (!IsPlayerInRange(range) && currState != EnemyState.Die)
    61.         {
    62.             currState = EnemyState.Wander;
    63.         }
    64.     }
    65.  
    66.     private bool IsPlayerInRange(float range)
    67.     {
    68.         return Vector3.Distance(transform.position, player.transform.position) <= range;
    69.     }
    70.  
    71.     private IEnumerator ChooseDirection()
    72.     {
    73.         chooseDir = true;
    74.         yield return new WaitForSeconds(Random.Range(1f, 3f));
    75.         randomDir = Random.Range(1, 8);
    76.         chooseDir = false;
    77.     }
    78.  
    79.     void Wander()
    80.     {
    81.         if (!chooseDir)
    82.         {
    83.             StartCoroutine(ChooseDirection());
    84.         }
    85.  
    86.         if (randomDir == 1)
    87.         {
    88.             anim.SetBool("IsRunningLeft", false);
    89.             anim.SetBool("IsRunningRight", true);
    90.             transform.position += transform.right * speed * Time.deltaTime;
    91.  
    92.         }
    93.         if (randomDir == 2)
    94.         {
    95.             anim.SetBool("IsRunningRight", false);
    96.             anim.SetBool("IsRunningLeft", true);
    97.             transform.position += -transform.right * speed * Time.deltaTime;
    98.         }
    99.         if (randomDir == 3)
    100.         {
    101.             transform.position += transform.up * speed * Time.deltaTime;
    102.         }
    103.         if (randomDir == 4)
    104.         {
    105.             transform.position += transform.up * speed * Time.deltaTime;
    106.         }
    107.         if (randomDir == 5)
    108.         {
    109.             transform.position += transform.right * speed * Time.deltaTime;
    110.             transform.position += transform.up * speed * Time.deltaTime;
    111.         }
    112.         if (randomDir == 6)
    113.         {
    114.             transform.position += transform.right * speed * Time.deltaTime;
    115.             transform.position += -transform.up * speed * Time.deltaTime;
    116.         }
    117.         if (randomDir == 7)
    118.         {
    119.             transform.position += -transform.right * speed * Time.deltaTime;
    120.             transform.position += transform.up * speed * Time.deltaTime;
    121.         }
    122.         if (randomDir == 8)
    123.         {
    124.             transform.position += -transform.right * speed * Time.deltaTime;
    125.             transform.position += -transform.up * speed * Time.deltaTime;
    126.         }
    127.  
    128.         if (IsPlayerInRange(range))
    129.         {
    130.             currState = EnemyState.Follow;
    131.         }
    132.     }
    133.  
    134.     void Follow()
    135.     {
    136.         transform.position = Vector2.MoveTowards(transform.position, player.transform.position, speed * Time.deltaTime);
    137.     }
    138.  
    139.     public void Death()
    140.     {
    141.         Destroy(gameObject);
    142.     }
    143. }
    144.  
     
    Last edited: Nov 29, 2019
  2. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    Hi @SonilPro

    You would be better off if you explained what you are trying to achieve and your super generic post heading makes it sure no one else will ever find this thread... making this only helpful for you... so perhaps edit the heading?

    Are you trying to simply set a random move direction based on random int value?

    I didn't bother to read too far, but the code seems a bit convoluted.

    I would just have a list / array of directions (Vector2 values) and then I would pick a new direction delta from this list after enough time has passed, and each update I would call the Wander and it will move the character with delta. I wouldn't put any direction selection logic in Wander method.

    But if this works already for you, you can make it more understandable / shorter later. There is always another way to do the same thing.
     
    SonilPro likes this.
  3. SonilPro

    SonilPro

    Joined:
    Jan 29, 2019
    Posts:
    5
    Thank you for the hints, i will make sure to make the headlines a little more appropriate next time, and thank you for the answer.
     
  4. eses

    eses

    Joined:
    Feb 26, 2013
    Posts:
    2,637
    "i will make sure to make the headlines a little more appropriate next time"

    No need to wait for next time - next time won't fix this thread's heading; just press "Thread Tools" button on top right above your original post and change the heading to something descriptive.
     
    SonilPro likes this.
  5. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    Why do you only animate left and right?
    Anyway, you should consider a Switch/Case logic to clean your code up a bit.

    Code (CSharp):
    1. // Inside Wander()
    2.  
    3. switch(randomDir)
    4. {
    5. case 8:
    6. transform.position += -transform.right * speed * Time.deltaTime;
    7. transform.position += -transform.up * speed * Time.deltaTime;
    8. break;
    9.  
    10. case 7:
    11. transform.position += -transform.right * speed * Time.deltaTime;
    12. transform.position += transform.up * speed * Time.deltaTime;
    13. break;
    14.  
    15. case 6:
    16. transform.position += transform.right * speed * Time.deltaTime;
    17. transform.position += -transform.up * speed * Time.deltaTime;
    18. break;
    19.  
    20. case 5:
    21. transform.position += transform.right * speed*Time.deltaTime;
    22. transform.position += transform.up * speed * Time.deltaTime;
    23. break;
    24.  
    25. case 4:
    26. transform.position += transform.up * speed*Time.deltaTime;
    27. break;
    28.  
    29. case 3:
    30. transform.position += transform.up * speed *Time.deltaTime;
    31. break;
    32.  
    33. case 2:
    34. anim.SetBool("IsRunningRight",false);
    35. anim.SetBool("IsRunningLeft",true);
    36. transform.position += -transform.right * speed*Time.deltaTime;
    37. break;
    38.  
    39. case 1:
    40. anim.SetBool("IsRunningRight",true);
    41. anim.SetBool("IsRunningLeft",false);
    42. transform.position += transform.right * speed*Time.deltaTime;
    43. break;
    44.  
    45. default:
    46. // Insert a fail-safe code to insure something happens
    47. // Maybe pick a new random direction?
    48. break;
    49. }
    Otherwise, consider else if statements rather than a bunch of if's. Generally these are all the same, but I believe switch and else/if statements check more systematically. Which regular if statements will check every condition every single time regardless if a solution has returned true. Switch and else if stop checking once something returns true.

    Code (CSharp):
    1. if (randomDir == 1)
    2.         {
    3.             anim.SetBool("IsRunningLeft", false);
    4.             anim.SetBool("IsRunningRight", true);
    5.             transform.position += transform.right * speed * Time.deltaTime;
    6.         }
    7.       else  if (randomDir == 2)
    8.         {
    9.             anim.SetBool("IsRunningRight", false);
    10.             anim.SetBool("IsRunningLeft", true);
    11.             transform.position += -transform.right * speed * Time.deltaTime;
    12.         }
    13.        else if (randomDir == 3)
    14.         {
    15.             transform.position += transform.up * speed * Time.deltaTime;
    16.         }
    17.        else if (randomDir == 4)
    18.         {
    19.             transform.position += transform.up * speed * Time.deltaTime;
    20.         }
    21.        else if (randomDir == 5)
    22.         {
    23.             transform.position += transform.right * speed * Time.deltaTime;
    24.             transform.position += transform.up * speed * Time.deltaTime;
    25.         }
    26.        else if (randomDir == 6)
    27.         {
    28.             transform.position += transform.right * speed * Time.deltaTime;
    29.             transform.position += -transform.up * speed * Time.deltaTime;
    30.         }
    31.        else if (randomDir == 7)
    32.         {
    33.             transform.position += -transform.right * speed * Time.deltaTime;
    34.             transform.position += transform.up * speed * Time.deltaTime;
    35.         }
    36.        else if (randomDir == 8)
    37.         {
    38.             transform.position += -transform.right * speed * Time.deltaTime;
    39.             transform.position += -transform.up * speed * Time.deltaTime;
    40.         }
    41. else { // All checks failed, pick a new random number or something }
     
    Last edited: Nov 29, 2019
    SonilPro likes this.
  6. SonilPro

    SonilPro

    Joined:
    Jan 29, 2019
    Posts:
    5
    Hope that is good now
     
  7. SonilPro

    SonilPro

    Joined:
    Jan 29, 2019
    Posts:
    5
    I think i get it, thanks for the help
     
  8. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    You let me know what you don't understand about it and I will tell you, amigo :)
     
  9. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    Is it just me or could you not move the whole if dead statements to the start of the update function so in case of death you do not have to do all the checks when it is dead.
     
  10. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    Show me exactly what you mean and I will tell you :)
     
  11. PuppyPolice

    PuppyPolice

    Joined:
    Oct 27, 2017
    Posts:
    116
    Typing this on my phone so it is quite the pain to edit, anyways check enemystate if dead do nothing else run all the other code since they all assume the enemy state is not dead. That way at least you would avoid all the extra checks when enemy is set to dead.

    Since it is in the update function, less code to run the better due to amount of calls, else I do not think it matters to much.

    Code (CSharp):
    1.  void Update()
    2.     {
    3. If(currState != EnemyState.Die) {
    4.         switch (currState)
    5.         {
    6.             case (EnemyState.Wander):
    7.                 Wander();
    8.                 break;
    9.             case (EnemyState.Follow):
    10.                 Follow();
    11.                 break;
    12.             case (EnemyState.Die):
    13.                 break;
    14.         }
    15.         if (IsPlayerInRange(range))
    16.         {
    17.             currState = EnemyState.Follow;
    18.         }
    19.         else
    20.         {
    21.             currState = EnemyState.Wander;
    22.         }
    23. }
    24.     }
     
  12. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    Yes, the code looks okay to me. However, if you want it to cease action upon enemy death, you may want to do:

    Code (CSharp):
    1. if(IsPlayerInRange(range) && currState != EnemyState.Die)
     
    SonilPro likes this.