- Home /
Enemy AI Movement Decision Making
Hi, everyone,
I'm working on an enemy AI movement system for a Unity platformer game that will allow the enemy to make one of three decisions on a constant basis: idle, move to the right, or move to the left. I want the enemy to be able to pick any of these decisions, even if the decision it just picked will be the same as its next decision (i.e. it can choose "move right" twice in a row, or as many more times as it wants). The script below has no errors, but when I test the game it causes my enemy to stutter around. Sometimes it moves right for a split second, then moves to the left, etc. I feel like the inherent logic of my code is somewhat correct, but the way in which it is implemented needs some work. I appreciate any help you can give me.
By the way, if I put the "MakeMovementDecision" function in the "Start" function the enemy moves .07 units right or left, or is seemingly idle, but never makes another decision about movement again.
 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
 public class AIMovement : MonoBehaviour {
 
 // References the enemy's Rigidbody2D component
 private Rigidbody2D enemyRigidbody;
 
 // Sets the enemy's movement speed
 [SerializeField]
 private int movementSpeed;
 
 // Checks if the enemy is moving (to be used with animations)
 private bool isMoving;
 
 // The direction in which the enemy will move
 private Vector2 directionToMove;
 
 // The random decision (0, 1 or 2) that represents which movement function the enemy will perform
 private int decisionValue;
 
 // The time remaining before the enemy chooses which movement function to perform again
 private float timeTilNextDecision;
 
 // The random float that will be used to determine for how long the enemy remains idle
 private float idleTime;
 
 // The random float that will be used to determine for how long the enemy moves left or right
 private float moveTime;
 
 // Use this for initialization
 void Start () {
 
     // Accesses the enemy's Rigidbody2D component
     enemyRigidbody = GetComponent<Rigidbody2D>();
 }
 
 void FixedUpdate () {
 
     MakeMovementDecision();
 }
 
 /// <summary>
 /// Generates the decision for which type of movement the enemy will perform
 /// </summary>
 private void MakeMovementDecision ()
 {
     // Chooses a value upon which the movement decision will be based
     decisionValue = Random.Range(0, 3);
 
     switch (decisionValue)
     {
         // Keeps the enemy standing still
         case 0:
             Idle();
             break;
 
         // Moves the enemy to the right
         case 1:
             MoveRight();
             break;
 
         // Moves the enemy to the left
         case 2:
             MoveLeft();
             break;
     }
 }
 
 /// <summary>
 /// Causes the enemy to stand still with idle animations 
 /// </summary>
 private void Idle ()
 {
     // Sets the idle stance duration
     idleTime = Random.Range(5.0f, 10.0f);
 
     // Calculates the time until the enemy may decide to change its movement
     timeTilNextDecision = idleTime - Time.deltaTime;
 
     // Sets the movement bool to false to play the idle animations
     isMoving = false;
 
     // Stops the enemy's movement
     enemyRigidbody.velocity = Vector2.zero;
 
     // Checks if the enemy should make a decision on its next movement
     if (timeTilNextDecision < 0)
     {
         MakeMovementDecision();
     }
 
 }
 
 private void MoveRight()
 {
     moveTime = Random.Range(2.0f, 5.01f);
     timeTilNextDecision = moveTime - Time.deltaTime;
     isMoving = true;
     directionToMove = Vector2.right;
     transform.Translate(directionToMove * (movementSpeed * Time.deltaTime));
 
     if (timeTilNextDecision < 0)
     {
         MakeMovementDecision();
     }
 
 }
 
 private void MoveLeft()
 {
     moveTime = Random.Range(2.0f, 5.01f);
     timeTilNextDecision = moveTime - Time.deltaTime;
     isMoving = true;
     directionToMove = Vector2.left;
     transform.Translate(directionToMove * (movementSpeed * Time.deltaTime));
 
     if (timeTilNextDecision < 0)
     {
         MakeMovementDecision();
     }
 
 }
Answer by TheSOULDev · Sep 25, 2017 at 11:30 PM
You have no loop that reduces your timeTilNextDecision. Also, you need coroutines. I rewrote your script:
 public enum AIState
 {
     idle = 0,
     walk_l = 1,
     walk_r = 2
 }
 
 public class AIMovement : MonoBehaviour
 {
     public Vector2 idleRange;    //Add your constant delays here.
     public Vector2 leftRange;
     public Vector2 rightRange;
     
     Rigidbody2D enemyRigidbody;
     
     //Add your other stuff here...
     
     void Start()
     {
         enemyRigidbody = GetComponent<Rigidbody2D>();
         
         DecideMovement();
     }
     
     void DecideMovement()
     {
         StartCoroutine(Execute((AIState)(Random.Range(0, 99998) / 33333)));
     }
     
     public IEnumerator Execute(AIState state)
     {
         if(state == AIState.idle)
         {
             isMoving = false;
             enemyRigidbody.velocity = Vector2.zero;
 
             yield return new WaitForSeconds(Random.Range(idleRange.x, idleRange.y))
         }
         else
         {
             Vector2 dir;
             float Duration;
             
             isMoving = true;
             
             if(state == AIState.walk_l)
             {
                 dir = Vector2.left;
                 Duration = Random.Range(leftRange.x, leftRange.y);
             }
             else if(state == AIState.walk_r)
             {
                 dir = Vector2.right;
                 Duration = Random.Range(rightRange.x, rightRange.y)
             }
             
             while(Duration > 0f)
             {
                 Duration -= Time.deltaTime;
                 transform.Translate(dir * (movementSpeed * Time.deltaTime));
                     
                 yield return null;
             }
         }
         
         DecideMovement();
     }
 }
Comment if you still have problems.
Why are you doing Random.Range(0, 99998) / 33333)) ins$$anonymous$$d of simply do Random.Range(0, 3)?
Thanks for the example, it helped me with something similar.
Your answer
 
 
             Follow this Question
Related Questions
Enemy AI With changing Player 0 Answers
If I duplicate enemies, will their scripts mess each other up? 2 Answers
Unity AI/Enemy won't move towards target 0 Answers
Enemy controller.move script slows down and speeds up. How to get it consistent? 0 Answers
How to Add Knockback Force Based on What Rotation it Came From 2 Answers
 koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                