Public
AI for following paths.
This AI is the default movement script which comes with the A* Pathfinding Project. It is in no way required by the rest of the system, so feel free to write your own. But I hope this script will make it easier to set up movement for the characters in your game. This script works well for many types of units, but if you need the highest performance (for example if you are moving hundreds of characters) you may want to customize this script or write a custom movement script to be able to optimize it specifically for your game.
This script will try to follow a target transform. At regular intervals, the path to that target will be recalculated. It will in the Update method try to move towards the next point in the path. However it will only move in roughly forward direction (Z+ axis) of the character, but it will rotate around it's Y-axis to make it possible to reach the destination.
Quick overview of the variables
In the inspector in Unity, you will see a bunch of variables. You can view detailed information further down, but here's a quick overview.
The repathRate determines how often it will search for new paths, if you have fast moving targets, you might want to set it to a lower value. The destination field is where the AI will try to move, it can be a point on the ground where the player has clicked in an RTS for example. Or it can be the player object in a zombie game. The maxSpeed is self-explanatory, as is rotationSpeed. however slowdownDistance might require some explanation: It is the approximate distance from the target where the AI will start to slow down. Setting it to a large value will make the AI slow down very gradually. pickNextWaypointDist determines the distance to the point the AI will move to (see image below).
Below is an image illustrating several variables that are exposed by this class (pickNextWaypointDist, steeringTarget, desiredVelocity)
This script has many movement fallbacks. If it finds an RVOController attached to the same GameObject as this component, it will use that. If it fins a character controller it will also use that. If it finds a rigidbody it will use that. Lastly if will fall back to simply modifying Transform.position which is guaranteed to always work and is also the most performant option.
Public Methods
void
OnPathComplete
(
)
Called when a requested path has been calculated.
A path is first requested by #UpdatePath, it is then calculated, probably in the same or the next frame. Finally it is returned to the seeker which forwards it to this function.
void
OnTargetReached
()
The end of the path has been reached.
If you want custom logic for when the AI has reached it's destination add it here. You can also create a new script which inherits from this one and override the function in that script.
This method will be called again if a new path is calculated as the destination may have changed. So when the agent is close to the destination this method will typically be called every repathRate seconds.
void
Teleport
(
Vector3 | newPosition | |
bool | clearPath=true | |
)
Instantly move the agent to a new position.
This will trigger a path recalculation (if clearPath is true, which is the default) so if you want to teleport the agent and change its destination it is recommended that you set the destination before calling this method.
The current path will be cleared by default.
See
Works similarly to Unity's NavmeshAgent.Warp.
SearchPath
Public Variables
bool
alwaysDrawGizmos
Draws detailed gizmos constantly in the scene view instead of only when the agent is selected and settings are being modified.
float
endReachedDistance = 0.2F
Distance to the end point to consider the end of path to be reached.
When the end is within this distance then OnTargetReached will be called and reachedEndOfPath will return true.
bool
hasPath
True if this agent currently has a path that it follows.
bool
pathPending
True if a path is currently being calculated.
float
pickNextWaypointDist = 2
How far the AI looks ahead along the path to determine the point it moves to.
bool
reachedEndOfPath
True if the agent has reached the end of the current path.
This is the approximate distance the AI has to move to reach the end of the path it is currently traversing.
Note that setting the destination does not immediately update the path, nor is there any guarantee that the AI will actually be able to reach the destination that you set. The AI will try to get as close as possible.
It is very hard to provide a method for detecting if the AI has reached the destination that works across all different games because the destination may not even lie on the navmesh and how that is handled differs from game to game (see also the code snippet in the docs for destination).
float
remainingDistance
Remaining distance along the current path to the end of the path.
For the RichAI movement script this may not always be precisely known, especially when far away from the destination. In those cases an approximate distance will be returned.
If the agent does not currently have a path, then positive infinity will be returned.
float
rotationSpeed = 360
Rotation speed in degrees per second.
Rotation is calculated using Quaternion.RotateTowards. This variable represents the rotation speed in degrees per second. The higher it is, the faster the character will be able to rotate.
float
slowdownDistance = 0.6F
Distance from the end of the path where the AI will start to slow down.
bool
slowWhenNotFacingTarget = true
Slow down when not facing the target direction.
Incurs at a small performance overhead.
Vector3
steeringTarget
Point on the path which the agent is currently moving towards.
This is usually a point a small distance ahead of the agent or the end of the path.
If the agent does not have a path at the moment, then the agent's current position will be returned.
CloseToDestinationMode
whenCloseToDestination = CloseToDestinationMode.Stop
What to do when within endReachedDistance units from the destination.
The character can either stop immediately when it comes within that distance, which is useful for e.g archers or other ranged units that want to fire on a target. Or the character can continue to try to reach the exact destination point and come to a full stop there. This is useful if you want the character to reach the exact point that you specified.
Inherited Public Members
bool
canMove = true
Enables or disables movement completely.
If you want the agent to stand still, but still react to local avoidance and use gravity: use isStopped instead.
This is also useful if you want to have full control over when the movement calculations run. Take a look at MovementUpdate
bool
canSearch = true
Enables or disables recalculating the path at regular intervals.
Setting this to false does not stop any active path requests from being calculated or stop it from continuing to follow the current path.
Note that this only disables automatic path recalculations. If you call the SearchPath() method a path will still be calculated.
float
centerOffset = 1
Offset along the Y coordinate for the ground raycast start position.
Normally the pivot of the character is at the character's feet, but you usually want to fire the raycast from the character's center, so this value should be half of the character's height.
A green gizmo line will be drawn upwards from the pivot point of the character to indicate where the raycast will start.
Vector3
desiredVelocity
Velocity that this agent wants to move with.
Includes gravity and local avoidance if applicable.
Position in the world that this agent should move to.
If no destination has been set yet, then (+infinity, +infinity, +infinity) will be returned.
Note that setting this property does not immediately cause the agent to recalculate its path. So it may take some time before the agent starts to move towards this point. Most movement scripts have a repathRate field which indicates how often the agent looks for a new path. You can also call the SearchPath method to immediately start to search for a new path. Paths are calculated asynchronously so when an agent starts to search for path it may take a few frames (usually 1 or 2) until the result is available. During this time the #pathPending property will return true.
If you are setting a destination and then want to know when the agent has reached that destination then you should check both #pathPending and #reachedEndOfPath: IEnumerator Start () {
ai.destination = somePoint;
// Start to search for a path to the destination immediately
// Note that the result may not become available until after a few frames
// ai.pathPending will be true while the path is being calculated
ai.SearchPath();
// Wait until we know for sure that the agent has calculated a path to the destination we set above
while (ai.pathPending || !ai.reachedEndOfPath) {
yield return null;
}
// The agent has reached the destination now
}
void
FinalizeMovement
(
Vector3 | nextPosition | New position of the agent. |
Quaternion | nextRotation | New rotation of the agent. |
)
Moves the agent to a position.
This is used if you want to override how the agent moves. For example if you are using root motion with Mecanim.
This will use a CharacterController, Rigidbody, Rigidbody2D or the Transform component depending on what options are available.
The agent will be clamped to the navmesh after the movement (if such information is available, generally this is only done by the RichAI component).
Vector3
GetFeetPosition
()
Position of the base of the character.
This is used for pathfinding as the character's pivot point is sometimes placed at the center of the character instead of near the feet. In a building with multiple floors the center of a character may in some scenarios be closer to the navmesh on the floor above than to the floor below which could cause an incorrect path to be calculated. To solve this the start point of the requested paths is always at the base of the character.
Vector3
gravity = new Vector3(float.NaN, float.NaN, float.NaN)
Gravity to use.
If set to (NaN,NaN,NaN) then Physics.Gravity (configured in the Unity project settings) will be used. If set to (0,0,0) then no gravity will be used and no raycast to check for ground penetration will be performed.
Layer mask to use for ground placement.
Make sure this does not include the layer of any colliders attached to this gameobject.
bool
isStopped
Gets or sets if the agent should stop moving.
If this is set to true the agent will immediately start to slow down as quickly as it can to come to a full stop. The agent will still react to local avoidance and gravity (if applicable), but it will not try to move in any particular direction.
The current path of the agent will not be cleared, so when this is set to false again the agent will continue moving along the previous path.
This is a purely user-controlled parameter, so for example it is not set automatically when the agent stops moving because it has reached the target. Use #reachedEndOfPath for that.
If this property is set to true while the agent is traversing an off-mesh link (RichAI script only), then the agent will continue traversing the link and stop once it has completed it.
Note
This is not the same as the canMove setting which some movement scripts have. The canMove setting disables movement calculations completely (which among other things makes it not be affected by local avoidance or gravity). For the AILerp movement script which doesn't use gravity or local avoidance anyway changing this property is very similar to changing canMove.
The #steeringTarget property will continue to indicate the point which the agent would move towards if it would not be stopped.
float
maxSpeed = 1
Max speed in world units per second.
void
Move
(
Vector3 | deltaPosition | Direction and distance to move the agent in world space. |
)
Move the agent.
This is intended for external movement forces such as those applied by wind, conveyor belts, knockbacks etc.
Some movement scripts may ignore this completely (notably the AILerp script) if it does not have any concept of being moved externally.
The agent will not be moved immediately when calling this method. Instead this offset will be stored and then applied the next time the agent runs its movement calculations (which is usually later this frame or the next frame). If you want to move the agent immediately then call: ai.Move(someVector);
ai.FinalizeMovement(ai.position, ai.rotation);
Plane which this agent is moving in.
This is used to convert between world space and a movement plane to make it possible to use this script in both 2D games and 3D games.
void
MovementUpdate
(
float | deltaTime | time to simulate movement for. Usually set to Time.deltaTime. |
out Vector3 | nextPosition | the position that the agent wants to move to during this frame. |
out Quaternion | nextRotation | the rotation that the agent wants to rotate to during this frame. |
)
Calculate how the character wants to move during this frame.
Note that this does not actually move the character. You need to call FinalizeMovement for that. This is called automatically unless canMove is false.
To handle movement yourself you can disable canMove and call this method manually. This code will replicate the normal behavior of the component: void Update () {
ai.canMove = false;
Vector3 nextPosition;
Quaternion nextRotation;
ai.MovementUpdate(Time.deltaTime, out nextPosition, out nextRotation);
// Modify nextPosition and nextRotation in any way you wish
ai.FinalizeMovement(nextPosition, nextRotation);
}
System.Action
onSearchPath
Called when the agent recalculates its path.
This is called both for automatic path recalculations (see canSearch) and manual ones (see SearchPath).
Position of the agent.
In world space. If updatePosition is true then this value is idential to transform.position.
float
repathRate = 0.5f
Determines how often the agent will search for new paths (in seconds).
The agent will plan a new path to the target every N seconds.
If you have fast moving targets or AIs, you might want to set it to a lower value.
Rotation of the agent.
If updateRotation is true then this value is identical to transform.rotation.
bool
rotationIn2D = false
If true, the forward axis of the character will be along the Y axis instead of the Z axis.
For 3D games you most likely want to leave this the default value which is false. For 2D games you most likely want to change this to true as in 2D games you usually want the Y axis to be the forwards direction of the character.
void
SearchPath
()
Recalculate the current path.
You can for example use this if you want very quick reaction times when you have changed the destination so that the agent does not have to wait until the next automatic path recalculation (see canSearch).
If there is an ongoing path calculation, it will be canceled, so make sure you leave time for the paths to get calculated before calling this function again. A canceled path will show up in the log with the message "Canceled by script" (see #Seeker.CancelCurrentPathRequest()).
If no destination has been set yet then nothing will be done.
Note
The path result may not become available until after a few frames. During the calculation time the #pathPending property will return true.
Quaternion
SimulateRotationTowards
(
Vector3 | direction | Direction in world space to rotate towards. |
float | maxDegrees | Maximum number of degrees to rotate this frame. |
)
Simulates rotating the agent towards the specified direction and returns the new rotation.
Note that this only calculates a new rotation, it does not change the actual rotation of the agent. Useful when you are handling movement externally using FinalizeMovement but you want to use the built-in rotation code.
bool
updatePosition = true
Determines if the character's position should be coupled to the Transform's position.
If false then all movement calculations will happen as usual, but the object that this component is attached to will not move instead only the position property will change.
This is useful if you want to control the movement of the character using some other means such as for example root motion but still want the AI to move freely.
bool
updateRotation = true
Determines if the character's rotation should be coupled to the Transform's rotation.
If false then all movement calculations will happen as usual, but the object that this component is attached to will not rotate instead only the rotation property will change.
Actual velocity that the agent is moving with.
In world units per second.
Private/Protected Members
void
ApplyGravity
(
)
Accelerates the agent downwards.
Vector2
CalculateDeltaToMoveThisFrame
(
Vector2 | position | |
float | distanceToEndOfPath | |
float | deltaTime | |
)
Calculates how far to move during a single frame.
void
CalculateNextRotation
(
)
void
CalculatePathRequestEndpoints
(
)
Outputs the start point and end point of the next automatic path request.
This is a separate method to make it easy for subclasses to swap out the endpoints of path requests. For example the #LocalSpaceRichAI script which requires the endpoints to be transformed to graph space first.
void
CancelCurrentPathRequest
()
bool IAstarAI.
canMove
Enables or disables movement completely.
If you want the agent to stand still, but still react to local avoidance and use gravity: use isStopped instead.
This is also useful if you want to have full control over when the movement calculations run. Take a look at MovementUpdate
bool IAstarAI.
canSearch
Enables or disables recalculating the path at regular intervals.
Setting this to false does not stop any active path requests from being calculated or stop it from continuing to follow the current path.
Note that this only disables automatic path recalculations. If you call the SearchPath() method a path will still be calculated.
Vector3
ClampToNavmesh
(
Vector3 | position | Current position of the character. |
out bool | positionChanged | True if the character's position was modified by this method. |
)
Constrains the character's position to lie on the navmesh.
Not all movement scripts have support for this.
Return
New position of the character that has been clamped to the navmesh.
Cached CharacterController component.
void
FixedUpdate
()
Called every physics update.
If rigidbodies are used then all movement happens here.
Color
GizmoColorRaycast = new Color(118.0f/255, 206.0f/255, 112.0f/255)
Helper which calculates points along the current path.
Vector2
lastDeltaPosition
Amount which the character wants or tried to move with during the last frame.
float
lastDeltaTime
Delta time used for movement during the last frame.
float
lastRepath = float.NegativeInfinity
Time when the last path request was started.
float IAstarAI.
maxSpeed
Max speed in world units per second.
void
MovementUpdateInternal
(
)
Called during either Update or FixedUpdate depending on if rigidbodies are used for movement or not.
void
OnDrawGizmosSelected
()
void
OnEnable
()
Called when the component is enabled.
int
OnUpgradeSerializedData
(
int | version | |
bool | unityThread | |
)
Handle serialization backwards compatibility.
Current path which is followed.
Position of the character at the end of the last frame.
Position of the character at the end of the frame before the last frame.
Vector3
RaycastPosition
(
Vector3 | position | Position of the character in the world. |
float | lastElevation | Elevation coordinate before the agent was moved. This is along the 'up' axis of the movementPlane. |
)
Checks if the character is grounded and prevents ground penetration.
Sets verticalVelocity to zero if the character is grounded.
Return
The new position of the character.
IEnumerator
RepeatTrySearchPath
()
Tries to search for a path every repathRate seconds.
Cached Rigidbody component.
Cached Rigidbody component.
Cached RVOController component.
bool
shouldRecalculatePath
True if the path should be automatically recalculated as soon as possible.
Vector3
simulatedPosition
Position of the agent.
If updatePosition is true then this value will be synchronized every frame with Transform.position.
Rotation of the agent.
If updateRotation is true then this value will be synchronized every frame with Transform.rotation.
Quaternion
SimulateRotationTowards
(
Vector2 | direction | Direction in the movement plane to rotate towards. |
float | maxDegrees | Maximum number of degrees to rotate this frame. |
)
Simulates rotating the agent towards the specified direction and returns the new rotation.
Note that this only calculates a new rotation, it does not change the actual rotation of the agent.
void
Start
()
Starts searching for paths.
If you override this method you should in most cases call base.Start () at the start of it.
Cached Transform component.
void
Update
()
Called every frame.
If no rigidbodies are used then all movement happens here.
bool
usingGravity
Indicates if gravity is used during this frame.
Current desired velocity of the agent (does not include local avoidance and physics).
Lies in the movement plane.
float
verticalVelocity
Velocity due to gravity.
Perpendicular to the movement plane.
When the agent is grounded this may not accurately reflect the velocity of the agent. It may be non-zero even though the agent is not moving.
bool
waitingForPathCalculation = false
Only when the previous path has been calculated should the script consider searching for a new path.
Deprecated Members
Vector3
CalculateVelocity
(
)
Current desired velocity of the agent (excluding physics and local avoidance but it includes gravity).
Deprecated
This method no longer calculates the velocity. Use the desiredVelocity property instead.
float
speed
Maximum speed in world units per second.
Vector3
targetDirection
Direction that the agent wants to move in (excluding physics and local avoidance).
bool
TargetReached
True if the end of the path has been reached.
Deprecated
When unifying the interfaces for different movement scripts, this property has been renamed to reachedEndOfPath
float
turningSpeed
Rotation speed.
Deprecated
This field has been renamed to rotationSpeed and is now in degrees per second instead of a damping factor.