Godot跳跃动画从输入稍微延迟后开始



这是我的第一个项目之一,我是按照YT教程编写这段代码的。据我所见,这个教程不包括关于动画的内容,所以我试着自己完成它,并让空闲和运行的动画工作。跳跃也可以,但它在稍微延迟后开始,并且由于角色过早着陆而没有完成循环(对于最后一个问题,我将尝试调整动画的速度(

扩展Actor

func _physics_process(delta):
var direction = get_direction()
velocity = calculate_move_velocity(velocity, direction, maxSpeed)
velocity = move_and_slide(velocity, FLOOR_NORMAL) #Funzione che permette il movimento del personaggio
func get_direction() -> Vector2:
return Vector2(
Input.get_action_strength("right") - Input.get_action_strength("left"),
-1.0 if Input.is_action_just_pressed("jump") and is_on_floor() else 0.0
)
func calculate_move_velocity(               #Movimento e Animazioni
linear_velocity: Vector2,
direction: Vector2,
maxSpeed: Vector2
) -> Vector2:
var new_velocity = linear_velocity      #la new_velocity sarà il movimento lineare del personaggio
new_velocity.x = maxSpeed.x * direction.x
new_velocity.x = lerp(new_velocity.x, 0, 0.1)
if is_on_floor() and direction.x == 1.0:                  #muoversi verso destra
$AnimationPlayer.play("run")
$Sprite.scale.x = 1
elif is_on_floor() and direction.x == -1.0:               #muoversi verso sinistra
$AnimationPlayer.play("run")
$Sprite.scale.x = -1
if is_on_floor() and direction.x == 0.0:                  #stare fermi
$AnimationPlayer.play("idle")
new_velocity.y += gravity * get_physics_process_delta_time()
if direction.y == -1.0:                 #saltare
new_velocity.y = maxSpeed.y * direction.y
if !is_on_floor() == false and Input.is_action_just_pressed("jump"):
$AnimationPlayer.play("jump")
return new_velocity 

我看到了很多小事情,会一一回顾。


在地板上吗

当您调用move_and_slide(...)时,值is_on_floor()会更新。但是在调用move_and_slide(...)之前调用is_on_floor(),这意味着它正在操作先前物理帧的值。事实上,你希望move_and_slide(...)撞击地面(因此,你可能想先施加重力(。

这本身并不是什么大事<最引人注目的是完美跳跃,但仍然如此>


勒普

我在看这行:

new_velocity.x = lerp(new_velocity.x, 0, 0.1)

让我们看看lerp的官方文档。上面说lerp的签名是:

Variant lerp ( Variant from, Variant to, float weight )

因此,我们用0.1的权重从new_velocity.x插值到0。我相信这与相同

new_velocity.x *= 0.9

考虑到另一条线路:

new_velocity.x = maxSpeed.x * direction.x
new_velocity.x = lerp(new_velocity.x, 0, 0.1)

我们有:

new_velocity.x = maxSpeed.x * direction.x * 0.9

考虑到direction.x-11,我们得出new_velocity.x从未达到maxSpeed.x

你为什么要这么做?你认为你正在完成什么


缩放精灵

使用$Sprite.scale.x = 1$Sprite.scale.x = -1。强烈鼓励使用精灵的flip_h属性。


双重阴性

您有一个小小的代码块:!is_on_floor() == false

让我们制作一个真相表:

is_on_floor() │ !is_on_floor() │ !is_on_floor() == false
──────────────┼────────────────┼──────────────────────────
false        │ true           │ false
true         │ false          │ true

如您所见,!is_on_floor() == falseis_on_floor()相同顺便说一下,它返回bool,而不是Variant,以防您担心


多次播放动画

您必须知道,使用同一动画多次调用AnimationPlayer.play是完全没有问题的。这也意味着你不需要检查跳跃动作是否只是按下了。


关注点分离

一方面,我们关心的是运动物体的运动。另一方面,我们关心的是播放动画。第一个问题是物理问题。在_physics_process中这样做是有意义的。第二个问题是视觉问题。改为在_process中执行此操作是有意义的。


将所有这些结合在一起

func _physics_process(delta:float) -> void:
velocity.y += gravity * delta
velocity = move_and_slide(velocity, Vector2.UP)
var h_direction = Input.get_action_strength("right") - Input.get_action_strength("left")
velocity.x = maxSpeed.x * h_direction
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = -maxSpeed.y
func _process(_delta:float) -> void:
if is_on_floor():
if velocity.x == 0.0:
$AnimationPlayer.play("idle")
$Sprite.flip_h = false
else:
$AnimationPlayer.play("run")
$Sprite.flip_h = velocity.x < 0.0
else:
$AnimationPlayer.play("jump")

又短又甜

注意:我用Vector2.UP替换了FLOOR_NORMAL。我还去掉了lerp引入的0.9。否则,这应该是相同的,减去is_on_floor和动画播放时间问题(我认为这在墙上也不同,如果这是一个问题,就有is_on_wall()(。然而,我们谈论的问题最多只能扩展一个物理框架。


还有一件事

假设您使用的是2D中的精灵。考虑对精灵动画使用AnimatedSprite而不是AnimationPlayer

顺便说一句,动画的时间可能是造成明显延迟的原因。例如,如果跳跃动画的第一个精灵与空闲动画的一帧相匹配。这是在我们看到跳跃精灵之前必须经过的一整帧。仔细检查一下。

最新更新