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);
}
}`