I’m currently working on a 3D side-scroller where the main character needs to be able to switch between different behavioral states such as walking, aiming a weapon and kneeling. Different player controls and behaviors are naturally active depending on the active state, and animations are played to transition from one state to another.
The problem:
The system is mostly working as I have it, using some rough placeholder animations, but some relatively rare glitches are occurring which makes me wonder if I might have implemented it in a sloppy way that needs to be changed.
One example is when transitioning from a kneeling position to a standing position, it will work as expected unless I hold the key to move forward while the character stands up; now it will usually work the same way but occasionally the character will move forward slightly before resuming normal behavior resulting in a stuttering feel. Logically, this seems to be the result of some kind of off-by-one error where holding forward is resulting in the game thinking it should be moving forward for a single frame before checking the controls should be frozen until the standing animation is finished.
I assumed the nature of FixedUpdate being called more often than Update and potentially much more or less often depending on framerate may have had something to do with it and why it only happens now and then (it does seem more frequent during lag spikes) but examining those functions carefully didn’t provide a clear answer and it still looked to me as though there shouldn’t be a possible way FixedUpdate could decide to move the character AFTER Update had been called and seemingly the state was changed to one where the controls would be locked.
I’ve tried to pin down the exact cause, but after adding another ugly boolean that did seem to stop it from happening at least almost all of the time (it’s hard to check for sure) I decided I needed to reassess whether or not my entire behavior/animation state switching system makes sense or I’m setting myself up for more trouble down the line, not to mention it looking uglier than I feel it should as things are.
My current system:
The character can be in one of several movement states including WALK_MODE and KNEEL_MODE. The problem I’ve described occurs when transitioning from KNEEL_MODE (where the player is holding down a key to remain kneeling and releases to stand up again; left/right direction keys no longer work, but shooting is still possible etc.) to WALK_MODE (left/right movement is now possible again etc.).
A major issue is that animations take time to play, and during that time I obviously don’t want some controls to be usable but once I detect the player has decided to stop kneeling I instantly change the player’s movement mode to WALK_MODE but freeze the controls by checking if the “Unkneel” animation is still playing like so:
if ( animator.GetCurrentAnimatorStateInfo( 0 ).IsName( "Unkneel" ) && animator.GetCurrentAnimatorStateInfo( 0 ).normalizedTime < 1.0f
|| animator.GetCurrentAnimatorStateInfo( 0 ).IsName( "Kneel" ) && animator.GetCurrentAnimatorStateInfo( 0 ).normalizedTime < 1.0f )
{
inKneelAnim = true;
}
This sets a bool called “inKneelAnim” which is used to check if controls should be frozen. Clearly, the problem could lie in having a frame where WALK_MODE has been entered but for some reason the animation is occasionally not considered to be playing yet when checked; I notice I’m setting the booleans for the Animator using its Update function, perhaps FixedUpdate would be better? Presumably the Animator isn’t calling its Update function early enough to Unity seems to suggest putting them in Update, but either way I assume my system probably needs to be cleaned up as this seems very vulnerable to lag given the game’s actual logic depends on these things being done in the right order every time.
Is this a bad way to deal with animations or is there no real other majorly different way? Perhaps the addition of something like ANIM_MODE that I could switch to while animations were playing between states would at least prevent problems like the WALK_MODE behavior seemingly being active for a frame when it shouldn’t be…
Just testing now I can see that with one implementation the glitch seems not to happen until I scroll to encounter some enemies, at which point it happens almost all the time. Seems to be closely related to framerate so, and presumably the bool in the Animator indicating whether to kneel or not being set in Update too long after FixedUpdate.
Sorry if this wasn’t as clear as it could be, but TL;DR I basically just need some advice on how best to transition between different behavior states for a character using animations, making sure that the appropriate controls are active exactly when they’re supposed to be and there is no chance of undesired behavior due to animation states not being updated in time.