How to immediately reset OneShot in AnimationTree?

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

Hello, I am making a 3D shooter and trying to make gun fire animation on the player model play everytime the player presses the fire action. More specfically I want it to reset the animation every time it is pressed and start from the beginning again. I achieved this with the AnimationPlayer by doing:

$AnimationPlayer.stop()
$AnimationPlayer.play("fire")

Giving me the exact effect I wanted.
Since my animations have begun getting more complex and context oriented, I moved over to using the AnimationTree, assuming I could use the OneShot to do the same thing. But I haven’t been able to recreate what I did with the animation player.
I tried doing:

$AnimationTree.set("parameters/one_shot/active", false)
$AnimationTree.set("parameters/one_shot/active", true)

But it still seems to play the full OneShot animation and doesn’t interrupt it and restart. I tried using a seek node attached to the animation, but still not avail. The closest I’ve gotten was turning the AnimTree’s active parameter on and off, but that cancels all other animations and blends so it was far from the optimal behavior I wanted.

Does anyone know a way to do this with the AnimationTree?

I’ve been wondering the exact same thing. I think the reason this:

$AnimationTree.set("parameters/one_shot/active", false)
$AnimationTree.set("parameters/one_shot/active", true)

doesn’t work, is because it takes one frame for the animation tree to update its state based on the changed parameter.

I believe setting active to false in one frame, and then delaying active=true to the next frame would work, but I haven’t tried this yet. Might be doable by using something like yield(get_tree(), “idle_frame”) in-between.

Ninfur | 2022-06-16 13:43

Yeah, I assumed it had to do with how it’s processing the state change, I even tried to change process mode of the tree, but it still acts the same way regardless if it is IDLE or PHYSICS. I tried out the yield in different combinations, but still nothing. Can’t find any github issues or other threads about this so I’m at wit’s end.

neverbegameover | 2022-06-16 14:46

So I tested the yield idea. Yielding until idle_frame does not seem to work. However, yielding until physics_frame does seem to work in my brief testing.

I’m on godot 4 right now and have something like this:

animation_tree.set("parameters/attack/active", false)
await get_tree().physics_frame
animation_tree.set("parameters/attack/active", true)

Translated to godot 3 I think this would be:

animation_tree.set("parameters/attack/active", false)
yield(get_tree(), "physics_frame") 
animation_tree.set("parameters/attack/active", true)

My animation tree is set to process on idle. I’m not entirely sure how reliable this would be though since idle/physics frames are not run synchronously.

Ninfur | 2022-06-16 15:26

Holy crud it worked! Thank you so much man! I’ve been stuck on this for days! I’ll put this as the selected answer.

neverbegameover | 2022-06-16 15:58

As of Godot 4 beta 9, the Godot 4 solution no longer works.

krazyjakee | 2023-01-10 23:32

:bust_in_silhouette: Reply From: neverbegameover

Thanks to Ninfur for figuring this out. His code and research is in the comments of my original question.
All that’s needed to do is:

animation_tree.set("parameters/attack/active", false)
yield(get_tree(), "physics_frame") 
animation_tree.set("parameters/attack/active", true)

Glad to have found one solution to this problem.

Just a heads-up to anyone thinking of using this; yield(get_tree(), “physics_frame”) will delay the activation of the one shot until the next physics frame. This is most likely not noticable, but it could be problematic if you need frame perfect animations, for example for a fighting game’s hitboxes or I-frames.

Ninfur | 2022-06-16 18:01