Local Avoidance and clipping through walls

Is there anything special I need to do to stop my seekers from clipping into walls when I try to implement local avoidance? I’m not sure what I’m doing wrong. When I have a moderate number of entities trying to get through a small space, some of them seem to exit the graph area and just clip into the walls. I’ve tried setting the wall avoid force to something pretty high, and it doesn’t have much effect (not that I’m too sure what it’s meant to do, the documentation is pretty weak in some areas).

One or two entities seem to work ok, but if I deliberately clog up a choke point, they will just clip into walls. Only on occasions, most of the time they seem to behave, which if anything makes it more frustrating.

I’m using a seeker, the RVO controller and a custom movement script.

`using UnityEngine;
using System.Collections;
using Pathfinding;

[RequireComponent(typeof(Seeker))]
[RequireComponent(typeof(RVOController))]
public class AIMovementController : MonoBehaviour {
public float repathRate = 0.5f;
public Vector3 lastTargetPosition;
public bool canMove;
public bool canSearch;
public float nextWaypointDistance = 0.5f;
public bool useGameDeltaTime = true;

public Vector3? target;

private bool isFindingPath;
private Seeker seeker;
private float rateCooldown;
private RVOController characterController;

private Path path;
private int pathIndex;
public float speed { get { return characterController.maxSpeed; } }

// Use this for initialization
void Start () {
    seeker = GetComponent<Seeker>();
    characterController = GetComponent<RVOController>();
}

void FindPath()
{
    if (target.HasValue)
    {
        isFindingPath = true;
        lastTargetPosition = target.Value;
        seeker.StartPath(transform.position, target.Value, OnPathComplete);
    }
}

void OnPathComplete(Path p)
{
    isFindingPath = false;

    if (!p.error)
    {
        path = p;
        pathIndex = 0;
    }
}

// Update is called once per frame
void Update () {
    if (rateCooldown > 0)
    {
        rateCooldown -= Time.deltaTime;
        if (rateCooldown < 0) rateCooldown = 0;
    }

    if (canSearch && !isFindingPath && rateCooldown <= 0)
    {
        rateCooldown = repathRate;
        FindPath();
    }

    if (canMove)
    {
        Move();
    }
    else //we have to stop
    {
        if (!characterController.locked) 
            characterController.locked = true;
    }
}

public void Repath()
{
    ClearPath();
}

void ClearPath()
{
    path = null;
    pathIndex = 0;
}

void Move()
{
    if (path == null)
    {
        //We have no path to move after yet
        return;
    }

    if (pathIndex >= path.vectorPath.Count)
    {
        Debug.Log("End Of Path Reached");
        ClearPath();
        target = null;
        return;
    }

    //Direction to the next waypoint
    var dir = (path.vectorPath[pathIndex] - transform.position).normalized;
    dir = (useGameDeltaTime && GameManager.gameDeltaTime == 0 ? Vector3.zero : dir);
    characterController.locked = false;
    characterController.Move(dir);

    //Check if we are close enough to the next waypoint
    //If we are, proceed to follow the next waypoint
    if (Vector3.Distance(transform.position, path.vectorPath[pathIndex]) < nextWaypointDistance)
    {
        pathIndex++;
        return;
    }
}

}
`

Here is a snippet of the AI Controller
`
private Seeker seeker;
private AIMovementController mover;

void Act()
{
    if (currAttackCooldown > 0) currAttackCooldown -= GameManager.gameDeltaTime;
    if (currAttackCooldown < 0) currAttackCooldown = 0;

    if (canSeePlayer)
    {
        if (!inAttackRange)
        {
            //move towards player
            Move(lastPlayerLocation.Value);
        }
        else
        {   //Attack
            transform.LookAt(lastPlayerLocation.Value);
            Stop();
            Attack();
        }
    }
    else
    {
        if (lastPlayerLocation != null)
        {
            //move towards last known location
            Move(lastPlayerLocation.Value);
        }
    }
}

void Attack()
{
    if (currAttackCooldown <= 0)
    {
        currAttackCooldown = attackCooldown;
        var projectile = GameObject.Instantiate(enemyProjectilePrefab) as Projectile;
        projectile.transform.position = projectileSpawnPoint.position;
        projectile.transform.eulerAngles = projectileSpawnPoint.eulerAngles;
        projectile.source = gameObject;
    }
}

void Stop()
{
    mover.canMove = false;
    mover.canSearch = false;
}

void Move(Vector3 target)
{
    mover.target = lastPlayerLocation.Value;
    mover.canMove = true;
    mover.canSearch = true;

    var t = transform;
    t.LookAt(lastPlayerLocation.Value);
    var moveDelta = t.forward * mover.speed * GameManager.gameDeltaTime;
    var distanceToTarget = (t.position - lastPlayerLocation.Value).magnitude;

    if (moveDelta.magnitude > distanceToTarget)
    {
        Stop();

        t.position = lastPlayerLocation.Value;
        lastPlayerLocation = null;
        //look at the player just in case we can still see them
        t.LookAt(player.transform.position);

    }        
}`

Also, if I don’t lock the RVOController when I want to stop the entity from moving, it will just head off on whatever vector it was previously set on, and completely ignore the boundaries of my graph.

I know there is a sticky that says I might need to wait a little for support, but other queries have been answered :confused:

Is there anything special I need to do to stop my seekers from clipping into walls when I try to implement local avoidance?
Yes! And it depends the type of Graph you are using for your path-finding.

Local avoidance and path-finding are two separate things. For agents to avoid unwalkable area, you need to create RVO Obstacles, this is what RVONavmesh makes automatically in the RVO sample (Example11_RVO).

If you are using using a GridGraph, this feature is currently unsupported, but you can use my own implementation here:

Perfect :slight_smile: Thanks