Unity蹲伏静止转移动动画无法切换问题求助
问题分析与解决方案
问题现象
- 蹲伏静止状态下,
idleCrouch动画正常触发; - 蹲伏状态下开始移动时,无法切换至
isCrouchWalk动画; - 先行走再按C键进入蹲伏,
CrouchWalk动画可正常触发,仅从蹲伏静止转移动时卡在idleCrouch动画。
代码问题定位
核心问题出在Movement函数的条件判断顺序:
当处于蹲伏状态且移动时,direction.magnitude > 0.1f会先触发第一个普通行走分支,设置WalkForward为true,后续的蹲伏移动判断(else if (isCrouching && direction.magnitude >0.1f))永远不会被执行。同时,状态切换时未及时重置对立的动画布尔值,导致动画状态冲突。
另外,Crouching函数中按下C键时直接强制设置isCrouchWalk为true的逻辑不合理,应该根据当前是否移动动态调整。
修正后的代码
void Movement() { isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask); if (isGrounded && velocity.y < 0) { velocity.y = -2f; } float horizontal = Input.GetAxisRaw("Horizontal"); float vertical = Input.GetAxisRaw("Vertical"); Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized; velocity.y += gravity * Time.deltaTime; if (Input.GetButtonDown("Jump") && isGrounded) { animator.SetTrigger("isJumping"); velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity); } if (WeaponHolster.selectedWep == 0 || WeaponHolster.selectedWep == 1 || WeaponHolster.selectedWep == 2) { // 优先处理蹲伏状态逻辑 if (isCrouching) { if (direction.magnitude > 0.1f) { // 蹲伏移动:重置行走动画,启用蹲走动画 animator.SetBool("WalkForward", false); animator.SetBool("isCrouchWalk", true); animator.SetBool("IsIdleCrouch", false); // 执行蹲伏移动逻辑(可替换为专属蹲伏移动速度) float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y; float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime); transform.rotation = Quaternion.Euler(0f, angle, 0f); Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward; controller.Move(moveDir.normalized * moveSpeed * Time.deltaTime); } else { // 蹲伏静止:重置蹲走动画,启用蹲伏 idle animator.SetBool("isCrouchWalk", false); animator.SetBool("IsIdleCrouch", true); animator.SetBool("WalkForward", false); } } else { // 非蹲伏状态逻辑 if (direction.magnitude > 0.1f) { animator.SetBool("WalkForward", true); animator.SetBool("isCrouchWalk", false); animator.SetBool("IsIdleCrouch", false); float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y; float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime); transform.rotation = Quaternion.Euler(0f, angle, 0f); Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward; controller.Move(moveDir.normalized * moveSpeed * Time.deltaTime); } else { animator.SetBool("WalkForward", false); animator.SetBool("isCrouchWalk", false); animator.SetBool("IsIdleCrouch", false); } } } controller.Move(velocity * Time.deltaTime); } void Crouching() { if (Input.GetKeyDown(KeyCode.C) && !ShotgunEngine.isReloading) { isCrouching = true; aiming.m_Offset = new Vector3(0.4f, 0f, 1); // 进入蹲伏时根据当前移动状态设置对应动画 float horizontal = Input.GetAxisRaw("Horizontal"); float vertical = Input.GetAxisRaw("Vertical"); Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized; if (direction.magnitude > 0.1f) { animator.SetBool("isCrouchWalk", true); animator.SetBool("WalkForward", false); animator.SetBool("IsIdleCrouch", false); } else { animator.SetBool("IsIdleCrouch", true); animator.SetBool("WalkForward", false); animator.SetBool("isCrouchWalk", false); } } if (Input.GetKeyUp(KeyCode.C)) { isCrouching = false; aiming.m_Offset = new Vector3(0.4f, 0.2f, 0); // 退出蹲伏时重置所有蹲伏相关动画 animator.SetBool("isCrouchWalk", false); animator.SetBool("IsIdleCrouch", false); } }
关键修正点
- 调整判断优先级:先判断蹲伏状态,避免蹲伏移动逻辑被普通行走逻辑覆盖;
- 状态切换全量重置:每次切换动画时,关闭所有对立状态的布尔值,防止动画状态冲突;
- 优化蹲伏触发逻辑:进入蹲伏时根据当前是否移动动态设置动画,而非强制启用蹲走动画;
- 分离状态逻辑:将蹲伏与非蹲伏的移动、动画逻辑完全分离,避免相互干扰。
内容的提问来源于stack exchange,提问作者Ron Ron
相关产品推荐
相关产品推荐

