+1 vote

I'm working on a point&click puzzle game, where most of the player's interaction uses animationplayer nodes (eg. drop a key into a lock, open a chest, etc).

However, I'm very confused by the behavior of the animationplayer node.

When the game starts, I need to play a 'default' animation for interactable objects (like the chest) before doing some other setup. Logically, there's nothing difficult about that ... but I just couldn't get it to work ! The animation always played -after- the rest of the setup was done ?!

I read the docs again, and noticed 3 methods :
. play()
. seek()
. advance()

But I don't understand the explanation. For instance, for play() :
"the anim will be updated the next time the AnimPlayer is processed (???) ; If other variables are updated at the same time this is called, they may be updated too early (???) ; to perform the update immediately, call advance(0)"

And for seek() :
"seeks the anim to the seconds point in time ; if update is true, the anim updates too, otherwise it updates at process time. Events betw/ the current frame and seconds are skipped."

What is the difference between the 3 ??? When am I supposed what method ?

And then there's also the 'AnimationProcessMode' :
- ANIMATIONPROCESSPHYSICS --- Process animation during the physics process. This is especially useful when animating physics bodies.
- ANIMATIONPROCESSIDLE --- Process animation during the idle process
- ANIMATIONPROCESSMANUAL --- Do not process animation. Use advance to process the animation manually

I don't notice anything different when I try this out ... So again, what's the difference between them ?

Sorry for the long question - I just want/need to understand !

in Engine by (101 points)

2 Answers

0 votes

Easy. You create the animations in the editor by creating a SpriteFrames resource and then use logic to choose the animation.

For instance, assuming you are referencing the object from its parent node:

Var anim = $AnimationPlayer
Anim.play(‘default’)

So the name of the AnimationPlayer node, method is play and in parentheses, a string for your animation. There are other methods too, like

anim.play_backwards(‘default’)

Good note: you can also yield to the animation ending before you trigger other logic. For instance, waiting until a animation is done to add points:

Yield(anim, “animation_finished”)
# next code here

The Godot docs also explain it well but Davidepesce.com also has some good tutorials to give you a visual reference. Also this link: kidscancode tutorial

Also, good note here: signals connected to the node’s own script are great ways to make transitions between animations and since they connect to its own tree normally, they are easy to instance with little code later if you duplicate them.

Signal next_frames

Func _ready():
   Self.connect(“next_frames”, self, “on_next_frames”)
   Anim.play(‘default’)

And say when a hit runs you emit your signal:

Emit_signal(“next_frames”)

And then put the code you want to run here:

Func on_next_frames():
    Anim.play(‘moving’)

And as for the warning for when they are done processing: you generally don’t want to call anim.play() more than once in the same function unless you have some way to sequence them. Generally better to separate these into different pieces of logic (and signals are great for this) and not the same piece of code from what I have learned so far. I have a carnival mini-game/whack-a-mole i am working on and i have managed to transition between moles moving up, down, getting hit and being idle all only using the play() function. All you need to do is plug it into the right sequence of logic using the steps above.

by (534 points)
edited by

Thank you for your long explanation ! Even though this didn't answer my question , I still learned some new things !

Puzzle objects usually have a fair number of area nodes for interaction (hotspots). For this chest for example, there are : swing lock, key drop, key turn, open lid, close lid, 2 zoom levels, and a zoom out.
The easiest way to activate/deactivate these hotspots in turn, is by using an animationplayer with 1 track for each action.

The problem I'm having, is an issue of timing - even though my code @startup says :
play a 'default' animation, -then- setup the default zoom object, Godot always plays the animation -after- the setup of the zoom object.

I suspect it has something to do with the things I mentioned in my original question (the difference betw play() / seek() / advance(), and/or AnimationProcessMode ), but I don't understand the documentation ... So, if someone could explain it in simple terms, I would be very grateful.

chest w multiple area nodes for interaction

That seems easy. Just put this function in the animation for when you load it AND load that zoom box.

Assuming anim is assigned the child $AnimationPlayer:

Func my_function_name()
    Anim.play(“default”)
    Yield(anim, “animation_finished”)
    ### then your function or signal or code to load the zoom box

Try that? That should make the loading of the box wait until the animation is done.

Thank you. Yes, I understand what you are saying. However, this is a big game and I want to decouple object animations from zoom functionality.

Also, the way I want/need to set all of this up -should- work. There's nothing strange or complictated about it. It's just that the animationplayer always starts playing too late (logically).

0 votes

For anyone interested (thanks to @SpeCterMK & @golddotasksquestions on Reddit) :
<br/>

The AnimationProcessModes change how often the animationplayer updates it's internal state.

=> PhysicsProcess : it will update at 60 times per second(60hz or 60fps) - use if you move physics bodies with the animationplayer.

=> Idle : updates during idle frames

=> Manual : only updates when you tell it to update with advance( )
<br/>

The methods :

=> play() : plays the assigned anim from start to finish (you can set some params to specify how it will play) IF it is the first time you play this anim., OR, you just assigned this animation to the player.
If you use stop(false) while the anim is playing, play() wil resume it (continue where you stopped it).
If you use stop(true) while the anim is playing, play() wil start the anim from the first frame again.

=> seek() : sets the player head at a certain position in the animation (eg. half way - moves TO). You need to use play() to actually start the animation from that point.
If you use seek(true), the visuals will be updated right away.
If you use seek(false), the visuals will only update the moment you have started playing the animation.
If you seek() to the very end of your animation, and you have the animplayer connected to an animation_finished signal, this signal will NOT fire.

=> advance() : behaves almost like seek() (moves BY), except that the signal animation_finished WILL fire when you advance() to the end of the animation.

You can use the 3 methods in combination with AnimationProcessModes PhysicsProcess and Idle, but you need to use advance() with Manual (if you want anything to happen =) ).
<br/>

Note 1 : there is a bug in Godot 3.3 where advancing to the end of an animation doesn't update the visuals (but does fire the signal). Advancing to just before the end of an animation works ok.

Note 2 : there is a bug in Godot 3.4.4 where using stop(true) followed by advancing to the end of an animation is broken (doesn't update the visuals and doesn't fire the signal).

by (101 points)
edited 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.