Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AnimationNode lifecycle callbacks #1462

Open
RolandMQuiros opened this issue Sep 4, 2020 · 4 comments · May be fixed by godotengine/godot#41771
Open

Add AnimationNode lifecycle callbacks #1462

RolandMQuiros opened this issue Sep 4, 2020 · 4 comments · May be fixed by godotengine/godot#41771

Comments

@RolandMQuiros
Copy link

RolandMQuiros commented Sep 4, 2020

Describe the project you are working on:
A heavily animation-driven beat'em-up.

Describe the problem or limitation you are having in your project:
In Unity, I like to use StateMachineBehaviours to drive a lot of my character logic. It puts my code very close to the onscreen representation, which makes it quick to adjust and rebalance character abilities and behaviors.

image

This lets me attach modular logic to specific animation states, without having to juggle a separate state machine structure. It also lets me implement rollback netcode fairly easily, since I can track state and resimulate using just the Animator's Update(float deltaTime) method.

Godot's AnimationTree is almost to the point where I can recreate this approach, but AnimationNode's API doesn't expose a lot of its own information to scripts. Specifically, I'm having a hard time telling if a node is processing, and when it starts and stops processing. I'm able to script around this, but it's lot of hacking that involves traversing property lists and finding nested AnimationNodeStateMachinePlayback objects. And those playback objects only exist for state machines, which means I have to write specific implementations for other subclasses.

I know parts of this have been an issue for users in the past but apparently not many of them.

Describe the feature / enhancement and how it helps to overcome the problem or limitation:
Expose more AnimationNode data to scripts. Add lifecycle callbacks to the AnimationNode scripting API for entering, exiting, and processing.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
I've already made the modifications here: godotengine/godot#41771 (comment)

The changes add the following members to AnimationNode:

  • property Dictionary child_nodes
    • Property that exposes the result of AnimationNode.get_child_nodes() to scripts, so you can traverse the structure of the AnimationTree at runtime. Currently get_child_nodes returns null for extends AnimationNode scripts, and simply doesn't exist for AnimationNode subclasses.
  • virtual void _advance(float delta)
    • Called every time the node is processed, with the delta time passed in.
  • virtual void _on_play(float time)
    • Called when the node starts playing, or is "entered" in a state machine. time is the time returned by AnimationNode.process, which is the time left in the node's current animation.
  • virtual void _on_stop(float time)
    • Called when the node stops playing, or is "exited" in a state machine. Same time parameter as _on_play

I also modified the behavior of get_child_nodes(List<ChildNode> *) in the C++ classes. They now call the script get_child_node implementation, even in AnimationNode subclasses, so you can override the behavior even if your extends AnimationNode script is attached to an AnimationNodeStateMachine.

I would absolutely appreciate any feedback on the above API choices.

If this enhancement will not be used often, can it be worked around with a few lines of script?:
It can be worked around, but not elegantly, and in many more lines than I'd like.

I'm not aware of many people who use animation state machines this way, especially since Unity's been neglecting Mecanim in favor of DOTS stuff, but I'm hoping Godot can pick up the slack.

Is there a reason why this should be core and not an add-on in the asset library?:
It's directly modifying the behavior of a built-in class.

@jonbonazza
Copy link

I think you are confusing AnimationNodeStateMachine, intended to be used only for animation playback control, with unity's StateMachineBehaviour, intended to be used for behavior.

What you should be doing instead is using one of the many FSM libs on the assetlib to create your behavior states, and then change the AnimationNodeStateMachine states to the correct state from within your behavior states.

@jonbonazza
Copy link

FWIW, I do believe an official FSM implementation should be provided by Godot, but that's a separate issue.

@RolandMQuiros
Copy link
Author

Having already made the modifications, I can tell the AnimationTree was made only with animations in mind. The same is true for Mecanim, Unity just seemed to provide StateMachineBehaviour as a courtesy.

But for genres like fighting games that have tight coupling between logic and animation, this approach does a lot to curb complexity, and scales well when creating new animations+behaviors.

I'll mention the rollback netcode example again, since it's a pretty big benefit of this approach. If logic is coupled to the AnimationNodeStateMachine, you can accomplish both the rewind and resimulate steps using the ANSMPlayback's start and advance methods, without having to maintain a separate FSM.

@Calinou Calinou changed the title AnimationNode lifecycle callbacks Add AnimationNode lifecycle callbacks Mar 30, 2021
@QbieShay
Copy link

Hey @RolandMQuiros ,
Perhaps I am misunderstanding the problem, but have you tried setting up function calls in the animations (with post import scripts where appropriate)? Is there any particular limitation with that method?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants