0 votes

I have this script that is working fine, except for the attack animation which I believe is being overridden by the idle or running animations. The attack animation is only showing the first frame every time I press Ctrl and then goes to idle or run animations. Any tips on how to fix this?

extends KinematicBody2D

onready var ground_ray = get_node("ground_ray")
onready var ground_ray2 = get_node("ground_ray2")
onready var anim = get_node("AnimationPlayer")

const UP = Vector2(0, -1)
const GRAVITY = 10
const ACCELERATION = 50
const MAX_SPEED = 180
const JUMP_HEIGHT = -380

var motion = Vector2()
var acc = Vector2()

func _physics_process(delta):
    motion.y += GRAVITY
    var friction = false

    acc.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))

    if acc.x == 1:
        $Sprite.flip_h = false
        motion.x = min(motion.x+ACCELERATION, MAX_SPEED)
        if anim.current_animation != "run" && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
            anim.play("run")        
    elif acc.x == -1:
        $Sprite.flip_h = true
        motion.x = max(motion.x-ACCELERATION, -MAX_SPEED)
        if anim.current_animation != "run" && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
            anim.play("run")
    else:
        if anim.current_animation != "idle" && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
            anim.play("idle")
        friction = true


    if Input.is_action_just_pressed("ui_up") && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
        motion.y = JUMP_HEIGHT

    if (ground_ray.is_colliding() || ground_ray2.is_colliding()):
        if friction == true:
            motion.x = lerp(motion.x, 0, 0.2)   
        if Input.is_action_just_pressed("ui_ctrl"):
            if anim.current_animation != "combo 1":
                anim.play("combo 1")
    else:
        if motion.y <= JUMP_HEIGHT*0.45:
            if anim.current_animation != "jump":
                anim.play("jump")
        if motion.y >= 0:
            motion.y += 8
        if motion.y >= JUMP_HEIGHT*0.45 && motion.y <= JUMP_HEIGHT*(-0.45): 
            if anim.current_animation != "maxHeight":
                anim.play("maxHeight")
        if motion.y > JUMP_HEIGHT*(-0.45):
            if anim.current_animation != "fall":
                anim.play("fall")
        if friction == true:
            motion.x = lerp(motion.x, 0, 0.2)
    motion = move_and_slide(motion, UP)
in Engine by (187 points)

I think the problem is that after you attacked, the next time you enter physics process you will met other cases and another animation will start. For example, you press control, so play attack animation, but in next physics process call process call, idle conditions met, so idle is run.

Another thing, Have you tried changing all this:

if Input.is_action_just_pressed("ui_ctrl"):
        if anim.current_animation != "combo 1":
            anim.play("combo 1")

for this:

 if Input.is_action_just_pressed("ui_ctrl"):
     anim.current_animation = "combo 1"

You can set animations like that so you don't have to check if animation is already being played.

For your problem, i think you should ad abool variable like is_attacking which you set to true when start the attack animation, and set to false when finish. If is attacking, then don't try to change animation.

Hi. I set the flag attack and changed the if statements, the combo animation works now, but can be stopped at any time. Do you know how I can prevent "combo 1" animation from being interrupted? Any Animation Player command? Thank you for your response.

Can you share me the project so i see in depth? I would use tha atack flag to prevent any other animations to be loaded, and connect animation finished signal to a function that, if the animation finished was the attack, then se attack flag to false.

Here are the last changes. The combo 1 animation is playing almost well, the only problem is that if I press Ctrl again it restart the combo 1 animation.

extends KinematicBody2D

onready var ground_ray = get_node("ground_ray")
onready var ground_ray2 = get_node("ground_ray2")
onready var anim = get_node("AnimationPlayer")

const UP = Vector2(0, -1)
const GRAVITY = 10
const ACCELERATION = 50
const MAX_SPEED = 180
const JUMP_HEIGHT = -380

var motion = Vector2()
var acc = Vector2()

var attack = false

func _physics_process(delta):
    motion.y += GRAVITY
    var friction = false

    acc.x = int(Input.is_action_pressed("ui_right")) - int(Input.is_action_pressed("ui_left"))

    if acc.x == 1 && !attack:
        $Sprite.flip_h = false
        motion.x = min(motion.x+ACCELERATION, MAX_SPEED)
        if anim.current_animation != "run" && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
            anim.play("run")        
    elif acc.x == -1 && !attack:
        $Sprite.flip_h = true
        motion.x = max(motion.x-ACCELERATION, -MAX_SPEED)
        if anim.current_animation != "run" && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
            anim.play("run")
    else:
        if anim.current_animation != "idle" && !attack && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
            anim.play("idle")
        friction = true


    if Input.is_action_just_pressed("ui_up") && anim.current_animation != "combo 1" && (ground_ray.is_colliding() || ground_ray2.is_colliding()):
        motion.y = JUMP_HEIGHT

    if (ground_ray.is_colliding() || ground_ray2.is_colliding()):
        if friction == true:
            motion.x = lerp(motion.x, 0, 0.2)   
        if Input.is_action_just_pressed("ui_ctrl"):
            attack = true
            anim.play("combo 1")
            yield(anim, "animation_finished")
            attack = false
    else:
        if motion.y <= JUMP_HEIGHT*0.45:
            if anim.current_animation != "jump":
                anim.play("jump")
        if motion.y >= 0:
            motion.y += 8
        if motion.y >= JUMP_HEIGHT*0.45 && motion.y <= JUMP_HEIGHT*(-0.45): 
            if anim.current_animation != "maxHeight":
                anim.play("maxHeight")
        if motion.y > JUMP_HEIGHT*(-0.45):
            if anim.current_animation != "fall":
                anim.play("fall")
        if friction == true:
            motion.x = lerp(motion.x, 0, 0.2)
    motion = move_and_slide(motion, UP)

hi:
Change anim.play("combo 1") by `anim.current_animation = "combo 1". Have you tried that?
If not you can check current animation as you did before.

This worked very well. Do you think yield works as good as signal to notified about finished animation? Thanks again man.

if Input.is_action_just_pressed("ui_ctrl"):
    attack = true
    anim.current_animation = "combo 1"
    yield(anim, "animation_finished")
    attack = false

I think in this case yield is better! We should post an answer so this does not remain unsolved, and then you should select it. Would you do it, so you can add the finished version of the code? Or you prefer me to do so?

You can make it. Thanks.

hey, i think that if you use yield, you don't need attack flag anymore.. can you please test it?

I test it, and without attack flag we comeback to the first issue, the combo 1 animation just plays the first frame and the idle or run animation overrides it. I just don't understand why it overrides if I am using the anim.current_animation = "combo 1" to avoid it.

1 Answer

+1 vote
Best answer

Hi,
This was solved in comments, but here is a summary of what we got working.

  • anim.pay("combo 1") was changed to anim.current_animation = "combo 1" so the animation didn't restart when pressed Ctrl repeatedly.

  • yield was used when the attack animation started, so that no other actions can be done while character is attacking.

For further info, se comments above.

by (3,505 points)
selected by
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.