This problem happens when the Player goes inside and outside of the Enemy's sightRadius multiple times.
Here is the bug code.
bool FoundPlayer()
{
int numColliders = Physics.OverlapSphereNonAlloc(transform.position, sightRadius, colliders);
Debug.Log(numColliders);
for (int i = 0; i < numColliders; i++)
{
var target = colliders[i];
if (target.CompareTag("Player"))
{
attackTarget = target.gameObject;
return true;
}
}
attackTarget = null;
return false;
}
And here are the setting of the Player with the Collider, Rigidbody, Layer and tag.
When the Player is inside of the Enemy's sightRadius, 3 is printed.
When the Player is outside of the Enemy's sightRadius, 2 is printed.
After I control the Player to go inside and outside of the sightRadius several times, when the Player is inside of the sightRadius, 2
instead of 3 is printed, and the Enemy doesn't chase the Player anymore. If I restart the game, it works well again.
This problem happens both in Unity 2020 and 2022.
My code used OverlapSphereNonAlloc, but I met the same problem, trying to use both OverlapSphereNonAlloc and OverlapSphere.
Here is the full code of the Enemy.
using UnityEngine;
using UnityEngine.AI;
enum EnemyStatus
{
GURAD,
PATROL,
CHASE, DEAD
}
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(BoxCollider))]
public class EnemyController : MonoBehaviour
{
private EnemyStatus enemyStates;
private NavMeshAgent agent;
private Animator animator;
[Header("Basic Settings")]
public float sightRadius;
private GameObject attackTarget;
// enermy will find 10 max players at one frame
const int maxColliders = 10;
private Collider[] colliders = new Collider[maxColliders];
// speed set in agent.speed, but patrol, chase and return from chase have different speed
private float speed;
// is GUARD or PATROL when no enemy
public bool isGuard;
[Header("Patrol State")]
public float patrolRange;
private Vector3 wayPoint;
private Vector3 centerPosition;
// animator
bool isWalk;
// entry of Chase Layer
bool isChase;
//
bool isFollow;
private void Awake()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
speed = agent.speed;
wayPoint = centerPosition = transform.position;
}
private void Start()
{
if (isGuard)
{
enemyStates = EnemyStatus.GURAD;
}
else
{
enemyStates = EnemyStatus.PATROL;
}
}
private void Update()
{
SwitchStates();
SwitchAnimation();
}
void SwitchAnimation()
{
animator.SetBool("Walk", isWalk);
animator.SetBool("ChaseState", isChase);
animator.SetBool("Follow", isFollow);
}
private void SwitchStates()
{
if (FoundPlayer())
{
enemyStates = EnemyStatus.CHASE;
}
switch(enemyStates)
{
case EnemyStatus.GURAD:
break;
case EnemyStatus.PATROL:
// this is error, when enemy reach wayPoint, it will stop walking
// isWalk = true;
isChase = false;
isFollow = false;
if (Vector3.Distance(transform.position, wayPoint) <= agent.stoppingDistance )
{
wayPoint = GetNewWayPoint();
agent.destination = wayPoint;
agent.speed = speed * 0.5f;
isWalk = false;
}
else
{
isWalk = true;
}
break;
case EnemyStatus.CHASE:
//TODO: back to gurad or patrol if player far away
//TODO: attack player
//TODO: attack animator
isWalk = false;
isChase = true;
if (FoundPlayer())
{
//TODO: chase player
agent.destination = attackTarget.transform.position;
agent.speed = speed;
isFollow = true;
}
else
{
isFollow = false;
// stop at the current when lost target
agent.destination = transform.position;
}
break;
case EnemyStatus.DEAD:
break;
}
}
bool FoundPlayer()
{
int numColliders = Physics.OverlapSphereNonAlloc(transform.position, sightRadius, colliders);
Debug.Log(numColliders);
for (int i = 0; i < numColliders; i++)
{
var target = colliders[i];
if (target.CompareTag("Player"))
{
attackTarget = target.gameObject;
return true;
}
}
attackTarget = null;
return false;
}
Vector3 GetNewWayPoint ()
{
Vector3 wayPoint = new Vector3(centerPosition.x + Random.Range(-patrolRange, patrolRange), centerPosition.y, centerPosition.z + Random.Range(-patrolRange, patrolRange));
NavMeshHit hit;
// sample the nearnet reachable point for enemy to go.
// if can not find any point, SamplePosition will retturn false and enemy will stand there for next sample next frame.
wayPoint = NavMesh.SamplePosition(wayPoint, out hit, patrolRange, 1) ? hit.position : transform.position;
return wayPoint;
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, sightRadius);
Vector3 size = new Vector3(patrolRange, patrolRange, patrolRange);
Gizmos.DrawWireCube(centerPosition, size);
}
}
I have tried a different API and a different version of Unity.
I found out that enabling the Use gravity on the Rigidbody component causes this problem, but I don't know how it happens. The Player stands on the plane and the transform.position, but the position in the info of the Rigidbody component keeps decreasing.
Here is the configuration of Plane.





