You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中Rigidbody.MovePosition()行为异常问题排查

第三人称移动异常问题解决方案

问题现象

将以下代码挂载到勾选「Is Kinematic」选项的Rigidbody组件角色上时,出现角色长时间无移动响应,之后随机向前跳跃一段距离,再次按下W键重复该现象。此前使用transform.Translate可正常移动,但存在角色穿透地面问题。

原代码:

using UnityEngine;

public class ThirdPersonMovement : MonoBehaviour
{
    Rigidbody rb;
    private Animator animator;

    public float speed = 5f;
    void Start() {
        animator = GetComponent<Animator>();
        rb = GetComponent<Rigidbody>();
    }
    // Update is called once per frame
    void Update()
    {
        //Get player input based on world space.
        float playerHorizontalInput = Input.GetAxisRaw("Horizontal");
        float playerVerticalInput = Input.GetAxisRaw("Vertical");

        //Get camera-normalized directional vectors
        Vector3 forward = Camera.main.transform.forward;
        Vector3 right = Camera.main.transform.right;

        //Create direction-relative input vectors
        Vector3 forwardRelativeVerticalInput = playerVerticalInput * forward;
        Vector3 rightRelativeHorizontalInput = playerHorizontalInput * right;


        Vector3 cameraRelativeMovement = forwardRelativeVerticalInput + rightRelativeHorizontalInput;

        Vector3 movement = cameraRelativeMovement * speed * Time.deltaTime;
        rb.MovePosition(transform.position + movement);


        transform.forward = cameraRelativeMovement;


        if (cameraRelativeMovement != Vector3.zero)
        {
            animator.SetBool("IsMoving", true);
        }
        else {
            animator.SetBool("IsMoving", false);
        }
    }
}

解决方案

1. 切换物理更新时机

Rigidbody相关操作必须放在FixedUpdate中执行,Update的帧间隔不稳定,会导致物理计算和输入不同步,引发延迟、跳跃等异常。

2. 清除相机向量的Y轴分量

相机的forward和right向量默认包含Y轴信息,会导致角色移动时出现上下偏移,需将Y轴置0并归一化,保证移动仅在水平平面进行。

3. 优化移动状态判断

直接通过输入的平方和判断是否有移动输入,避免Vector3.zero精确比较带来的误差(浮点运算存在精度问题)。

修改后的代码:

using UnityEngine;

public class ThirdPersonMovement : MonoBehaviour
{
    Rigidbody rb;
    private Animator animator;

    public float speed = 5f;
    
    void Start() 
    {
        animator = GetComponent<Animator>();
        rb = GetComponent<Rigidbody>();
    }

    // 物理更新函数,固定时间步执行
    void FixedUpdate()
    {
        float playerHorizontalInput = Input.GetAxisRaw("Horizontal");
        float playerVerticalInput = Input.GetAxisRaw("Vertical");

        // 提取相机水平方向向量,清除Y轴分量并归一化
        Vector3 cameraForward = new Vector3(Camera.main.transform.forward.x, 0f, Camera.main.transform.forward.z).normalized;
        Vector3 cameraRight = new Vector3(Camera.main.transform.right.x, 0f, Camera.main.transform.right.z).normalized;

        // 计算相机相对的移动方向
        Vector3 cameraRelativeMovement = cameraForward * playerVerticalInput + cameraRight * playerHorizontalInput;
        
        // 仅当有输入时才更新朝向
        if (cameraRelativeMovement.magnitude > 0.1f)
        {
            transform.forward = cameraRelativeMovement.normalized;
            animator.SetBool("IsMoving", true);
        }
        else
        {
            animator.SetBool("IsMoving", false);
        }

        // 计算移动位移并应用到刚体
        Vector3 movement = cameraRelativeMovement.normalized * speed * Time.fixedDeltaTime;
        rb.MovePosition(rb.position + movement);
    }
}

额外说明

  • 保持Rigidbody的「Is Kinematic」勾选,此模式下刚体不会受物理力影响,适合通过代码控制移动,同时能触发碰撞检测,避免穿透地面问题。
  • 使用Time.fixedDeltaTime替代Time.deltaTime,因为FixedUpdate的执行间隔是固定的,对应物理时间步。

内容的提问来源于stack exchange,提问作者hiling99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 01:41:02