Unity 2D铰接火柴人移动动画重复及Idle动画失效问题求助
问题分析
- 协程定义位置错误:你把
MoveRight和MoveLeft协程写在Update方法内部,每帧都会重新创建协程定义,属于无效写法,还会造成不必要的性能浪费。 - 协程重复启动且不受控:按住方向键时,
Update每帧都会调用StartCoroutine,导致大量相同协程同时运行。就算松开按键,之前启动的协程仍会持续修改腿部velocity,角色停不下来,Idle动画自然无法正常表现。 - 未在停止移动时重置速度:松开方向键后没有主动清空腿部水平速度,协程残留的速度会让角色继续移动,视觉上和
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
相关产品推荐
相关产品推荐

