Wander movement for Enemy AI (different approach)

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)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum EnemyState
{
    Wander,

    Follow,

    Die,
}

public class EnemyController : MonoBehaviour
{

    GameObject player;

    private Animator anim;

    public EnemyState currState = EnemyState.Wander;

    public float range;

    public float speed;

    private bool chooseDir = false;

    public int randomDir;

    // Start is called before the first frame update
    void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player");
        anim = GetComponent<Animator>();

    }

    // Update is called once per frame
    void Update()
    {
        switch (currState)
        {
            case (EnemyState.Wander):
                Wander();
                break;
            case (EnemyState.Follow):
                Follow();
                break;
            case (EnemyState.Die):

                break;
        }

        if (IsPlayerInRange(range) && currState != EnemyState.Die)
        {
            currState = EnemyState.Follow;
        }
        else if (!IsPlayerInRange(range) && currState != EnemyState.Die)
        {
            currState = EnemyState.Wander;
        }
    }

    private bool IsPlayerInRange(float range)
    {
        return Vector3.Distance(transform.position, player.transform.position) <= range;
    }

    private IEnumerator ChooseDirection()
    {
        chooseDir = true;
        yield return new WaitForSeconds(Random.Range(1f, 3f));
        randomDir = Random.Range(1, 8);
        chooseDir = false;
    }

    void Wander()
    {
        if (!chooseDir)
        {
            StartCoroutine(ChooseDirection());
        }

        if (randomDir == 1)
        {
            anim.SetBool("IsRunningLeft", false);
            anim.SetBool("IsRunningRight", true);
            transform.position += transform.right * speed * Time.deltaTime;

        }
        if (randomDir == 2)
        {
            anim.SetBool("IsRunningRight", false);
            anim.SetBool("IsRunningLeft", true);
            transform.position += -transform.right * speed * Time.deltaTime;
        }
        if (randomDir == 3)
        {
            transform.position += transform.up * speed * Time.deltaTime;
        }
        if (randomDir == 4)
        {
            transform.position += transform.up * speed * Time.deltaTime;
        }
        if (randomDir == 5)
        {
            transform.position += transform.right * speed * Time.deltaTime;
            transform.position += transform.up * speed * Time.deltaTime;
        }
        if (randomDir == 6)
        {
            transform.position += transform.right * speed * Time.deltaTime;
            transform.position += -transform.up * speed * Time.deltaTime;
        }
        if (randomDir == 7)
        {
            transform.position += -transform.right * speed * Time.deltaTime;
            transform.position += transform.up * speed * Time.deltaTime;
        }
        if (randomDir == 8)
        {
            transform.position += -transform.right * speed * Time.deltaTime;
            transform.position += -transform.up * speed * Time.deltaTime;
        }

        if (IsPlayerInRange(range))
        {
            currState = EnemyState.Follow;
        }
    }

    void Follow()
    {
        transform.position = Vector2.MoveTowards(transform.position, player.transform.position, speed * Time.deltaTime);
    }

    public void Death()
    {
        Destroy(gameObject);
    }
}

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.

1 Like

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.

“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.

1 Like

Why do you only animate left and right?
Anyway, you should consider a Switch/Case logic to clean your code up a bit.

// Inside Wander()

switch(randomDir)
{
case 8:
transform.position += -transform.right * speed * Time.deltaTime;
transform.position += -transform.up * speed * Time.deltaTime;
break;

case 7:
transform.position += -transform.right * speed * Time.deltaTime;
transform.position += transform.up * speed * Time.deltaTime;
break;

case 6:
transform.position += transform.right * speed * Time.deltaTime;
transform.position += -transform.up * speed * Time.deltaTime;
break;

case 5:
transform.position += transform.right * speed*Time.deltaTime;
transform.position += transform.up * speed * Time.deltaTime;
break;

case 4:
transform.position += transform.up * speed*Time.deltaTime;
break;

case 3:
transform.position += transform.up * speed *Time.deltaTime;
break;

case 2:
anim.SetBool("IsRunningRight",false);
anim.SetBool("IsRunningLeft",true);
transform.position += -transform.right * speed*Time.deltaTime;
break;

case 1:
anim.SetBool("IsRunningRight",true);
anim.SetBool("IsRunningLeft",false);
transform.position += transform.right * speed*Time.deltaTime;
break;

default:
// Insert a fail-safe code to insure something happens
// Maybe pick a new random direction?
break;
}

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.

if (randomDir == 1)
        {
            anim.SetBool("IsRunningLeft", false);
            anim.SetBool("IsRunningRight", true);
            transform.position += transform.right * speed * Time.deltaTime;
        }
      else  if (randomDir == 2)
        {
            anim.SetBool("IsRunningRight", false);
            anim.SetBool("IsRunningLeft", true);
            transform.position += -transform.right * speed * Time.deltaTime;
        }
       else if (randomDir == 3)
        {
            transform.position += transform.up * speed * Time.deltaTime;
        }
       else if (randomDir == 4)
        {
            transform.position += transform.up * speed * Time.deltaTime;
        }
       else if (randomDir == 5)
        {
            transform.position += transform.right * speed * Time.deltaTime;
            transform.position += transform.up * speed * Time.deltaTime;
        }
       else if (randomDir == 6)
        {
            transform.position += transform.right * speed * Time.deltaTime;
            transform.position += -transform.up * speed * Time.deltaTime;
        }
       else if (randomDir == 7)
        {
            transform.position += -transform.right * speed * Time.deltaTime;
            transform.position += transform.up * speed * Time.deltaTime;
        }
       else if (randomDir == 8)
        {
            transform.position += -transform.right * speed * Time.deltaTime;
            transform.position += -transform.up * speed * Time.deltaTime;
        }
else { // All checks failed, pick a new random number or something }
1 Like

Hope that is good now

I think i get it, thanks for the help

You let me know what you don’t understand about it and I will tell you, amigo :slight_smile:

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.

Show me exactly what you mean and I will tell you :slight_smile:

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.

 void Update()
    {
If(currState != EnemyState.Die) {
        switch (currState)
        {
            case (EnemyState.Wander):
                Wander();
                break;
            case (EnemyState.Follow):
                Follow();
                break;
            case (EnemyState.Die):
                break;
        }
        if (IsPlayerInRange(range))
        {
            currState = EnemyState.Follow;
        }
        else
        {
            currState = EnemyState.Wander;
        }
}
    }

Yes, the code looks okay to me. However, if you want it to cease action upon enemy death, you may want to do:

if(IsPlayerInRange(range) && currState != EnemyState.Die)
1 Like