Unity 2D俯视角学生游戏攻击动画仅1帧即切回Idle问题求助
解决Unity 2D俯视角游戏攻击动画仅播放1帧的问题
嘿,我来帮你搞定这个攻击动画的问题!你的代码逻辑里有个关键小漏洞,导致攻击动画刚播放一帧就被切回Idle了,我来给你拆解清楚,再给你修复方案。
问题根源
你的Update()方法每帧都会执行一次完整的判断逻辑:
- 当你按下
Fire1的那一瞬间,代码进入攻击分支,播放Attack动画; - 但到了下一帧,
CrossPlatformInputManager.GetButtonDown("Fire1")就不成立了(因为GetButtonDown只在按下的第一帧返回true),代码直接跳到else分支,把动画切回Idle,这就导致Attack动画只播了一帧就被打断。
修复方案
核心思路是:用一个状态变量标记当前是否正在攻击,在攻击动画播放的全过程中,跳过移动和Idle的状态判断,直到攻击动画完全播放完毕。
步骤1:添加攻击状态标记
在你的脚本类里添加一个私有布尔变量,用来记录当前是否处于攻击状态:
private bool isAttacking = false;
步骤2:调整Update方法的逻辑优先级
把攻击相关的判断放在最前面,并且在攻击状态生效时跳过其他逻辑:
void Update () { // 如果正在攻击,直接跳过后续所有逻辑,避免打断动画 if (isAttacking) { return; } Move(); float lastInputX = CrossPlatformInputManager.GetAxis("Horizontal"); float lastInputY = CrossPlatformInputManager.GetAxis("Vertical"); // 优先处理攻击输入:只有不在攻击状态时才能触发新的攻击 if (CrossPlatformInputManager.GetButtonDown("Fire1")) { isAttacking = true; anim.SetBool("Attacking", true); anim.Play("Attack"); return; // 触发攻击后,直接结束当前帧的逻辑,不处理移动/Idle } // 处理移动/Idle逻辑 if (lastInputX != 0 || lastInputY != 0) { anim.SetBool("Walking", true); anim.SetFloat("LastMoveX", lastInputX); anim.SetFloat("LastMoveY", lastInputY); anim.Play("Walk"); } else { anim.SetBool("Walking", false); anim.Play("Idle"); } float inputX = CrossPlatformInputManager.GetAxis("Horizontal"); float inputY = CrossPlatformInputManager.GetAxis("Vertical"); anim.SetFloat("SpeedX", inputX); anim.SetFloat("SpeedY", inputY); }
步骤3:动画结束后重置攻击状态
这里推荐用Unity动画事件来同步动画结束的时机,比用协程等待时长更可靠:
- 在脚本里添加一个公开的回调方法:
// 这个方法会在攻击动画播放完毕时被调用 public void OnAttackAnimationFinished() { isAttacking = false; anim.SetBool("Attacking", false); }
- 打开Unity的Animation窗口,选中你的Attack动画,在动画的最后一帧右键选择「Add Event」;
- 在Inspector面板的动画事件设置里,把这个
OnAttackAnimationFinished方法拖到函数选择框里,这样动画播放到最后一帧时就会自动调用这个方法,重置攻击状态。
备选方案:用协程等待动画时长
如果你不想用动画事件,也可以用协程来实现,不过要注意动画时长要和实际播放时长匹配:
IEnumerator AttackCoroutine() { isAttacking = true; anim.SetBool("Attacking", true); anim.Play("Attack"); // 获取当前Attack动画的时长,等待播放完毕 yield return new WaitForSeconds(anim.GetCurrentAnimatorStateInfo(0).length); isAttacking = false; anim.SetBool("Attacking", false); }
然后在触发攻击的地方替换成:
if (CrossPlatformInputManager.GetButtonDown("Fire1")) { StartCoroutine(AttackCoroutine()); return; }
额外提示
- 记得在Animator Controller里,确保Attack状态和Idle/Walk状态的过渡条件设置正确,避免动画被意外打断;
- 测试的时候可以打开Animator窗口的Debug模式,实时查看当前的动画状态,方便排查问题。
内容的提问来源于stack exchange,提问作者TobiasNorum
相关产品推荐
相关产品推荐

