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

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);
    }
}

关键修正点

  1. 调整判断优先级:先判断蹲伏状态,避免蹲伏移动逻辑被普通行走逻辑覆盖;
  2. 状态切换全量重置:每次切换动画时,关闭所有对立状态的布尔值,防止动画状态冲突;
  3. 优化蹲伏触发逻辑:进入蹲伏时根据当前是否移动动态设置动画,而非强制启用蹲走动画;
  4. 分离状态逻辑:将蹲伏与非蹲伏的移动、动画逻辑完全分离,避免相互干扰。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 09:06:09