Unity 3D – Super Simple Animation System (SSAS)

One thing I always considered good practice is “If you know what you need, and ‘the wheel’ is over-bloated, it’s OK to reinvent.” I looked at animation systems involving many awesome features, but I wanted something really, really simple. Named after my room mate, here is the Super Simple Animation System (SSAS).

So, let me start by saying this isn’t a  complete system. This is extremely basic, and has much room for improvement. Anything you want to add or change, feel free. But if you need something to animate, and animate now, go for it.

Features:

  • Pro: Pretty fast!
  • Pro: Easy to implement and modify.
  • Pro: Supports switching animations at runtime.
  • Pro: Supports different sized textures.
  • Con: A bit memory heavy.
  • Con: Replaces Textures in the materials.

We get it, get on with it!

Geez, bossy, bossy…

So, for the noobies out there, you’re probably wondering “How do animations work?” Well, I’ll tell you.

So you know movies? Like, watch it in a theater? Moving pictures? So one single picture in the movie is called a frame. To make the movie, the frames flip by really fast. This is called Animation. That’s why you’re here. Good.

So, here is my full SpriteAnimation class. Just, gonna toss it at you, and we’ll break it down. Real simple-like.

SpriteAnimation

using UnityEngine;
using System.Collections;

public class SpriteAnimation : MonoBehaviour 
{
    [System.Serializable]
    public class Animation
    {
        public string Name;
        public Texture2D[] Frames;
        public int currentFrame = 0;
        public float frameTime = 0.5f;
        private float curTime = 0.0f;

        public void Reset()
        {
            curTime = 0.0f;
            currentFrame = 0;
        }

        public Texture2D UpdateAnimation()
        {
            if(curTime >= frameTime)
            {
                ++currentFrame;
                if (currentFrame >= Frames.Length)
                    currentFrame = 0;
                curTime = 0.0f;
            }
            else
            {
                curTime += Time.deltaTime;
            }

            return Frames[currentFrame];
        }

        public Texture2D GetCurrentFrame()
        {
            return Frames[currentFrame];
        }
    }

    public Animation[] Animations;
    private Animation currentAnimation;
    public string DefaultAnimationName;
    private int DefaultAnimationIdx = 0;
    public Texture2D currentFrame;

    void Awake()
    {
        if(DefaultAnimationName.Length == 0)
        {
            DefaultAnimationName = Animations[0].Name;
        }
        else
        {
            DefaultAnimationIdx = GetAnimationByName(DefaultAnimationName);
        }

        currentFrame = Animations[DefaultAnimationIdx].GetCurrentFrame();
    }

    // Use this for initialization
    void Start () 
    {
        currentAnimation = Animations[DefaultAnimationIdx];
    }

    // Update is called once per frame
    void Update () 
    {
        currentFrame = currentAnimation.UpdateAnimation();
    }

    public int GetAnimationByName(string Name)
    {
        for (int i = 0; i < Animations.Length; ++i)
        {
            if(Animations[i].Name == Name)
            {
                return i;
            }
        }

        return 0;
    }

    public string GetCurrentName()
    {
        return currentAnimation.Name;
    }

    public void SetAnimation(string Name)
    {
        if (currentAnimation.Name == Name)
            return;
        foreach (Animation a in Animations)
        {
            if(a.Name == Name)
            {
                currentAnimation = a;
                currentAnimation.Reset();
                return;
            }
        }

    }
}

OK, take a few breaths, before you blow your mind. As you see, I have a nested class, Animation, inside my SpriteAnimation class. Doing this allows me to keep an array of Animations in my SpriteAnimation, and keep a multitude of variables for each individual object. And using the [System.Serializable] attribute allows it to appear correctly in the Unity3D inspector.

So lets start with the Animation class:

        public string Name;
        public Texture2D[] Frames;
        public int currentFrame = 0;
        public float frameTime = 0.5f;
        private float curTime = 0.0f;

Here are our variables in Animation.

  • Name – Our most important variable here. This is how we identify and look up the animations. If you can’t get this system to work, come to me asking for help, and I find out it’s because you didn’t name your variable – I will find you.
  • Frames – Here are our frames. Every individual frame that makes up this animation goes in here*.
  • currentFrame – This is the iterator for our animation. This will increment after frameTime elapses.
  • frameTime – The duration of a single frame. After 0.5 seconds, it will iterate to the next frame (I just explained this – pay attention!)**.
  • curTime – How much time elapsed on the current frame.

* – This method switches out the texture in the material, which, in some cases, can create a massive drop in performance. You may want to switch to an array of Materials, if one was so inclined.

* – This is a slight disadvantage, because if you wanted a particular frame to last longer/shorter than frameTime, you’re SOL. You could take this class a bit forward and make a nested Frame class. Has a ton of advantages, but then you’ll need to drop an ‘S’ in our SSAS.

Now that we have our members, it’s time to get down to the methods:

  • Reset – Resets the Animation back to its initial frame, and resets the curTime to 0.
  • UpdateAnimation – Adds deltaTime to curTime, and when curTime >= frameTime, it iterates the frame. Returns the current frame.
  • GetCurrentFrame – What do you think?

Next, we look at the SpriteAnimation Class

Here we have our members:

    public Animation[] Animations;
    private Animation currentAnimation;
    public string DefaultAnimationName;
    private int DefaultAnimationIdx = 0;
    public Texture2D currentFrame;

And now we break it down:

  • Animations – an Array of all our animations for this SpriteAnimation. This could be “Jump,” and “Walk,” and “Fire” and so on and so forth…
  • currentAnimation – the Animation that’s currently… Animating… yeah…
  • DefaultAnimationName – This is the default animation to start on when our game starts.
  • DefaultAnimationIdx – It’s easier to search by index than by name.
  • currentFrame – The current frame to render.

And now that we have our members, lets take a look at all the methods:

  • Awake – Runs when the object is first created in the scene. Sets up the default animation and default frame.
  • Start – Runs before the first update. Sets the current animation.
  • Update – Runs once every update frame in our game. Calls UpdateAnimation on the current animation and sets the current frame.
  • GetAnimationByName – Searches the list of animations and returns the index animation who’s Name is equal to the parameter (This is why Name is important).
  • GetCurrentName – Obvious, isn’t it? It gets the Name back from the current animation.
  • SetAnimation – Sets the current playing animation to the animation who’s Name is equal to the parameter. This is what we use to switch animations on the fly.

The SpriteAnimation class does the meat of the work in terms of animation. What we need now is a way set the current frame to our object.

Enter SpriteManager

using UnityEngine;
using System.Collections;

public class SpriteManager : MonoBehaviour 
{
    SpriteAnimation animator = null;
    MeshRenderer mesh;
    // Use this for initialization
    void Start () 
    {
        if (animator == null)
        {
            animator = GetComponent();
        }

        mesh = GetComponent();
    }

    // Update is called once per frame
    void Update () 
    {
        mesh.material.mainTexture = animator.currentFrame;
    }    public void ChangeAnimation(string Name)
    {
        animator.SetAnimation(Name);
    }    public string GetCurrentAnimationName()
    {
        return animator.GetCurrentName();
    }
}

First thing right off the bat you should think “Hey, why do I need 2 components to do the same thing?” Short answer is shut up. Longer answer is by having the SpriteAnimation class and a SpriteManager class separate, this allows us to do interesting things. The SpriteManager is what puts the frame of animation onto the object. We can have multiple SpriteManagers using the same SpriteAnimation and synchronize all their animations. The SpriteManager is also the façade class that we will use to change animations from other objects.

Lets break it down. Here are the members:

  • animator – This is the SpriteAnimation class that is linked up to this SpriteManager.
  • mesh – This is the object we will be plastering the game object onto. We can also make another SpriteManager that deals with GUI textures, or whatever. Changes to this Animation System are Super Simple (See what I did there?).

And here are the simple methods:

  • Update – Applies the current frame in the animation to the mesh.
  • ChangeAnimation – Call this function from other scripts to change the animation.

So, that’s pretty much it! The SpriteAnimation class can go anywhere that updates, but the SpriteManager has to go on something with a mesh.

Use these to your wee little hearts delight. Some form of credit would be appreciated.

Any questions or problems, just leave a comment below and I’ll do my best to help. Till next time, take care, programmers!


Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.