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.isOnNavMesh
是 true
并且在 Start
和 Update
中正常工作。另一个实例引用了不同的 agent
,其中 agent.isOnNavMesh
是 false
,但这是 OnGroundclick
被调用的实例。
我们可以判断,因为 GetInstanceID()
returns Update
与 OnGroundClick
中的不同值。
此处的解决方案是确保在事件系统中注册的 OnGroundClick
是 PlayerMovement
!
的正确实例中的那个
我更改了标题以反映添加的澄清信息。
我正在学习 [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.isOnNavMesh
是 true
并且在 Start
和 Update
中正常工作。另一个实例引用了不同的 agent
,其中 agent.isOnNavMesh
是 false
,但这是 OnGroundclick
被调用的实例。
我们可以判断,因为 GetInstanceID()
returns Update
与 OnGroundClick
中的不同值。
此处的解决方案是确保在事件系统中注册的 OnGroundClick
是 PlayerMovement
!