The attack animation doesn't finish. Help me!

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

I press the attack key and the animation doesn’t last even 1 second

extends KinematicBody2D

const gravity = 500
const speed = 80
const jump_force = -250

var velocity = Vector2()
var move_direction = 0
var jump = false
var pre_fire = preload(“res://Scenes/Fire.tscn”)

func _physics_process(delta):

if Input.is_action_pressed("ui_right"):
	move_direction = 1
	$AnimatedSprite.flip_h = false
	$AnimatedSprite.play("running")

elif Input.is_action_pressed("ui_left"):
	move_direction = -1
	$AnimatedSprite.flip_h = true
	$AnimatedSprite.play("running")

else:
	move_direction = 0
	$AnimatedSprite.play("idle")

if is_on_floor():
	if Input.is_action_pressed("ui_space"):
		jump = true
	else:
		velocity.y = 0
else:
	$AnimatedSprite.play("jump")

if jump:
	velocity.y = jump_force
	jump = false

velocity.y += gravity * delta
velocity.x = speed * move_direction

if Input.is_action_just_pressed("ui_shoot"):
	var fire = pre_fire.instance()
	fire.global_position = $boca.global_position
	get_parent().add_child(fire)
	$AnimatedSprite.play("atack")

move_and_slide(velocity, Vector2(0, -1))
:bust_in_silhouette: Reply From: SCV-ready

you are overriding the animation with your movements and idle.

do you want to be still in your animations? do you want to cancel them by moving/jumping only?

for the first one you can make a check before each call to animation player as such:

if $AnimationPlayer.current_animation == "atack" and $AnimationPlayer.is_playing():
    pass
else:
    $AnimationPlayer.play("walk")
    #tie your move actions to this condition as well.

this is assuming your shot animation is not looped.

in the case you want to cancel it by moving and jumping, but not idle, you can just add this before the idle animation

if $AnimationPlayer.current_animation == "atack" and $AnimationPlayer.is_playing():
    pass
else:
    $AnimationPlayer.play("idle")
   

I am not using Animation Player, I am using Animated Sprite, and it is not working with Animated Sprite, when I put it gives an error

Snayk | 2019-10-17 20:49

Sorry for misreading.

you have in animated sprite an attribute called “animation” and a method called “is_playing”.
you should be able to replace “current_animation” with the “animation” attribute and try it again.

also, can you post the error given by the engine?

SCV-ready | 2019-10-17 20:55

This is the error Invalid get index ‘current_animation’ (on base: ‘AnimatedSprite’).

Snayk | 2019-10-18 00:44

Where i can find this attribute?

Snayk | 2019-10-18 00:45

so. in the type of programing godot uses you have things called Objects. objects have attributes and methods.

attributes are variables belonging to that object. methods are functions of the object.

when you create AnimatedSprite you create an instance of that object.

to access attributes, you can use $AnimatedSprite.attribute

to access methods you can use $AnimatedSprite.method() for example.

you can see which attributes and method an object has if you go to the documentation page for it. attributes will be at the top and then you will see all the methods available.

the error you got was trying to get an attribute that AnimatedSprite didn’t have.
to solve this you can get its attribute of current animation, “animation” or
$AnimatedSprite.animation

SCV-ready | 2019-10-18 07:19

I put like this:
if $AnimatedSprite.attribute(“atack”) and $AnimatedSprite.method.is_playing():

And gives another error: Invalid call. Nonexistent function ‘attribute’ in base ‘AnimtedSprite’.

Snayk | 2019-10-18 15:25

the right way to use attributes and methods is with their name, without their type before.
methods are only visibly different by having parentheses

for example, in your code it would look like this:

 if $AnimatedSprite.animation == "atack" and $AnimatedSprite.is_playing():

do notice that the is_playing() method returns a true/false value, so no tests are needed on it.

when you have an object in your scene, you can usually get its node and start typing “.” and see what attributes and features it shows you.

SCV-ready | 2019-10-18 15:35

It was like this:

extends KinematicBody2D

const gravity = 500
const speed = 80
const jump_force = -250

var velocity = Vector2()
var move_direction = 0
var jump = false
var pre_fire = preload(“res://Scenes/Fire.tscn”)

func _physics_process(delta):

if Input.is_action_pressed("ui_right"):
	move_direction = 1
	$AnimatedSprite.flip_h = false
	$AnimatedSprite.play("correndo")

elif Input.is_action_pressed("ui_left"):
	move_direction = -1
	$AnimatedSprite.flip_h = true
	$AnimatedSprite.play("correndo")

if $AnimatedSprite.animation == "atacando" and $AnimatedSprite.is_playing():

	pass

else:
	move_direction = 0
	$AnimatedSprite.play("parado")

if is_on_floor():
	if Input.is_action_pressed("ui_space"):
		jump = true
	else:
		velocity.y = 0
else:
	$AnimatedSprite.play("pulando")

if jump:
	velocity.y = jump_force
	jump = false

velocity.y += gravity * delta
velocity.x = speed * move_direction

if Input.is_action_just_pressed("ui_shoot"):
	if get_tree().get_nodes_in_group("fire_balls").size() < 1:
		var fire = pre_fire.instance()
		fire.global_position = $boca.global_position
		get_parent().add_child(fire)
		$AnimatedSprite.play("atacando")

move_and_slide(velocity, Vector2(0, -1))

But now the character doesn’t move and the animation keeps stopping

Snayk | 2019-10-18 16:08

alright. i tested your code. my version of it now works as intended.

first, add a idle frame to the fire animation at the end. lets say that frame’s number is N.
this frame signals that the animation finished. you can just replicate the last frame instead.

now you can use the test:

if $AnimatedSprite.animation == "attack" and $AnimatedSprite.frame != N:
  pass
else:
  move_direction =0 
  $AnimatedSprite.play("idle")

the other thing that caused you being stuck in place is that this if statement needs to be on the end of the movement loop.

so the correct loop would be:

if Input.is_action_pressed("ui_right"):
	move_direction = 1
	$AnimatedSprite.flip_h = false
	$AnimatedSprite.play("running")
elif Input.is_action_pressed("ui_left"):
	move_direction = -1
	$AnimatedSprite.flip_h = true
	$AnimatedSprite.play("running")
else:
	if $AnimatedSprite.animation == "attack" and $AnimatedSprite.frame != N:
		pass
	else:
		move_direction = 0 
		$AnimatedSprite.play("idle")

hope this helps.

SCV-ready | 2019-10-19 10:23

Thank you bro!!!

Snayk | 2019-10-19 20:57