How to handle complexity with a lot of character animations

Trying out my first attempt at a full project, I’m noticing something that rapidly becomes apparent: As you add more features to the player or a character, using logic nodes to setup the animations becomes a nightmare very fast, to the point where it’s soon unmanageable.

You’ve defined a Platformer Object for your player: First you have an idle and walk animation… all easy, play the walk animation when the player has speed or idle otherwise. Now there’s a fall animation… okay, play that whenever the player isn’t on the ground then for the other two check the on-ground status. Then comes the slide animation for when the player stops from high speed… once more define what triggers it then add inverted exceptions everywhere else. Once I finally get all the standard ones working, something else comes along and makes it all the more complicated: Actions that depend on a key being held or an animation to finish playing, such as running while holding down the Shift key.

It gets even worse when you have to cover edge cases like contradictory keys being pressed. Let’s say the player is holding the crouch key but also the left or right key: The walk animation must play and ignore crouch if there’s speed, but if the down key is still being held when the player stops it must revert to crouch. This is just one screen of the mess I’ve got right now:

At this point I don’t know how to describe animations without my event sheet becoming huge: Without being specific on each animation and grouping by sets of circumstance, the wrong anim takes priority over the desired one when you don’t want it to, while another animation may not play because the circumstances for a former animation were met first. Everything must be told “when this key is pressed but this one isn’t, also the player mustn’t be in the air, and they must have this much speed, oh and not when this timed animation playing every 30 seconds got triggered and didn’t finish playing”.

I’d like to know if there are any extension that can help: Has anyone made an animation manager with a scheduler, where you can maybe queue multiple ones with timeouts and priorities over each other? Otherwise what are the best practices you recommend with a lot of animations to avoid complexity?

Hello, MirceaKitsune!

Without a doubt, as our game grows, it becomes a challenge to assemble our code in a simple way. But looking your code I think you could improve the use of events and subevents because you are repeating things unnecessarily. And to improve this you could use the logic of FSM: How to handle complex logic – The finite state machine (FSM) - GDevelop documentation
It wasn’t easy for me to understand in the beginning, but little by little I changed and improved my game’s code a lot following this logic.

I don’t know if this extension can help you, because I never used:

2 Likes

Thank you very much! That article is exactly what I was looking for. The extension is interesting too: Main issue I’m seeing with it at first glance is it only helps with the default animations of the Platformer Object behavior, I have plenty of custom animations and would need to override it… further more I have states / transformations so the animation wouldn’t be just walk but more like player.VariableString(state) + "_walk", the behavior doesn’t seem to support that.

The machine states approach is interesting, may even use multiple events if that’s ideal. I was initially thinking of using an array and priority based system, but that seems like it’s more likely to just move the mess. This sounds better but I’d need to think what to separate into different states: I have random idle animations, a stop and slide animation, even one for pushing against a wall or object… each would be part of one of the various states and I’ll need to stop them fighting among each other as well.

A step based approach seems best, including animation names as each adds a new word to represent a branching action (eg: inair_falling, onground_walk, onground_pushing): For each one go down the ladder and see what the next step is. I’ll think of it then probably redo the everything.

1 Like

I’m done for the night so I’ll need to finish the rest tomorrow: For the time being I redid the basis in a new event group in this form which looks a lot better already! First I set the base animation variable to the base state, as I go along I add a new word to the animation name for every (sub)specific, at the end setting the animation name to this variable if it differs. Obviously I’ll be doing more things in there like checking pressed keys then flipping the sprite or changing speed.

I think it’s something the FSM does. Look at this answer with an image of FSM that @MrMen is using in his game How do I make the enemy patrol, chase in a certain distance and at the same time attack the Player when in Collision - #3 by MrMen
It’s impossible to more than one state be true exactly the same time, because it’s just one variable. Another good thing is the optimization, because while one state is false, Gdevelop didn’t read the subevents.
In my game I didn’t use a variable. I use the states of the Platform Character Behavior (on Floor; Jumping; etc)

I don’t know if it’s necessary. But if you gonna do it make a backup of that your code. Maybe you feel the need to go back and try to modify it.

It took me a while to understand your code! Before I was thinking that it would accumulate “pieces” of text on your variable “anim”, but every frame your variable “anim” resets to the variable “state”. That’s interessting! I’ve never seen it that way! I use the “traditional” way of simply choosing each animation in each situation.

Good luck with your code tomorrow!

1 Like

As a heads up, the new “make a zelda game” tutorial videos by HelperWesley on the official GDevelop YouTube channel has some more examples of unique FSMs, and my example “Not-a-vania” has an advanced FSM for a platformer that uses external event sheets to keep the main scene event sheet cleaner.

They may help you get closee to what you are looking for.

1 Like

Yes, saw a bit of that as well. I liked how he used a similar animation concept, where you add words to the animation name so the various modes fit in flawlessly. Just got the new system done myself, still a bit long but much shorter simpler and now I know where to add every new thing without having worry how it may affect something else :slight_smile:


2 Likes

Wow! Great! :star_struck:

MirceaKitsune, I don’t want to be boring :eyes:, but there are still possibilities to simplify using subevents. I don’t think that one or two events depending on the conditions will impact the optimization or the organization of your game, but several might (especially if it’s for mobile). So my advice is that in simple situations, be sure to take advantage of the logic of subevents. Look this example of your code:
image
Gdevelop will check if the player is not grabbing a platform ledge two times per frame if your player is not on the floor.
But you can change for this and Gdevelop will check only one time:
image

In your second screenshoot you are checking if the boolean value of variable “keys_crouch” of player is false three times in separated events. Maybe you could do the same thing using an event with this condition and creating subevents.
But I think you already understand the logic and it is more a matter of practice and i’m being annoying. :sweat_smile:

It’s alright. I intentionally wanted to not use more sub-events than strictly needed, it can make the event sheet longer: Sometimes it’s easier to group by a few different circumstances checked together.

Also something important I can’t believe I forgot: If you want maximum simplicity and efficiency, the best choice by far is to create a custom behavior for both your player and enemies, this way you can create and call your own actions in an actually organized format. You also don’t even need to link external events on every map, just make the player a global object add your custom behavior after Platformer Character and that’s it… you can also customize the properties of each enemy from its behaviors menu instead of having to use variables. My final step will be to port it all to a custom extension and get rid of the scene events used for this purpose.

1 Like

This, the Not-a-vania example! This was I think the first project I explored on my own and I used it to do a simple metroid vania that used assets from Spawn on SNES and a few others from Mugen games. Utilizing it first and being like whoa there is a lot going on here was really tough, but I built an easier version of the controls that didn’t really use parts of the code in the example. At that point in time I didn’t understand why they had decided to move the player character like that, but I quickly learned as my system wasn’t able to handle so many other things going on.

As I wanted my player character to do more and more, I eventually pretty much went back with the system used in that example, only some minor tweaks here and there as I was trying to capture the feel of my first test project.

Thankfully though, it’s nice to take code from projects I have already tweaked put that whole system under a trigger group and then copy and paste it to my current project. So after it works, I keep it all minimized under that heading until I want to add something new. I don’t know about you guys but my machine I work on mainly is a decade old chromebook that has been reformatted with Gallium so my max resolution is just barely bigger than the default game view lol. Clean code/triggers are really important for me to not feel so overwhelmed.