Godot Version
4.5 stable
Question
I have seen many varieties of this question asked in the many places I’ve looked, but no satisfying answers or pointers, as they all end up with issues. I’m hoping I can explain this very clearly here and maybe get some useful insight for me and the community.
If you are kind enough, please read the situation, issues, and solutions I have tried in order to understand what is needed.
The situation:
I have three different types of characters. The only differences between them are a few nodes and their data (like sprites, stats, and animations), so I only have 3 base scenes that I plan to use for all my characters. The base scenes are devoid of the data specific to characters; all of that is set up with a custom resource class called CharacterData. When I instantiate one of the scenes, I assign it a particular character’s data file, which the scene reads and uses to set itself up. I would like to save my animations for each character as resources as well, but there are several issues that seem to make it a very tricky situation.
Animations are played by a character’s states, like Idle or Walk. States are modular and shared between characters, too. For example, one base scene has a state machine with the states Idle, Walk, and Jump. Another has Idle, Walk, and Attack, but no Jump. In my game, each state has a few different animations to pick from, but let’s simplify it and say that each scene has one animation that it needs to play. So, every single character needs an animation for each state that it has, and the 3 types of characters have 3 different state machine setups.
Issue 1: Creating the Animations
The first pain point is actually figuring out how to go about creating the animations in the first place. Let’s say I use the base scene so I can set it up in the editor: the ideal approach. I go to the AnimationPlayer node to create my first animation for a given character.
And… I must name it. By hand. By typing in a magic string.
This isn’t really the biggest issue of this post, but it sets off all my programmer alarms. Come to think of it, my states all have this sort of thing in them, too:
animation_player.play("Idle")
It might not seem like a huge problem, but this means I have to just trust myself to not make a typo every time I make an animation, and that it properly matches the code that I have in the corresponding states. Not ideal, not to mention – what happens if down the line, I rename a state? Maybe I change “walk” to “run” for whatever reason. If I had saved 100 animation libraries at that point, they would all break and I would need to go back and fix them.
I would love to type something like “Idle.animation_name” directly in the animation editor as if it were a script, but that’s just not how the engine works.
Bad Solution: Create the animations via code at runtime
You can, of course, make animations in code, at runtime. This might actually work if all you needed to worry about was the sprite. You could just give your data class export variables for the start and end frames of each of the animations, then have the scene make the animations with that info.
But I also need to animate other things, which is why I’m using the AnimationPlayer. I also need to, for example, animate the position of a weapon a character holds as it does its animations, or any other possible thing based on the character. I basically NEED to make my animations visually, in the editor, for this. So this solution doesn’t work.
Issue 2 (The MAIN issue): Animations reference node paths
Let’s put Issue 1 aside for a moment and say I don’t really care about that. I create my animations for a character, then I save the AnimationLibrary so I can use it in the data class. The data class gets this line:
@export var animations: AnimationLibrary
Then I go ahead and instantiate my scene at runtime, it adds the library to the AnimationPlayer, and boom. My states call magic string names for the animations, but it works like a charm. Until… it doesn’t.
Animations are based on node paths from the AnimationPlayer’s root node. So let’s say my scene looks like this:
- Character
-
- Sprite
-
- SomeOtherNode
-
- AnimationPlayer
Then, after I have all my animations done and saved for a few dozens of characters, during development, I decide… you know what, the Sprite node should actually be a child of SomeOtherNode. So I move it there, and now my scene is:
- Character
-
- SomeOtherNode
-
-
- Sprite
-
-
- AnimationPlayer
Then I run the game again, and… all my animations no longer work. Because the node path from Character to Sprite has changed, and all my animations were saved before that. So now, I have to go through hundreds of animations to fix them all, or write some kind of script or use an addon (there is an addon someone made for this!) to do it all at once. This can’t possibly be a good approach if it’s so brittle.
Bad Solution: Don’t save any animations as resources. Leave them all in the base scenes, in the editor.
This solution kind of works, actually.
Let’s say I want to make animations for my character Timmy. I go into the inspector. Now, this time, instead of calling his idle animation “Idle”, I instead call it “TimmyIdle.”
I make all his animations, then I just leave them there. I don’t save them as resources. Then I go ahead and make another character’s, Bob’s, animations, in the same AnimationPlayer. I name them stuff like “BobIdle” and so on.
Then, I put this in my CharacterData class:
@export var character_name: StringName
Now, what you end up with is one huge AnimationLibrary in the editor, with all the animations inside the AnimationPlayer node, organized by character name. It’s not really hard to sift through – there’s even a built-in filter for animations!
Then, when my character states call the animation they need, they just do something like this:
animation_player.play(character_name + "Idle")
Presto. It works. And why is this a solution to the Issue 2?
Because if you leave all your animations in the editor, then change your node paths around during development, the AnimationPlayer automatically updates all of the node paths for you. So the problem is entirely solved.
You might even be able to have a separate library for each character instead. I just haven’t tested that. But that might be better, assuming it still updates all the node paths for you automatically in each library.
So why is this solution bad?
Well, the most obvious reason is because… well, I don’t actually know if this would cause performance or memory issues under the hood, but isn’t it messy and icky regardless? You just clump all of your hundreds of animations in one spot.
Is it memory-heavy or performance-heavy? I don’t actually know if each scene would have a copy of this huge library at runtime, or if the library would just work exactly like other resources and wouldn’t be duplicated with every instance.
The other reason it’s bad is because, well, it still doesn’t solve issue 1. I can be happy with all my animations, until one day I rename a state for whatever reason, and then I have to fix ALL of them. And remembering them and typing magic strings as I create them just isn’t good, either.
Another Bad Solution for Issue 1: Save individual Animations, have the scene name them according to the states it has
This might be the smartest solution I can think of, but I haven’t tried it yet.
Instead of one CharacterData class, I would use that as the parent for 3 different data classes: one for each type of character. So I would basically have CharacterData1, CharacterData2, CharacterData3 that all extend CharacterData.
Each class would have nothing but a few variables for each animation, like this:
@export var idle_animation: Animation
@export var walk_animation: Animation
@export var jump_animation: Animation
Then, each base scene could do something like this:
var data: CharacterData1 //set when instantiated
... //other vars
func _ready() -> void:
var library := animation_player.get_animation_library("") //gets the base library
library.add_animation(idle_state.state_name, data.idle_animation)
library.add_animation(walk_state.state_name, data.walk_animation)
library.add_animation(jump_state.state_name, data.jump_animation)
I assume this would work, and it would eliminate the issue of the magic strings. Now when I create the animations in the editor, I don’t have to worry about whatever I call them as I’m setting them up. (Still a bit awkward that I have to name them something as I create them, but eh, that doesn’t matter)
But there’s still the elephant in the room. Issue 2. There would be no way to fix Issue 2 this way, either.
And now there’s a whole other issue, albeit it’s a much slighter issue: Now I’ve created 3 more classes I didn’t need before, AND they all have overlapping variables. Remember that my states are modular? So if two classes have a Jump state, that means I need to put a variable “jump_animation” in those two, but not the other one. Duplicated code for no real good reason.
But… maybe I could just put every animation variable in the base class instead, and just keep those variables null for the characters that don’t need them. Anyway, since this approach doesn’t solve Issue 2, I don’t think I’ll be doing this, though.
My plea for help
Is there no way to solve both of these issues in a clean, elegant way? I have seen that quite a few people have asked this question over the years, but every thread I read either ends with them giving up, or people not giving good answers, or them saying “thanks!” and closing the thread, thinking they’ve solved the issue, when they haven’t. I want to leave my thread here up until I hopefully find an answer. And if I find it myself, I’ll update this.
For the time being, I’ll be going with the “one giant library in the editor without saving resources” approach. If you don’t know a good solution to both issues, but you could at least tell me whether the giant library approach would be okay or would use a bunch of memory/tank performance (assuming I’m instantiating about 30 or more characters in a scene at once), then I would appreciate that, too.








