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

快速按键致近战攻击动画冻结的替代解决方案

Godot KinematicBody2D 攻击动画冻结问题及解决方法

我参考某视频写了一段Godot脚本,实现KinematicBody2D角色的移动与近战攻击功能,但发现一个坑:快速同时按下攻击和移动按键时,有时isAttacking变量在Slash动画结束后没法重置为false,直接导致角色动画冻结。排查后发现是快速按键时的动画逻辑冲突,这里把解决方法分享出来,帮大家避坑。

原问题脚本

extends KinematicBody2D

var movement=Vector2(); 
var up= Vector2(0, -1); 
var speed=200;
var isAttacking=false; 

func _process(delta): 
    if Input.is_action_pressed("ui_right") && isAttacking == false:
        movement.x = speed;
        $AnimatedSprite.play("walk"); 
    elif Input.is_action_pressed("ui_left") && isAttacking == false: 
        movement.x= -speed;
        $AnimatedSprite.play("Walk"); 
    else: 
        movement.x = 0; 
        if isAttacking == false: 
            $AnimatedSprite.play("Idle"); 
    
    if Input.is_action_just_pressed("Attack"):
        $AnimatedSprite.play("Slash");
        isAttacking=true; 
    movement = move_and_slide(movement, up * delta); 
    
func _on_AnimatedSprite_animation_finished():
    if $AnimatedSprite.animation == "Slash": 
        isAttacking= false; 

问题根源

快速同时按攻击和移动键时,_process里的移动分支会在攻击动画刚播放时,立刻调用play("walk")覆盖Slash动画,导致Slash动画被中断,animation_finished信号根本不会触发,isAttacking就一直保持true,角色自然卡住在攻击状态。

解决方法

核心就是保证攻击动画播放期间,不会被移动/Idle动画打断,修改后的脚本如下:

extends KinematicBody2D

var movement = Vector2()
var up = Vector2(0, -1)
var speed = 200
var isAttacking = false

func _process(delta):
    # 攻击状态下完全跳过移动动画的切换逻辑
    if not isAttacking:
        if Input.is_action_pressed("ui_right"):
            movement.x = speed
            $AnimatedSprite.play("walk")
        elif Input.is_action_pressed("ui_left"):
            movement.x = -speed
            $AnimatedSprite.play("Walk")
        else:
            movement.x = 0
            $AnimatedSprite.play("Idle")
    
    # 只有不在攻击状态时,才响应攻击按键,避免重复触发打断动画
    if Input.is_action_just_pressed("Attack") and not isAttacking:
        $AnimatedSprite.play("Slash")
        isAttacking = true
    
    movement = move_and_slide(movement, up * delta)

func _on_AnimatedSprite_animation_finished():
    if $AnimatedSprite.animation == "Slash":
        isAttacking = false
        # 攻击结束后自动恢复到对应状态,过渡更自然
        if movement.x != 0:
            $AnimatedSprite.play("walk" if movement.x > 0 else "Walk")
        else:
            $AnimatedSprite.play("Idle")

修改说明

  1. 把移动、Idle的动画逻辑全部放在not isAttacking判断里,攻击时绝不切换动画,确保Slash动画能完整播放,触发animation_finished信号重置isAttacking。
  2. 攻击按键增加not isAttacking判断,防止快速按键重复触发攻击,打断正在播放的Slash动画。
  3. 攻击动画结束后,自动根据当前移动状态切换回Walk或Idle,不用等玩家再按一次移动键,体验更流畅。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 08:21:35