#AnimationPlayer Method Call - Animation Is Looping

1 messages · Page 1 of 1 (latest)

lethal pecan
#

Player script: ```extends CharacterBody2D

const SPEED = 130.0
const JUMP_VELOCITY = -300.0

@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D
var is_alive = true # Variable for the die() funcion.

func _physics_process(delta: float) -> void: # physics_process runs all the time. It will override your animations that are outside of this function.

# Add the gravity.
if not is_on_floor():
    velocity += get_gravity() * delta
    
    # Handle jump.
if Input.is_action_just_pressed("jump") and is_on_floor() and is_alive:
    velocity.y = JUMP_VELOCITY
    
# Get the input direction: -1, 0, 1
var direction = Input.get_axis("move_left", "move_right")

if is_alive: # This condition disables the following on func die().
    
    # Flip the sprite
    if direction > 0:
        animated_sprite.flip_h = false
    elif direction < 0:
        animated_sprite.flip_h = true        

    # Play animations
    if is_on_floor():
        if direction == 0:
            animated_sprite.play("idle")
        else:
            animated_sprite.play("run")
    else:
        animated_sprite.play("jump2")

    # Apply movement
    if direction:
        velocity.x = direction * SPEED
    else:
        velocity.x = move_toward(velocity.x, 0, SPEED)

move_and_slide()

func die():
if not is_alive:
return
is_alive = false # When is_alive is false and stops all other animations.
while not is_on_floor(): # Renables gravity allowing player to fall to ground if they die in air.
move_and_slide()
$AnimationPlayer.play("death") # Make sure to set the frame interval to .1 (10 FPS).
Engine.time_scale = 0.5

func reset_game():
Engine.time_scale = 1.0
get_tree().reload_current_scene()

#

Killzone script:


@onready var timer: Timer = $Timer # @onready is pulling nodes from ATTACHED scene ONLY!



func _on_body_entered(body: Node2D) -> void: # We know this function is for a killzone and not a coin because we added the killzone scene to the enemy. 
    print("You died!")
    #body.get_node("CollisionShape2D").queue_free()
    if body.is_in_group("player"): # Placed the player scene into group 'player' allowing to use this function.
        body.die()
    #timer.start()


#func _on_timer_timeout() -> void:
    #get_tree().reload_current_scene()

I created an animation for the player where upon entering a killzone, the die() function is called and triggers my death animation, which calls for the scene reset once finished. However, my death animation loops (or rather plays twice) before the reset_game function is triggered DESPITE the Engine.time_scale. Disabling this produces that same looping. Disabling the gravity command in die() also doesn't resolve this. ~~In addition, if I'm running into the enemy, my death animation triggers but my player still slides. See here: https://streamable.com/sfvp28~~

Some bit of troubleshooting. If I were to set my death animation to Autostart, my player spawns -> death animation starts -> finishes and immediately resets my scene. So it appears my method call in the animation player is working. See: https://streamable.com/mtzqao

Watch "normal death trigger" on Streamable.

▶ Play video
#

It seems as though something is happening in my die() that is allowing for my animation to loop. Not sure what

lethal pecan
#

I'm thinking the loop has to do with the enemy still colliding with the player. Once the enemy has moved away it stops the die() function

lethal pecan
#

fixed the sliding issue with velocity.x = 0

hollow bison
#

I fell asleep sorry haha

hollow bison
#

Also you can get it working properly this way for sure but I suggest learning about animation tree

#

Because in the future if you like to make games where you can only reach some animations from others and some animations have to be allowed to play out entirely and others not it will save you

lethal pecan
lethal pecan
#

I thought it was collision layer, but I was getting errors eariler

#

so I'm using a universal killzone node for my enemies with its own script

#

so each enemy node gets a child of that killzone. my enemy script looks like ``` extends Node2D

const SPEED = 60

var direction = 1

@onready var ray_cast_right: RayCast2D = $RayCastRight
@onready var ray_cast_left: RayCast2D = $RayCastLeft
@onready var animated_sprite: AnimatedSprite2D = $AnimatedSprite2D

Called every frame. 'delta' is the elapsed time since the previous frame.

func _process(delta: float) -> void:
if ray_cast_right.is_colliding():
direction = -1
animated_sprite.flip_h = true
if ray_cast_left.is_colliding():
direction = 1
animated_sprite.flip_h = false

position.x += direction * SPEED * delta ```
#

so I was trying to figure how the enemy will know my body triggered the killzone and turn the enemy mask layer off

hollow bison
#

just do it on the player on death , not on the enemies

lethal pecan
#

not in the killzone script as so ```extends Area2D

func _on_body_entered(body: Node2D) -> void: # We know this function is for a killzone and not a coin because we added the killzone scene to the enemy.
print("You died!")
if body.is_in_group("player"): # Placed the player scene into group 'player' allowing to use this function.
body.die()
set_collision_mask_value(0, true)```

#

although, that doesnt work here

#

oh yeah let me try the player

hollow bison
#

in body.die

#

here you're changing the mask of the area2D

lethal pecan
#


func _on_body_entered(body: Node2D) -> void: # We know this function is for a killzone and not a coin because we added the killzone scene to the enemy. 
    print("You died!")
    if body.is_in_group("player"): # Placed the player scene into group 'player' allowing to use this function.
        body.die()
        body.set_collision_mask_value(0, true)``` ?
#

does not work, but I won't be surprised if I'm doing it wrong

hollow bison
#

Why do you intent on doing it here and not in the die() function

#

not that it changes anything but code clutter is dangerous

lethal pecan
#

My thought was to disable the killzone's collision layer

#

I will do it in player

hollow bison
#

i mean that works too. if you want to disable the killzone you can just disable the collisionshape of the area then

hollow bison
#

and that layers start at 1

#

not at 0

#

you can know this from the function's doc too

#

But disabling the killzone was a good idea tbh, unless you plan on having multiple enemies be able to pursue the player in which cases the death animation will be retriggered once per enemy

lethal pecan
#

I didnt see that documentation

#

I just tried 1, false

#

on my player as the layer is 1

#

still looping

#
    if not is_alive:
        return
    is_alive = false # When is_alive is false and stops all other animations.
    velocity.x = 0 # Stop the player from sliding if running. But freezes game if player dies mid-air.
    $AnimationPlayer.play("death") 
    set_collision_layer_value(1, false)
hollow bison
hollow bison
#

wait i just realized you have a if not is_alive: return

#

that should take care of looping

#

does the "death" animation ever loop

lethal pecan
#

yeah, this is realling messing with me lol

hollow bison
#

when you launch it by itself in the editor

lethal pecan
lethal pecan
#

it does the animation then stops

hollow bison
#

print something in the die() function to know if it's getting triggered twice

#

somehow ??

lethal pecan
#

ok this is interesting

#

1 sec

#

ok, so it only prints once

hollow bison
#

phew

lethal pecan
#

hmmmmmm

#

but if I just set the death animation to autoplay, the scene resets instantly

hollow bison
#

does the animation even play here

lethal pecan
#

it does

#

that's also why it;s resetting

#

because of the method call in the animation player triggering func reset_game(): # This is called from the AnimatonPlayer on completion of "death" animation. get_tree().reload_current_scene()

#

so that seemingly works as intended

hollow bison
#

oh right it's bc the time scale is slowing down the other one so it seemed strange to me

lethal pecan
#

yeah sorry

hollow bison
#

no no it's fine it's me

lethal pecan
#

so it appears that whatever is happening in the die function it's being delaying

#

or something

hollow bison
#

tbh i would need to like prod your code myself to get why tf this is happening

lethal pecan
#

yeah, I mean it's not much

#

I feel like there's nothing else I can do within the die() to prevent this though

hollow bison
#

either your code is doing something weird somewhere or engine_scale doesnt play nice with the animationplayer somehow

#

probably the first but i can't be sure

lethal pecan
#

yeah I mean I disabled the engine_scale

#

but does still does it

hollow bison
#

yeah there's a thing

#

try and hide () your player at the end of the death animation and before the scene reset and push the scene reset at bit further

lethal pecan
#

oh wait

#

I disabled the engine slow and it printed twice

#

from ``` extends Area2D

func _on_body_entered(body: Node2D) -> void: # We know this function is for a killzone and not a coin because we added the killzone scene to the enemy.
print("You died!")
if body.is_in_group("player"): # Placed the player scene into group 'player' allowing to use this function.
body.die()```

hollow bison
#

yea that's normal and doesnt do anything

lethal pecan
#

oh

hollow bison
#

bc the die() returns immediately

#

thanks to your if_alive check

lethal pecan
#

oh right

#

it returns

#

yeah hmm. I'm at a loss then

lethal pecan
#

ok

#

hmm I'd be lying to you if I told you I did it correctly, but it still doesn't appear to be working

#

well shit

#

I fixed it..

#

so dumb

#

wow I feel so dumb

#

I had my reset_game() too far out, I guess allowing for the animation to loop

#

was

#

now

hollow bison
#

wait a minute i get it now

#

i was like why tf is the animation looping still when the loop flag is not checked

#

you're not dumb,

#

it's because the animatedsprite is still playing isn't it ? you have both the animationplayer and animatedsprite playing the anim

lethal pecan
#

the animatedsprite should not be playing

#

as I never called it

#

but I think because the reset_game() had a .4 second gap, I guess it allowed for the animation to repeat?

hollow bison
#

check your physics process are you sure

lethal pecan
#

yeah

hollow bison
#

even with 2 minute gap

#
        if is_on_floor():
            if direction == 0:
                animated_sprite.play("idle")
            else:
                animated_sprite.play("run")
        else:
            animated_sprite.play("jump2")```
#

you're literally calling play the animated sprite

lethal pecan
#

No "death" though

hollow bison
#

yeah that doesn't matter

lethal pecan
#

or does that not matteR?

#

oh really?

hollow bison
#

yeah because you change the animation of it in the AnimationPlayer

#

but you don't call stop() or pause()

#

so it's interpreting that as keep playing but change the anim

#

mixing animation systems is slippery business and i must apologize as i was the one to tell you switching was a possibility but i didn't warn you

lethal pecan
#

I really enjoy doing my animations in sheets, outside of the engine

hollow bison
#

you're not dumb at all that was pretty hard to see

lethal pecan
#

which is why I opted to do so

#

so without changing the reset_game, where would you add the stop() or pause()?

hollow bison
#

i get it i used animatedsprite + sheets all the time

lethal pecan
#

yeah - outside of this I enjoy doing animations as just a stand-alone hobby

#

and enjoy the program I use to do it

lethal pecan
#

ok

#

how would I code that it? I can't just call stop() can I don't think

hollow bison
#

you can totally call stop() on the animatedsprite

lethal pecan
#

but animated sprite is not in the die function

hollow bison
#

animated_sprite is an attribute of your player

#

you can use it anywhere in your player script

lethal pecan
#

oh

#

wow

#

that fixed it

hollow bison
#

^_^

lethal pecan
#

and since the reset_game func is pushed back a bit there's a nice delay before the scene resets

#

hey thank you so much for being patient and helping out

#

you were a huge help

hollow bison
#

it's my job haha don't worry about it i hope you learned a lot

lethal pecan
#

I for sure did

#

I just don't totally understand it. I'm thinking that it triggered the die function, started the death animation, right into the idle, then back to death animation?

#

I don't get why the animated sprites of idle, run, and jump, would enable the death animation to loop a bit

hollow bison
#

animated_sprite is one entity

#

death,idle run and jump are just animations it can play

#

when you do animated_sprite.play("idle") it goes ok

#

playing mode ON

#

and starts playing idle

#

when you change the animation to "death" in the animationplayer

#

the animatedsprite is like ok.. playing mode is still ON

#

i'm just playing another animation now . But then the AnimationPlayer changes the frames, and it has priority

#

so the animatedsprite is like -_-

#

but because there's a gap between the scene reset and the end of the animationplayer interference, it can go again

#

and takes back the handle on the frames for that time (and so plays the death animation)

#

to prevent that, we tell the sprite to stop on die() like "hey it's ok the animationplayer will take over"

lethal pecan
#

ah that makes sense

#

which is why when I lowered the reset_game, the animated sprite did not have time to reinterfer with it

hollow bison
#

exactly

lethal pecan
#

ah makes sense

#

awesome! you're a great teacher

#

a lot of patience

#

I much appreciate it. I've learned a lot. I'll edit this thread to solved and add the solution in the even someone else runs into this problem. I'm sure I'll be back with some more issues in the future!

hollow bison
#

thank you !. if you ever want lessons lmk hahaha