Custom Local Avoidance Movement Script

This page explains how to integrate local avoidance in your own movement scripts.

Let's build a small concrete example so you can see how it works.
Start by creating a new scene, add a large plane as a ground (position (0,0,0), scale (10,10,10)). Then add a new GameObject, name it "Simulator". Now add the component RVOSimulator, you can find it in Components -> Local Avoidance -> RVO Simulator. You can see that it has a few options, but you can leave them at the default setting for now. However I recommend that you read the class documentation for the RVOSimulator later since the performance is very dependent on those few settings. This component will handle the simulation of our agents as well as storing any dynamic obstacles we add (more about those later).

Now we want an AI to walk around. It will be a very simple AI, it will basically walk forward. So first add a new Cylinder to the scene (GameObject -> Create Other -> Cylinder). It will create a cylinder with a height of 2 units somewhere in the scene, place it somewhere visible above the ground plane we added before. Add to this GameObject the component RVOController, you can find it at Components -> Local Avoidance -> RVO Controller. This component is designed to be an almost drop-in replacement for the Unity Character Controller, so if you have used the character controller, you will feel at home with this one. It does not, for obvious reasons support some collision specific things, like collision flags but it is very similar. Since our cylinder is 2 units high, set the height variable on the RVOController to 2.

Now that we have our AI standing on the ground, we want to tell it to do something: so fire up your favorite text editor and create a script called SimpleRVOAI.cs. This is what it should contain:

using UnityEngine;
using System.Collections;
using Pathfinding.RVO;

[HelpURL("https://arongranberg.com/astar/documentation/beta/class_simple_r_v_o_a_i.php")]
public class SimpleRVOAI : MonoBehaviour {
RVOController controller;

// Use this for initialization
void Awake () {
controller = GetComponent<RVOController>();
}

// Update is called once per frame
public void Update () {
// Just some point far away
var targetPoint = transform.position + transform.forward * 100;

// Set the desired point to move towards using a desired speed of 10 and a max speed of 12
controller.SetTarget(targetPoint, 10, 12, new Vector3(float.NaN, float.NaN, float.NaN));

// Calculate how much to move during this frame
// This information is based on movement commands from earlier frames
// as local avoidance is calculated globally at regular intervals by the RVOSimulator component
var delta = controller.CalculateMovementDelta(transform.position, Time.deltaTime);
transform.position = transform.position + delta;
}
}

What the code does is that it gets the RVOController during Awake and every frame it sets the point that we want it to move to to a point far away in the forwards direction. It tells the local avoidance system that it wants to move with a speed of 10 units per second but if necessary it can move with a speed of 12 units per second. If you add this script to your cylinder and press play, it should move forward at a steady speed.

Note that the RVOController does not handle movement by itself. Some games might want to use a CharacterController as well, some might want to use transform.Translate and some might want to use a Rigidbody, so it is up to the movement script to actually move the character based on the velocity that the RVOController calculates.

Version

Prior to version 4.0 the RVOController did handle movement by itself and worked much like Unitys CharacterController. However this turned out to be a design mistake as there would often be 2 components that wanted to handle movement (both the movement script such as AIPath and the RVOController) and this often lead to confusion.

Now for the fun part. Duplicate the cylinder and place it some distance in front of the first one, then rotate it so that they are facing each other. Press play. The cylinders should move towards each other, and just before collision, avoid each other! Ain't that awesome!