Unity - 如何使用 NavMeshAgent 跳转并点击移动逻辑

Unity - How to jump using a NavMeshAgent and click to move logic

我正在构建一个可以使用鼠标输入控制玩家的游戏,通过导航网格代理使用点击移动逻辑。

为了让玩家跳跃,我也开始使用CharacterController,它应该有助于管理玩家。我的问题是我无法弄清楚将跳转逻辑放在哪里。我找到的所有参考资料都与使用不带导航网格代理的角色控制器相关。

如果需要,我可以去掉 CharacterController,但 NavMeshAgent 必须保留。

这是一个允许行走的工作代码。你能帮我解决跳跃逻辑吗?

  private NavMeshAgent _agent;
  private CharacterController _characterController;
  private Vector3 _desVelocity;

  private void Update()
  {
     if (Input.GetMouseButtonDown(0))
     {
         Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
         if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo))
         {
             _agent.destination = hitInfo.point;
         }
     }
     var currMovementDirection = _desVelocity.normalized * currentSpeed;
     if (_agent.remainingDistance > _agent.stoppingDistance)
     {
         _desVelocity = _agent.desiredVelocity;
         _characterController.Move(currMovementDirection * Time.deltaTime);
     }
 }

跳转逻辑应该在Update()方法中,因为我们希望每一帧都计算高度。

void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo))
        {
            _agent.destination = hitInfo.point;
        }
    }
    var currMovementDirection = _desVelocity.normalized * currentSpeed;

    groundedPlayer = _characterController.isGrounded;
    if (groundedPlayer && currMovementDirection.y < 0)
    {
        currMovementDirection.y = 0f;
    }



    // Changes the height position of the player..
    if (Input.GetButtonDown("Jump") && groundedPlayer)
    {
        currMovementDirection.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
    }

    currMovementDirection.y += gravityValue * Time.deltaTime;
    if (_agent.remainingDistance > _agent.stoppingDistance)
    {
        _desVelocity = _agent.desiredVelocity;
        _characterController.Move(currMovementDirection * Time.deltaTime);
    }
}

请看官方文档here

您可以使用 Rigidbody 而不是 CharacterController 来实现此目的。诀窍是你需要禁用 NavMeshAgent 才能跳转。

您可以选择将目的地设置为跳跃时您所在的位置,以便代理在跳跃发生时不会继续模拟。

使用碰撞检测,您在着陆后再次打开 NavMeshAgent

public class PlayerMovement : MonoBehaviour
{

    private Camera cam;
    private NavMeshAgent agent;
    private Rigidbody rigidbody;
    public bool grounded = true;

    void Start()
    {
        cam = Camera.main;
        agent = GetComponent<NavMeshAgent>();
        rigidbody = GetComponent<Rigidbody>();
    }

    void Update()
    {
        // clicking on the nav mesh, sets the destination of the agent and off he goes
        if (Input.GetMouseButtonDown(0) && (!agent.isStopped))
        {
            Ray ray = cam.ScreenPointToRay(Input.mousePosition);
            if (Physics.Raycast(ray, out RaycastHit hit))
            {
                agent.SetDestination(hit.point);
            }
        }

        // when you want to jump
        if (Input.GetKeyDown(KeyCode.Space) && grounded)
        {
            grounded = false;
            if (agent.enabled)
            {
                // set the agents target to where you are before the jump
                // this stops her before she jumps. Alternatively, you could
                // cache this value, and set it again once the jump is complete
                // to continue the original move
                agent.SetDestination(transform.position);
                // disable the agent
                agent.updatePosition = false;
                agent.updateRotation = false;
                agent.isStopped = true;
            }
            // make the jump
            rigidbody.isKinematic = false;
            rigidbody.useGravity = true;
            rigidbody.AddRelativeForce(new Vector3(0, 5f, 0), ForceMode.Impulse);
        }
    }

    /// <summary>
    /// Check for collision back to the ground, and re-enable the NavMeshAgent
    /// </summary>
    private void OnCollisionEnter(Collision collision)
    {
        if (collision.collider != null && collision.collider.tag == "Ground")
        {
            if (!grounded)
            {
                if (agent.enabled)
                {
                    agent.updatePosition = true;
                    agent.updateRotation = true;
                    agent.isStopped = false;
                }
                rigidbody.isKinematic = true;
                rigidbody.useGravity = false;
                grounded = true;
            }
        }
    }
}