Godot跳跃动画只播放第一帧

时间:2018-09-04 02:39:03

标签: animation godot gdscript

我在一个简单的平台游戏中有一个脚本,其中说如果我的玩家在地面上并且按下“ 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)

3 个答案:

答案 0 :(得分:2)

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

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

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

关于usinginput_(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))

请注意,我不使用重力作为速度或电影方向;取而代之的是y乘以delta以获得速度,因为加速度x时间给出速度。

我希望这会有所帮助。

答案 1 :(得分:0)

可以使用Finite State Machine来解决角色控制和行为的问题。从“行走”状态进入“跳跃”状态时,将播放“跳跃”动画。尽早使用正确的设计模式可以防止将来出现意粉代码。

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

答案 2 :(得分:0)

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

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

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

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")

根据自己的喜好将其设置为true或false。基于动画完成信号。

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