AnimationPlayer looping when I don't want it to

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

Hello !

I’m making a game where the player has to collect “light fragments” and bring them to an altar in order to complete the level. I have a problem where the “AltarLitUp” animation plays on loop when my player enters its detection area with all 10 fragments even though the “AltarLitUp” animation isn’t set on loop. I would like to make it so it stops at the last frame of the animation (when the altar is completely lit). Could someone please help me ? I’ve tried using AnimationPlayer.stop() and _on_animation_finished but nothing seems to work.

Here’s my code :

   extends Node2D

onready var animationPlayer = $AnimationPlayer

var player : Player


func _ready() -> void:
	set_process(false)

func _on_Altar_body_entered(body):
	if not body is Player:
		return
	player = body
	if player == body:
		set_process(true)
	
func _process(delta: float):
	if LightFragmentsCollected.current_score == 10:
			animationPlayer.play("AltarLitUp")
	else:
			animationPlayer.play("AltarIdle")
:bust_in_silhouette: Reply From: njamster

It loops because you’re calling play() in _process, i.e. every frame! That instruction is ignored if the specified animation is already playing, but once the animation finishes it’s processed again, thus the animation loops infinitely. Stopping it wont help because the animation will be instantly restarted the next time _process is called.


If the altar is supposed to light up once the player enters it’s area with enough fragments, you can simply do this:

func _on_Altar_body_entered(body):
    if not body is Player: return
    if LightFragmentsCollected.current_score == 10:
        animationPlayer.play("AltarLitUp")

If you want this to happen only once, add a boolean:

var already_entered = false

func _on_Altar_body_entered(body):
    if not body is Player: return
    if not already_entered:
        already_entered = true
        if LightFragmentsCollected.current_score == 10:
            animationPlayer.play("AltarLitUp")

If you really want the altar to light up regardless of where the player is, as long as the player entered the area once before and has collected enough fragments:

var already_entered = false

func _ready() -> void:
    set_process(false)

func _on_Altar_body_entered(body):
    if not body is Player: return
    set_process(true)

func _process(delta: float):
    if LightFragmentsCollected.current_score == 10:
        if not already_entered:
            already_entered = true
            animationPlayer.play("AltarLitUp")
    else:
        animationPlayer.play("AltarIdle")

On a side note, your if-condition is pointless: player == body will always be true, if you set player = body the line before. I’m not sure what you’re trying to do there.

Hey, thank you for your quick answer, it works ! :slight_smile:
I made my if condition player == body yesterday when I was trying to solve another problem I’m having where I was trying to make the player character plays its “LevelComplete” animation when the Enter key was pressed once inside the area of the altar and all fragments collected (still doesn’t work right now but I’ll figure it out somehow, maybe with signals), I didn’t realize it was pointless but it makes sense !

Lothrinn | 2020-05-06 12:04

:bust_in_silhouette: Reply From: jasperbrooks79

You can make it so, maybe been said, add another variable, HasPlayedOnce, set it to false, then make sure, condition for playing is what triggers animation and, also HasPlayedOnce = FALSE . . Then, when you play it, from code, also SET HasPlayedOnce to TRUE . . :smiley: :smiley:

Only play, if animation - triggered AND HasPlayedOnce = false <3

Hey, thank you for your answer !

Yes, the top comment of this question has answered my question and now everything works. I also used this method to make the player character play its “Level Complete” animation when it is in the area of the altar and has collected all fragments :slight_smile:

Lothrinn | 2020-05-06 15:14

:bust_in_silhouette: Reply From: jasperbrooks79

Or, you can make an integer, called ’ TimesPlayed ', start by setting it to ZERO, then WHEN animation is played, set it to 1, and ADD condition ( play IF Timesplayed LESS than 1 ) . . <3