My animated sprite plays just the first frame

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By owlisGODOT

I’m following a tutorial and I want to add a feature myself where you can slash the enemy. So far I’m working on the animation (called “Attack 1”), though I have a problem.
It only plays the first frame, then just switches to the idle animation. For some reason the other animations work fine, so I don’t understand what’s wrong. How do I get it to play the rest of the animation???
(for reference here’s the player script)

extends KinematicBody2D
const FLOOR = Vector2(0, -1) 
const GRAVITY = 30         
const JUMP_HEIGHT = -800
const SPEED = 300
const FIREBALL = preload("res://fireball.tscn")
var vel = Vector2()
var ground = false
func _physics_process(delta):
    if Input.is_action_pressed("ui_left"):
	   vel.x = -SPEED
	   $AnimatedSprite.play("Run")
	   $AnimatedSprite.flip_h = true
	    if sign($Position2D.position.x) == 1:
		  $Position2D.position.x *= -1 
    elif Input.is_action_pressed("ui_right"):
	    vel.x = SPEED 
	    $AnimatedSprite.play("Run")
	    $AnimatedSprite.flip_h = false
	    if sign($Position2D.position.x) == -1:
		  $Position2D.position.x *= -1
    else:
	   vel.x = 0
	if ground == true:
	   $AnimatedSprite.play("Idle")
    if Input.is_action_pressed("ui_up"):
	if ground == true:
		vel.y = JUMP_HEIGHT
		ground = false
               vel.y += GRAVITY
	
        if Input.is_action_just_pressed("shoot"):
	  var fireball = FIREBALL.instance()
	  if sign($Position2D.position.x) == 1:
		fireball.set_pos(1)
	else:
		fireball.set_pos(-1)
	get_parent().add_child(fireball)
	fireball.position = $Position2D.global_position
    if Input.is_action_just_pressed("slash"):
	    $AnimatedSprite.play("Attack 1") # <---- Bug
    else:
	    $AnimatedSprite.play("Idle")

 
    if is_on_floor():
	   ground = true
    else:
	    ground = false
	if vel.y < 0:
		$AnimatedSprite.play("Jump")
	else:
		$AnimatedSprite.play("Fall")
	 
   vel = move_and_slide(vel, FLOOR)

(I apologize for the improper indentation, it was hard to manually indent everything X( )

To properly paste code in the forum.

  1. copy properly formatted code from your text editor
  2. paste it into the forum message
  3. select it
  4. Press the {} button in the forum message toolbar

That’ll indent everything properly for forum display…

jgodfrey | 2020-06-09 15:50

:bust_in_silhouette: Reply From: jgodfrey

The immediate problem I see is that your Attack 1 animation is being triggered by Input.is_action_just_pressed, which is only true in the single frame where the action button was pressed. So, in that one frame, it’ll start to play the animation, but in the very next frame, that call will return false. Based on your code, that next frame would process the code in the else block, which causes the Idle animation to play again.

The most obvious thing to do is simply remove the else: block all together. By the looks of it, you’ll already play the idle animation if you’re grounded (higher in your code), so that might work for you.

That said, your input processing code is likely much more complex (and redundant) than necessary, which makes working this out more difficult than necessary…

The code was complex because I was following a tutorial… I’ve already fixed it, but I hope this answer can help others.

owlisGODOT | 2020-06-11 11:35

:bust_in_silhouette: Reply From: BrunoFreezee

it’s hard to handle too many if/elses, you should avoid them, they generates lots of bugs

I’ve made a simple code, I didn’t check if it’s working but you can try out this way, there’s some tips that can help you improve your codes

extends KinematicBody2D

const gravity = 50
var vel = Vector2.ZERO
var speed = 200
var jump_force = 500
enum {move, attack}

var state = move

func _physics_process(delta):
	vel.y += gravity * delta
	
	match state:
		move:
			move()
		attack:
			attack()
	
	vel = move_and_slide(vel, Vector2.UP)
	
func move():
	var direction = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left") #gives positive or negative 1
	if direction != 0:
		$animation.play("run")
		$animation.flip_h = direction < 0 #flip accordingly the direction
		vel.x = direction * speed
		
	if is_on_floor(): ###### --------------- insted ground var
		if !direction:
			$animation.play("idle")
			vel.x = 0
	else:
		pass #jump things
			
func attack():
	pass #attack code / $animation.play("atttack")

Hope this helps you, Good luck