- Home /
Tips on managing animation states
Hi all,
I am making a 2D beat-em-up style game and I am nearing the tail end of completing all the necessary functions for my main character controller. But, because I tend to code in a happy-go-lucky kinda way, the script is basically over 3000 lines of spaghetti.
There are tons of unused/outdated variables, randomly incrementing float timers and half-finished/commented out functions. Among all this, there are several different states that require me to play several different animations. And I'm noticing that some of these animation priorities don't work they way they are supposed to.
What I am looking for is just some tips on the most efficient ways one can manage animation priorities, especially with default or "idle" animations. My animation priorities code basically looks something like this right now:
//going up and less than -200 (Jump1)
if (transform.position.y < -200 && rigidbody.velocity.y > 0 && !dbzmode && !gettinghit && !animating
&& !moving && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Jump1");
//going up between -200 and -50
if (transform.position.y > -200 && transform.position.y < -50 && rigidbody.velocity.y > 0 && !animating
&& !dbzmode && !gettinghit && !moving && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Jump2");
//going up between 0 and 200 (Jump3)
if (transform.position.y > -50 && transform.position.y < 100 && rigidbody.velocity.y > 0 && !animating
&& !dbzmode && !gettinghit && !moving && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Jump3");
//going up less than 300 (Jump4)
if (transform.position.y > 100 && transform.position.y < 150 && rigidbody.velocity.y > 0 && !animating
&& !dbzmode && !gettinghit && !moving && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Jump4");
//going down and less than -200 (crab)
if (transform.position.y < -200 && rigidbody.velocity.y < 0 && !animating &&
!dbzmode && !gettinghit && !moving && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Crab");
//going down between -200 and 0 (Jump6)
if (transform.position.y > -200 && transform.position.y < 0 && rigidbody.velocity.y < 0 && !animating
&& !dbzmode && !gettinghit && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Jump6");
//going down between 0 and 300 (Jump5)
if (transform.position.y > 0 && transform.position.y < 150 && rigidbody.velocity.y < 0 && !animating
&& !dbzmode && !gettinghit && !moving && !junklin && !grabbing && !obox.heavyon && atkready)
playersprite.Play("Jump5");
That was probably painful to look at, but it is only one example. These are the animation sequences that should play while jumping and not performing any other actions and not being affected by any other objects. As you can see, it also changes depending on your Y-axis location and whether you're on the rising side of the jump arc or falling. As you can see, it is in pretty bad shape.
If I wanted to revamp all my animation code, could someone suggest an optimal way of doing so?
UPDATE: I've decided to consolidate most of my animation states using a variable called "animating". Whenever an animation is being played, I want to set animating to true so that other animations won't override it unless I want them to. But I am still having trouble tracking animation times.
Answer by DannyB · Aug 30, 2012 at 07:01 PM
Given the details you have provided, I would like to suggest two approaches hoping that at least one of them helps you get on a good trail of thought:
First, I would avoid at all costs having long functions with endless IF statements one after the other. It is a maintenance nightmare. Furthermore, I would also work hard to avoid conditions with many ANDs and ORs.
Approach 1: Animation Class / Delegates
So a first approach to this might be to structure your code differently to avoid it.
For example, you may construct an "Animating" class, with standard variables (e.g. animation name) and functions that are common across all animations (e.g. conditions to change animation).
Furthermore, you can combine the use of delegates with this approach, so your Update loop will only call something like AnimationDelegate.Run() and the actual underlying animation will be handled by that specific delegate.
Of course, this is a very generic description, but to discuss further we need to have a better understanding of your code and needs.
Approach 2: Finite State Machine
A second approach I would like to suggest is using a simple, loose implementation of a Finite State Machine. Unless you have a very specific use case, there are strong chances it can help you organize and extend your code with ease.
With this approach you can define your states (e.g. "Jumping", "Walking"), define the events (e.g. "CollisionWithEnemy", "GrabItem") and finally define which state can handle which event (e.g. From Jumping State, on "Grab" event, go to Grabbing state).
As for how to implement a state machine, that's a different discussion and I suggest you do a search in Unity Answers, Unity Forums and the Unity Wiki. I can point you to this implementation on the Wiki but I cannot vouch for it. Personally, I have opted to build my own FSM.
Hope this helps.
Answer by pgomes · Jan 26, 2014 at 08:53 AM
Updating the answer, you should use states in the Animator to maintain animations updated.
Official Tutorial: http://unity3d.com/learn/tutorials/modules/beginner/2d/2d-controllers
Paul Conway does a good intro on 2D in Unity: http://www.youtube.com/user/MrDaeltaja
(Unity 4.3.3)