Unity3d NavMeshAgent.isOnNavMesh становится ложным в определенной функции - PullRequest
2 голосов
/ 13 июня 2019

Я изменил название, чтобы отразить добавление уточняющей информации.

Я следую [Учебному пособию по Unity] [1], и когда пришло время тестировать элементы управления игроками, Unity выдала мне ошибку:

«SetDestination» может быть вызван только для активного агента, который был помещен в NavMesh.

Насколько я могу судить, мой агент активен и находится в navMesh, так что это немного сбивает с толку. Я попытался повторно выполнить navMesh и изменить положение агента, ни один из которых не работал.

Все вопросы, которые я нашел до сих пор, сводились к тому, что у спрашивающего вообще не было navMesh, так что ... да ... не очень полезно. Любые предложения о том, как решить эту проблему, пока приветствуются.

EDIT: Я просто добавил быстрый Debug.Log(agent.isOnNavMesh); к своему коду и низкий & вот он оценивается в true. Пик путаница.

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

        inputHoldWait = new WaitForSeconds(inputHoldDelay);

        destinationPosition = transform.position;
    }

РЕД-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;
}

РЕД-3 Я положил Debug.Log(agent.isOnNavMesh); в private void Update(), он оценивается в true и продолжает делать это даже после того, как Щелчок вызывает public void OnGroundClick.

Отключение и включение агента в начале OnGroundClick не влияет на ситуацию

Хотя я все еще в растерянности, я, по крайней мере, ближе к решению, и есть больше информации, чем «это не работает, пожалуйста, помогите!» сейчас.

Вот код в полном контексте:

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

1 Ответ

0 голосов
/ 13 июня 2019

У вас есть два экземпляра компонента PlayerMovement, ссылающихся на два разных экземпляра агента!

Один экземпляр agent.isOnNavMesh равен true и работает правильно в Start и Update.Другой экземпляр относится к другому agent, где agent.isOnNavMesh равно false, но это тот, чей OnGroundclick вызывается.

Мы можем сказать, потому что GetInstanceID() возвращает разные значения в Update vs. OnGroundClick.

Решение здесь состоит в том, чтобы убедиться, что OnGroundClick, зарегистрированный в системе событий, соответствует правильному экземпляру PlayerMovement!

...