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

Unity3D CharacterController碰撞体不跟随玩家网格移动问题求助

问题原因与解决方案

核心问题原因1:Animator开启了应用根运动

你挂载在玩家网格上的Animator组件默认勾选了Apply Root Motion(应用根运动),此时动画会直接驱动玩家网格的位移,而CharacterController的Move()方法只会移动脚本挂载的父物体,二者位移逻辑分离导致错位。

  • 解决方法:打开玩家网格的Animator组件面板,取消勾选Apply Root Motion即可,关闭后玩家网格作为子物体将完全跟随父物体的位移同步移动。

核心问题原因2:对象层级挂载错误

如果你的角色对象层级不符合Unity CharacterController的标准挂载规则,也会出现同步异常,正确层级如下:

玩家根对象(空对象)
  ├─ 挂载组件:CharacterController、你编写的移动控制脚本
  └─ 玩家网格子对象
      └─ 挂载组件:Animator、Mesh Renderer、Mesh Filter

如果你将CharacterController和移动脚本挂在了网格对象上,或者网格对象与CharacterController所在对象为平级关系,直接调整层级即可解决问题。

可选优化:代码变量命名修正

你代码中float moveY = Input.GetAxis("Horizontal");的变量命名存在歧义,水平输入对应的是X轴位移,建议改为float moveX避免后续维护出错。


异常参考示意图

移动前CharacterController与玩家网格位置:
移动前位置
移动后CharacterController与玩家网格错位:
移动后位置


// 修正变量命名后的移动控制代码参考
// Vars
[SerializeField] private float moveSpeed;
[SerializeField] private float walkSpeed;
[SerializeField] private float runSpeed;

private Vector3 moveDirection;
private Vector3 velocity;

[SerializeField] private bool isGrounded;
[SerializeField] private float groundCheckDistance;
[SerializeField] private LayerMask groundMask;
[SerializeField] private float gravity;

[SerializeField] private float jumpHeight;

// Ref
private CharacterController controller;
private Animator anim;

private void Start()
{
    controller = GetComponent<CharacterController>();
    anim = GetComponentInChildren<Animator>();
}

private void Update()
{
    Move();
    if (Input.GetKeyDown(KeyCode.Mouse0))
    {
        StartCoroutine(Attack());
    }
}

private void Move()
{
    isGrounded = Physics.CheckSphere(transform.position, groundCheckDistance, groundMask);


    if (isGrounded && velocity.y < 0)
    {
        velocity.y = -2f;
    }

    float moveZ = Input.GetAxis("Vertical");
    float moveX = Input.GetAxis("Horizontal");

    moveDirection = new Vector3(moveX, 0, moveZ);
    moveDirection = transform.TransformDirection(moveDirection);


    if (isGrounded)
    {
        if (moveDirection != Vector3.zero && !Input.GetKey(KeyCode.LeftShift))
        {
            Walk();
        }
        else if (moveDirection != Vector3.zero && Input.GetKey(KeyCode.LeftShift))
        {
            Run();
        }
        else if (moveDirection == Vector3.zero)
        {
            Idle();
        }

        moveDirection *= moveSpeed;

        if (Input.GetKeyDown(KeyCode.Space))
        {
            Jump();
        }

    }

    controller.Move(moveDirection * Time.deltaTime);

    velocity.y += gravity * Time.deltaTime;
    controller.Move(velocity * Time.deltaTime);
}

private void Idle()
{
    anim.SetFloat("Speed", 0, 0.1f, Time.deltaTime);

}
private void Walk()
{
    moveSpeed = walkSpeed;
    anim.SetFloat("Speed", 0.5f, 0.1f, Time.deltaTime);

}
private void Run()
{
    moveSpeed = runSpeed;
    anim.SetFloat("Speed", 1f, 0.1f, Time.deltaTime);
}
private void Jump()
{
    velocity.y = Mathf.Sqrt(jumpHeight * -2 * gravity);
}

private IEnumerator Attack()
{
    anim.SetLayerWeight(anim.GetLayerIndex("Attack Layer"), 1);
    anim.SetTrigger("Attack");

    yield return new WaitForSeconds(0.9f);
    anim.SetLayerWeight(anim.GetLayerIndex("Attack Layer"), 0);
}

内容的提问来源于stack exchange,提问作者Mohamed Al-Ryan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 18:57:01