Moving our Agents
General AI Behaviours
Since we’re mimicking the previous behaviours of the Survival Shooter, our agent should:
- Go to the where the player is
- Attacking the Player
- Stopping Actions Upon Death
- Stopping the Agent on Death
Let’s get started with setting up our agent to move.
Note
If you’re using the Asset Store version, the following components can be removed from Zombear, Zombunny, and the Hellaphant prefabs.
EnemyMovement
EnemyAttack
1. Moving the Agent
The agent needs to understand where it’s supposed to move and when it should stop moving. In this case, it’s quite simple. Every agent knows where the player, Sleepy Boy, is at any point in time.
Let’s create a Variable in Assets/Scripts/AI/Variables
, called Vector3Variable.cs
. This will
store the player’s position and share that information to all nodes within the Template.
// Vector3Variable.cs
using InitialPrefabs.DaniAI;
using UnityEngine;
// This creates a Variable which stores a Vector3
public class Vector3Variable : GenericVariable<Vector3> { }
When the script is done compiling, head back to the Editor and switch over to the Variables tab
in the Inspector. Click the (+) sign and add the Vector3Variable
. By default, the Variable’s name
will have the class' name. Change the name to “Position” for convenience.
Our variable stores the player’s position, but it needs to be updated. For this, we create an
Observer called GetPlayerPosition.cs
. The observer will cache the player within the scene and always
update its current position.
// GetPlayerPosition.cs
using InitialPrefabs.DaniAI;
using UnityEngine;
public class GetPlayerPosition : BoolObserver {
public string vector3VariableName = "Position";
private Vector3Variable playerPosition;
private Transform player;
// Use this for initialization
public override void OnStart () {
// Get a reference to the variable in DaniAI
playerPosition = Template.GetVariable<Vector3Variable> (vector3VariableName);
// Get the reference to the Player
player = GameObject.FindGameObjectWithTag ("Player").transform;
}
// Runs every frame like Unity's Update () call
public override bool OnObserverUpdate () {
// Set the player's position
playerPosition.Value = player.transform.position;
// For this basic AI, we'll always return true
return true;
}
}
Once created inside the editor, create a Decision (we’ll call it Attack Player) and hook it up to our Get Player Position
Observer.
Conditions
Our GetPlayerPosition always returns true, likewise our Condition must evaulate that output. Click on the connection
and set the Comparison value to True
.
We need a final component to create this entire context. We write a simple Move.cs
Action Script.
using UnityEngine;
using UnityEngine.AI;
/// <summary>
/// Moves the agent towards a specified position.
/// </summary>
public class Move : Action {
[Tooltip ("How far should the AI stop before the target destination?")]
public float stoppingDistance = 1.2f;
[Header ("Variables")]
[Tooltip ("What is the name of the Vector3Variable?")]
public string vector3VariableName = "Position";
private Vector3Variable position;
private NavMeshAgent navAgent;
public override void OnStart () {
// Get the variable
position = Template.GetVariable<Vector3Variable> (vector3VariableName);
// Get a reference to the NavMeshAgent
navAgent = GetComponent<NavMeshAgent> ();
}
public override void OnActionStart () {
// Ensure that the NavMeshAgent is not stopped and set the destination
navAgent.isStopped = false;
}
public override ActionState OnActionUpdate () {
// The player is always moving - so the NavMeshAgent needs to update its position
navAgent.SetDestination (position.Value);
// If the NavMeshAgent is close enough to the player, succeed the Action
if (navAgent.hasPath && navAgent.remainingDistance <= stoppingDistance) {
return ActionState.Success;
} else {
// otherwise continue running the Action
return ActionState.Running;
}
}
public override void OnActionEnd (ActionState state) {
// Stop the NavMeshAgent and clear the path as long as the NavMeshAgent
// is on the NavMesh
if (navAgent.isOnNavMesh) {
navAgent.isStopped = true;
navAgent.ResetPath ();
}
}
}
Let’s add Move
to our Zombie Brain and begin adding this to our Zombear, Zombunny, and the Hellaphant prefabs.
Finally, add the AIBrain component and apply the prefabs!
You should get a behaviour like the following gif.