Unity3d NavMeshAgent.isOnNavMesh在特定函数中变为false

Unity3d NavMeshAgent.isOnNavMesh becomes false in specific function

我更改了标题以反映添加的澄清信息。

我正在学习 [Unity 教程][1],当需要测试播放器点击控件时,Unity 给我一个错误:

"SetDestination" 只能在已放置在 NavMesh 上的活动代理上调用。

据我所知,我的代理处于活动状态并且在导航网格上,所以这有点令人困惑。我试过重新烘焙 navMesh 并重新定位代理,但均无效。

到目前为止,我发现的所有问题都相当于提问者根本没有导航网格,所以……是的……不是很有帮助。任何有关如何解决此问题的建议都将不胜感激。

编辑: 我刚刚在我的代码中快速添加了一个 Debug.Log(agent.isOnNavMesh); & low & 看它的计算结果为 true。偷看混乱。

private void Start()
    {
        Debug.Log(agent.isOnNavMesh);       //Evaluates *true*
        agent.updateRotation = false;

        inputHoldWait = new WaitForSeconds(inputHoldDelay);

        destinationPosition = transform.position;
    }

EDIT-2 将相同的 Debug.Log(agent.isOnNavMesh); 放入我的 public void OnGroundClick fxn & 它在点击后计算为 false。开始感兴趣的混乱。

这是由 Unity 事件系统调用的:

public void OnGroundClick(BaseEventData data)
{
    Debug.Log(agent.isOnNavMesh);       //Evaluates *FALSE*
    PointerEventData pData = (PointerEventData)data;
    NavMeshHit hit;

        //Click World Position, hit info, sample distance, navMesh areas to use
    if (NavMesh.SamplePosition(pData.pointerCurrentRaycast.worldPosition, out hit, navMeshSampleDistance, NavMesh.AllAreas))
    {
        destinationPosition = hit.position;
    }
    else
    {
        destinationPosition = pData.pointerCurrentRaycast.worldPosition;
    }

    //give the agent it's destination
    agent.SetDestination(destinationPosition);
    agent.isStopped = false;
}

EDIT-3 我将 Debug.Log(agent.isOnNavMesh); 放入 private void Update(),它的计算结果为 true,并且即使在点击调用 public void OnGroundClick.

后仍继续这样做

OnGroundClick 开始时禁用然后启用代理不会影响这种情况

虽然我仍然不知所措,但我至少离解决方案更近了,而且现在的信息比 "this doesn't work, please help!" 多。

这是完整上下文中的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.AI;

public class PlayerMovement : MonoBehaviour
{
    public Animator animator;                               //Reference to animator
    public NavMeshAgent agent;                              //Reference to NavMeshAgent
    public float inputHoldDelay = 0.5f;                     //Delay player ability to control character while interacting with interactable object
    public float turnSpeedThreshold = 0.5f;                 //minimum speed before character will turn
    public float speedDampTime = 0.1f;                      //Character rate acceleration
    public float slowingSpeed = 0.175f;                     //Character rate of neg accel
    public float turnSmoothing = 15;                        //Character rotational speed


    private WaitForSeconds inputHoldWait;                   //Coroutine Wait timer to delay player input while interacting with interactable object
    private Vector3 destinationPosition;                    //Player designated destination for the agent to pursue


    private const float stopDistanceProportion = 0.1f;
    private const float navMeshSampleDistance = 4f;


    private readonly int hashSpeedParam = Animator.StringToHash("Speed");


    private void Start()
    {
        Debug.Log(agent.gameObject.name);   //Is the "Player" object
        Debug.Log(agent.isOnNavMesh);       //Evaluates *true*
        agent.updateRotation = false;

        inputHoldWait = new WaitForSeconds(inputHoldDelay);

        destinationPosition = transform.position;
    }


    private void OnAnimatorMove()
    {
        //Velocity = Distance over Time, where Distance = change in position between frames & Time = time between frames
        agent.velocity = animator.deltaPosition / Time.deltaTime;
    }


    private void Update()
    {
        Debug.Log(agent.isOnNavMesh);       //Evaluates *true*
        //If path pending, do nothing
        if (agent.pathPending)
            return;

        float speed = agent.desiredVelocity.magnitude;

        if (agent.remainingDistance <= agent.stoppingDistance * stopDistanceProportion)
        {
            Stopping(out speed);
        }
        else if (agent.remainingDistance <= agent.stoppingDistance)
        {
            Slowing(agent.remainingDistance, out speed);
        }
        else if(speed > turnSpeedThreshold)
        {
            Moving();
        }

        animator.SetFloat(hashSpeedParam, speed, speedDampTime, Time.deltaTime);
    }


    private void Stopping(out float speed)
    {
        agent.isStopped = true;
        transform.position = destinationPosition;
        speed = 0.0f;
    }


    private void Slowing(float distanceToDestination, out float speed)
    {
        agent.isStopped = true;
        transform.position = Vector3.MoveTowards(transform.position, destinationPosition, slowingSpeed * Time.deltaTime);

        float proportionalDistance = 1f - distanceToDestination / agent.stoppingDistance;
        speed = Mathf.Lerp(slowingSpeed, 0, proportionalDistance);
    }


    private void Moving()
    {
        Quaternion targetRotation = Quaternion.LookRotation(agent.desiredVelocity);
        transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, turnSmoothing * Time.deltaTime);
    }


    public void OnGroundClick(BaseEventData data)
    {
        agent.enabled = false;              //Disabling then enabling the agent...
        agent.enabled = true;               //does not change anything.

        Debug.Log(agent.gameObject.name);   //Is the "Player" object
        Debug.Log(agent.isOnNavMesh);       //Evaluates *FALSE*

        PointerEventData pData = (PointerEventData)data;
        NavMeshHit hit;

            //Click World Position, hit info, sample distance, navMesh areas to use
        if (NavMesh.SamplePosition(pData.pointerCurrentRaycast.worldPosition, out hit, navMeshSampleDistance, NavMesh.AllAreas))
        {
            destinationPosition = hit.position;
        }
        else
        {
            destinationPosition = pData.pointerCurrentRaycast.worldPosition;
        }

        //give the agent it's destination
        agent.SetDestination(destinationPosition);
        agent.isStopped = false;
    }
}

您有两个 PlayerMovement 组件实例引用两个不同的代理实例!

一个实例是 agent.isOnNavMeshtrue 并且在 StartUpdate 中正常工作。另一个实例引用了不同的 agent,其中 agent.isOnNavMeshfalse,但这是 OnGroundclick 被调用的实例。

我们可以判断,因为 GetInstanceID() returns UpdateOnGroundClick 中的不同值。

此处的解决方案是确保在事件系统中注册的 OnGroundClickPlayerMovement!

的正确实例中的那个