这里以'史莱姆撞击'为例子,将'空中跃进'定义为伤害帧。(见下图)
先梳理流程:a.史莱姆原地蓄力(起跳准备)--->b.跳起并移动一段距离(空中跃进)--->c.落地调整
一 当状态机进入'攻击状态'时,在enter()中设置起跳速度,并播放'a动画'。a动画播放期间,do()函数什么也不做。
二 a动画结束后,do()函数中开始执行move_and_slide()。
b动画不要用play()播放,而是手动控制动画帧:
在上升过程中,设置动画为"空中跃进-第1帧"
在下降过程中,设置动画为"空中跃进-第2帧"
三 当史莱姆落回地板时(is_on_floor),播放c动画,不再执行move_and_slide()。
c动画结束后,退出攻击状态,转到移动/待机状态
python
#== gdScript
#== 攻击状态
var is_jump = 0 # 是否处于空中跳跃阶段
var to_end = 0 # 是否处于落地调整阶段
func enter():
print("进入攻击状态")
# 设置起跳速度
chara.velocity.x = $"../Run".direct.x*40
chara.velocity.y=-300
$"../../AnimatedSprite2D".play("攻击准备")
func do():
# 空中移动过程
if is_jump==1:
chara.velocity.y+=chara.gravity*0.01
chara.move_and_slide()
## 可以在这里判断是否触碰到玩家并造成伤害
# 空中移动动画
if chara.velocity.y>=0&&to_end==0:
$"../../AnimatedSprite2D".frame=1 # 下降期间动画
# 落地
if chara.is_on_floor()&&to_end==0&&is_jump==1:
is_jump=0 # 不再移动位置
to_end=1 # 该if块只执行一次
$"../../AnimatedSprite2D".play("攻击结束")
func exit():
to_end=0 # 记得重置变量
func _on_animated_sprite_2d_animation_finished():
# 若开启了"动画循环",则不会触发finished信号
if $"../../AnimatedSprite2D".animation=="攻击准备":
is_jump=1 # 开始移动
$"../../AnimatedSprite2D".animation="攻击过程"
$"../../AnimatedSprite2D".frame=0 # 上升期间动画
if $"../../AnimatedSprite2D".animation=="攻击结束":
get_parent().change_state($"../Run") # 转移到移动状态
关键是对攻击进一步细分