Physics.OverlapSphere couldn't detect my ‘Player’

49 Views Asked by At

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.

Player

When the Player is inside of the Enemy's sightRadius, 3 is printed.

Player inside

When the Player is outside of the Enemy's sightRadius, 2 is printed.

Player outside

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.

Player inside wrong

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.

Rigidbody

Here is the configuration of Plane.

Plane

0

There are 0 best solutions below