【问题标题】:Godot jump animation starting after a slight delay from the inputGodot 跳转动画在输入稍有延迟后开始
【发布时间】:2021-08-19 00:38:59
【问题描述】:

这是我的第一个项目之一,我正在按照 YT 上的教程编写此代码。据我所知,本教程不包括有关动画的内容,因此我尝试自己完成它并且空闲和运行动画工作。跳跃也有效,但它在稍微延迟后开始并且没有完成它的循环,因为角色着陆太快(对于最后一个问题,我会尝试调整动画的速度)

扩展演员

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 

【问题讨论】:

    标签: 2d-games godot


    【解决方案1】:

    我看到很多小东西,会一一回顾。


    在地板上吗?

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

    这本身没什么大不了的。 帧完美跳转最明显,但仍然。


    Lerp?

    我正在看这条线:

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

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

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

    所以我们从new_velocity.x 插值到0,权重为0.1。我认为这与以下内容相同:

    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。 Sprite 有一个 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")
    

    又短又甜。

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


    还有一件事

    鉴于您正在使用 2D 中的精灵。考虑为精灵动画使用AnimatedSprite 而不是AnimationPlayer

    顺便说一下,动画的时间安排可能会导致明显的延迟。例如,如果跳跃动画的第一个精灵匹配 - 比如说 - 空闲动画的帧。这是在我们看到跳跃精灵之前必须经过的一整帧。仔细检查。

    【讨论】:

    • 谢谢!我需要花很多时间来消化和理解你写的所有东西,但我真的很高兴你决定向一个新手解释这么多!我希望我能从你的解释中尽可能多地理解,并学习编写更干净、更高效的代码。
    • 好吧@Theraot,我理解和改变我的代码所遇到的大部分问题的时间比预期的要少(当我开始研究它时不到半小时)。我唯一不明白的是在 move_and_slide( . . . ) 部分之前的 is_on_floor( ) 部分。我只是把velocity = calculate_move_velocity(velocity, direction, maxSpeed) 放在velocity = move_and_slide(velocity, FLOOR_NORMAL) 之后,这是我应该做的吗?
    • @BlindVI is_on_floor 的值在move_and_slide 中更新。在move_and_slide 之前使用is_on_floor 可以为您提供先前物理框架的值。如果您每秒有 60 个物理帧(这是默认设置,请参阅项目设置),跳跃响应可能会延迟 0.016 秒,此时值 is_on_floor 应该已更改但没有更改(即当玩家想要跳跃与化身降落相同的物理框架)。诚然,这很难注意到,但对于严格的控制很重要。连续跳跃时偶尔会出现“我按下它,它没有跳跃”的问题。
    • @BlindVI 当然,我们可以做得更好,包括输入缓冲和 cayote 时间等等。但是,仅仅改变这些指令的顺序太容易了。
    • 哦,呃..我不知道输入缓冲和cayote时间是什么,哈哈
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 2021-10-17
    • 1970-01-01
    相关资源
    最近更新 更多