Godot Version
V4.2.1.stable.official
Background
In a classic 2D tilemapped platformer I want to be able to grab and climb ledges. I detect the ledges by using an area2D and tileset where ledges have a specific collision layer. When hanging on a ledge, the character should be able to do a climb up and end up on top of the tile.
My arhcitecture
I have some custom state nodes handling character state, like Ground, Air and now Ledge, and expecting a lot more in the future. These states act on _physics_process()
have a reference to an custom animator node which in turn is feeding the animation_tree with parameters like velocity and whatever conditional flags.
It works really well for the basic run/idle/jum/float/fall movement.
For example LedgeState will call animator.set_state('Ledge')
when it enters that state and the animator will call the tree like playback.travel(state)
or for conditions tree.set('parameters/StateMachine/' + state + '/conditions/' + condition, value)
Climb up
Climb up is triggered when hanging on a ledge and pressing up
. I start the climb up animation, start a timer that is updated with delta and ignore further input. Both the character.velocity and .position is Vector2.Zero during the climb up. Hence, the animation will animate climb up from the hanging position.
The problem
Now the problem, when my timer is done, about 1 second (climb up animation is also 1s) the character is animated on top of the ledge-tile, but the body is still positioned next to it, as it was when hanging on the ledge.
So I position the character on top of the tile and swap animation to Ground for an āidleā-pose.
The position happen before the animation has changed (guessing this is due to position is set in _physics_process and animation is updated in _process) so for about a frame I will have the climb-up animation but the new position. Itās an ugly flicker-glitch before the āidleā-animation is showing. I have tested to set the new position on defer but couldnāt see any improvement.
So what happes in code is:
character.position = ledgeTile.position
animation_tree.travel('idle')
It is positioned corectly on the tile but the glitch is due to the climb-up animation being offset as it runs from a position next to the tile. I need both animation change and position change to happen in the same visual frame.
Solution?
Iāve been fiddling with the timer of climb up and the climb-up animation and made some improvement but it feels really fragile and will not scale well if I want to change timings later to tune things, or have it variable of speed or whatever.
Is there a better way to solve climb-up animation + actual movement? Im thinking of have it the other way, starting with positioning the character on top of the tile and have the animation offset downwards instead. But I could end up having a animation-glitch in the beginning of climb up instead of the end of itā¦
Thanks. This was long, but I hope it was detailed enough to give you enough info to help me with some pointers, ideas, or how-tos. Thank you in advance.