【问题标题】:Godot jumping animation just plays the first frameGodot 跳跃动画只播放第一帧
【发布时间】:2019-02-09 00:04:17
【问题描述】:

我的简单平台游戏中有一个脚本,它说如果我的玩家在地面上并且按下“Z”,他在 Y 轴上的移动将上升到 600,如果他不在地面上,他将执行跳跃动画。

所以事情是这样的,我知道它只播放跳跃动画的第一帧,因为代码不断检测玩家在空中。 我想要一种方法告诉代码只触发一次动画。

我尝试使用一个名为input_(event): 的函数,但它似乎没有is_action_just_pressed 类型的输入,只有is_action_pressed

我对 Godot 还很陌生,不知道如何使用信号。信号可能会通过 animation_finished() 提供帮助,尽管该功能可能与我在代码中实际想要做的事情无关。

这是我的代码:

extends KinematicBody2D
#Variables van aquí 

var movimiento = Vector2();
var gravedad = 20; 
var arriba = Vector2(0, -1);
var velocidadMax = 600;
var fuerza_salto = -600;
var aceleracion = 5;
var saltando = false;
func _ready(): # Esto es void Start()
    pass;

func _physics_process(delta): #Esto es void Update() 

    movimiento.y += gravedad;


    if Input.is_action_pressed("ui_right"):
        $SonicSprite.flip_h = true;
        $SonicSprite.play("Walk");
        movimiento.x = min(movimiento.x +aceleracion, velocidadMax);


    elif Input.is_action_pressed("ui_left"):
        $SonicSprite.flip_h = false;
        $SonicSprite.play("Walk");
        movimiento.x = max(movimiento.x-aceleracion, -velocidadMax);

    else:
        movimiento.x = lerp(movimiento.x, 0, 0.09);
        $SonicSprite.play("Idle");


    if is_on_floor():
        if Input.is_action_just_pressed("z"):
            movimiento.y = fuerza_salto;
    else:
        $SonicSprite.play("Jump");

    movimiento = move_and_slide(movimiento, arriba)

【问题讨论】:

  • 欢迎来到 stackoverflow Jorge。您能否添加is_on_floor() 函数的代码。我认为问题出在那儿。

标签: animation godot gdscript


【解决方案1】:

我遇到了 smae 问题,我在 move_and_slide() 之后添加下一个问题解决了:

if velocity.y == 0:
    velocity.y = 10

显然,如果在 move_and_slide() 之后速度为 0,它不再检测 is_on_floor()(错误?)所以我在重力方向添加了小速度。

关于使用input_(event),你不需要just_pressed,因为它只在有输入时处理..你可以这样做:

func _input(event):
    if event.is_action_pressed("ui_up") and is_on_floor():
        velocity.y = jump_speed

我所说的速度,我认为在你的脚本中叫做movimiento。另外,我认为您在movimiento中混合了重力和速度。我正在与您分享我的角色脚本,以便您进行比较,看看它是否效果更好:

extends KinematicBody2D

var Bullet = preload("res://Bullet.tscn")

var speed = 200
var jump_speed = -300
var shot_speed = 100
var velocity = Vector2()
var grav = 980
var shooting = false

func _ready():
    $AnimatedSprite.play()
    $AnimatedSprite.connect("animation_finished",self,"on_animation_finished")
func _input(event):
    if event.is_action_pressed("ui_up") and is_on_floor():
        velocity.y = jump_speed
    if event.is_action_pressed("shoot") and !shooting:
        shooting = true
        shot_speed = 20
        velocity.y = -200
        fire_weapon()

func _physics_process(delta):
    velocity.x = 0
    if Input.is_action_pressed("ui_right"):
        velocity.x += speed
    if Input.is_action_pressed("ui_left"):
        velocity.x -= speed
    if velocity.length() > 0:
        if velocity.x < 0:
            $AnimatedSprite.flip_v = true
            $AnimatedSprite.rotation_degrees = 180 
        elif velocity.x > 0:
            $AnimatedSprite.flip_v = false
            $AnimatedSprite.rotation_degrees = 0 
    if shooting:
        $AnimatedSprite.animation = "shot"
        velocity.x = -shot_speed * cos($AnimatedSprite.rotation_degrees)
        shot_speed *= 0.98
    else:
        if is_on_floor():
            if velocity.x == 0:
                $AnimatedSprite.animation = "idle"
            else:
                $AnimatedSprite.animation = "moving"
        else:
            $AnimatedSprite.animation = "jumping"

    velocity.y += grav * delta
    velocity = move_and_slide(velocity, Vector2(0,-1))
    if velocity.y == 0:
        velocity.y = 10

func on_animation_finished():
    if $AnimatedSprite.animation == "shot":
        shooting = false

func fire_weapon():
    var bullet = Bullet.instance()
    get_parent().add_child(bullet)
    if $AnimatedSprite.flip_v :
        bullet.position = $ShotLeft.global_position
    else:
        bullet.position = $ShotRight.global_position
    bullet.rotation_degrees = $AnimatedSprite.rotation_degrees
    bullet.linear_velocity = Vector2(1500 * cos(bullet.rotation),1500*sin(bullet.rotation))

请注意,我不使用重力作为速度或电影;而是将它乘以 delta 以获得速度,因为加速度 x 时间给出速度。

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    可以使用Finite State Machine 来管理您的角色控制和行为来解决此类问题。您将在从步行状态进入跳跃状态时播放跳跃动画。尽早使用正确的设计模式可以防止将来出现意大利面条式代码。

    这不是 Godot 特定的解决方案,但绝对值得您关注。

    【讨论】:

      【解决方案3】:

      让我们剖析这里发生的事情,您启动代码并要求您的播放器在一帧中播放动画,然后在另一帧和下一帧中再次播放动画,只要按下正确的键或您处于正确的状态。

      问题是什么,问题在于每次调用函数 play 时都会一次又一次地触发动画,因此它只是重新启动或另一个调用单独运行,这会导致意外行为。

      更好的方法是同时管理播放器和动画播放器的状态,并使用它来执行动画调用。

      enum State { IDLE, WALK, RUN, JUMP, INAIR, GROUNDED } ## This is to manage the player state
      var my_state = State.IDLE  ## Start the player with the idle state
      

      至于动画播放器状态,请使用您所说的信号,使用 GUI 或使用如下代码。

      get_node("Animation Player").connect("animation_finished", this, "method_name")
      ## Here I assume that you have the Animation Player as the Child of the Node you the script on
      

      并且还保存一个布尔变量来判断动画是否正在播放。

      if ( animation_not_playing and (case)):
          animation_player.play("animation")
      

      根据您的喜好将其变为真或假。基于动画完成信号。

      将来,您甚至可能会考虑使用简单的 FSM 来维护所有这些状态数据和变量。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-20
        相关资源
        最近更新 更多