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
相关产品推荐
相关产品推荐

