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

Unity 2D铰接火柴人移动动画重复及Idle动画失效问题求助

问题分析
  1. 协程定义位置错误:你把MoveRight和MoveLeft协程写在Update方法内部,每帧都会重新创建协程定义,属于无效写法,还会造成不必要的性能浪费。
  2. 协程重复启动且不受控:按住方向键时,Update每帧都会调用StartCoroutine,导致大量相同协程同时运行。就算松开按键,之前启动的协程仍会持续修改腿部velocity,角色停不下来,Idle动画自然无法正常表现。
  3. 未在停止移动时重置速度:松开方向键后没有主动清空腿部水平速度,协程残留的速度会让角色继续移动,视觉上和Idle动画矛盾。
修复后的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Movement : MonoBehaviour
{
    public GameObject leftLeg;
    public GameObject rightLeg;
    Rigidbody2D leftLegRB;
    Rigidbody2D rightLegRB;

    Animator anim;

    [SerializeField] float speed = 2f;
    [SerializeField] float jumpHeight = 2f;
    [SerializeField] float legWait = .5f;

    // 跟踪当前运行的移动协程,用于启停控制
    private Coroutine currentMoveCoroutine;

    void Start()
    {
        leftLegRB = leftLeg.GetComponent<Rigidbody2D>();
        rightLegRB = rightLeg.GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();
    }

    void Update()
    {
        float horizontalInput = Input.GetAxisRaw("Horizontal");

        if (horizontalInput != 0)
        {
            anim.Play("Run");
            
            // 确保同一时间只有一个移动协程在运行
            if (currentMoveCoroutine == null)
            {
                currentMoveCoroutine = horizontalInput > 0 
                    ? StartCoroutine(MoveRight(legWait)) 
                    : StartCoroutine(MoveLeft(legWait));
            }
        }
        else
        {
            anim.Play("Idle");
            
            // 停止协程并重置水平速度,让角色立刻停下
            if (currentMoveCoroutine != null)
            {
                StopCoroutine(currentMoveCoroutine);
                currentMoveCoroutine = null;
            }
            leftLegRB.velocity = new Vector2(0, leftLegRB.velocity.y);
            rightLegRB.velocity = new Vector2(0, rightLegRB.velocity.y);
        }

        if (Input.GetKeyDown(KeyCode.Space))
        {
            leftLegRB.AddForce(Vector2.up * (jumpHeight * 1000));
            rightLegRB.AddForce(Vector2.up * (jumpHeight * 1000));
        }
    }

    // 协程移至类级别,作为成员方法
    IEnumerator MoveRight(float seconds)
    {
        float endTime = Time.time + seconds;
        Debug.Log("Moved Right");

        while (Time.time < endTime)
        {
            leftLegRB.velocity = new Vector2(speed, leftLegRB.velocity.y);
            rightLegRB.velocity = new Vector2(speed, rightLegRB.velocity.y);
            yield return null;
        }

        currentMoveCoroutine = null;
    }

    IEnumerator MoveLeft(float seconds)
    {
        float endTime = Time.time + seconds;
        Debug.Log("Moved Left");

        while (Time.time < endTime)
        {
            leftLegRB.velocity = new Vector2(-speed, leftLegRB.velocity.y);
            rightLegRB.velocity = new Vector2(-speed, rightLegRB.velocity.y);
            yield return null;
        }

        currentMoveCoroutine = null;
    }
}
关键修改点
  • 协程移至类级别:将MoveRight和MoveLeft从Update内部移出,避免每帧重复定义协程。
  • 协程跟踪机制:用currentMoveCoroutine变量控制协程启停,防止同一时间多个移动协程运行。
  • 停止时重置速度:切换到Idle动画时直接清空腿部水平速度,让角色状态和动画匹配。
  • 简化输入判断:直接复用Input.GetAxisRaw的结果,减少重复调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 18:40:39