Problem: Local Avoidance with terrain height differences


Hi again,
I’m having problem with Local Avoidance and height differences. I’m using my own custom AI for movement and moving code is copied from Local Avoidance docs:

controller.SetTarget(path.vectorPath [currentWaypoint], speed, speed+2);
Vector3 delta = controller.CalculateMovementDelta(transform.position, Time.deltaTime);
transform.position = transform.position + delta;

However, using that gives weird results with heights. Agents ignore hills and just go thru them, but some will remain floating in air and rotating horizontally (because path waypoint is below them and they cant reach it):

Without CalculateMovementDelta and using normal path-following heights work just fine. Here is example of working code:

Quaternion targetRotation = Quaternion.LookRotation (path.vectorPath [currentWaypoint] - transform.position);
transform.rotation = Quaternion.Lerp (transform.rotation, targetRotation, Time.deltaTime * turnSpeed);
transform.Translate (Vector3.forward * Time.deltaTime * speed, Space.Self);
transform.position += transform.forward * speed * Time.deltaTime;

Edit: I’m using version 4.0.11



The local avoidance system ignores velocities along the y coordinate (up direction) completely. I recommend that you get the XZ velocity from the local avoidance system and handle the y coordinate separately. This is what the included movement scripts (e.g AIPath) does. The local avoidance system introduces a small amount of delay into everything (since the rvo simulation is not done immediately, but instead together for all agents at the same time) and making the Y coordinate go through this pipeline as well could potentially introduce a small amount of velocity jitter which might look bad. This is why this is not done.

var delta = controller.CalculateMovementDelta(...);
// Very crude y coordinate handling, you probably want to do some raycasts as well
delta.y = (path.vectorPath[currentWaypoint] - transform.position).normalized.y * speed;


Thanks for your quick response and the tip. I didn’t notice that avoidance did not handle y-axis.

Here is my quick’n’dirty implementation with raycasting if someone finds this thread from Google and needs somewhat ready solution:

controller.SetTarget(path.vectorPath [currentWaypoint], speed, speed+2);
Vector3 delta = controller.CalculateMovementDelta(transform.position, Time.deltaTime);

Vector3 groundLevel =;
RaycastHit hit;

if (Physics.Raycast (transform.position+(Vector3.up), Vector3.down, out hit)) {                
  if (hit.transform != transform) {
    groundLevel = hit.point;
transform.position = transform.position + delta;
transform.position = new Vector3 (transform.position.x, groundLevel.y, transform.position.z);