Jump To Frame in 2D Unity

Jumping to a specific frame in a 2D animation is not supported by Unity out of the box. I’m not saying it should be as it’s only needed in a very specific situation. I however, am in that situation a lot, so I figured others might be too.

This article may contain affiliate links, mistakes, or bad puns. Please read the disclaimer for more information.

I needed a sample, so to illustrate the premise, below is a random emoji game. Click anywhere to display two random emojis. If they match, you get more points. So fun.

Loading...

It probably makes more sense to discuss the Why before the How, but I’m reversing that today. It’s easier to explain by starting with example, and most of you probably already know Why (otherwise what would bring you to this article?).

The How Part

Editor

In this example, I’ve got a game that displays a random emoji. I’ve got about 20 emoji’s as separate pngs, and I really don’t want to create 20 prefabs. So I follow these steps:

    1. Group select the sprites I want, and drag them into the scene.
    1. Unity will automatically turn this into an anim, and ask you what you’d like to name the it (I recommend “AwesomestAnim”).
  1. By default I now have an anim that just loops, which we need to fix.
      1. Find the Animation Controller (AwesomestAnim.controller), double click that.
      1. Select the animation inside it.
      1. Change Speed to 0.
    1. Close the animator window, it is now dead to us.

You now have an animation that’s ready to go. But what if you forgot some frames? To add frames (or edit) you have to open the Animation window (Window->Animation up to 2018.1 or Window->Animation->Animation for 2018.2+), and select a GameObject that references the animation. Note, this is not the .animation file that is on-disk. For whatever reason, you can only add frames to an animation that is in-scene.

Code

First, I need access to the animator and need to remember how long it is:

public class FrameJumper : MonoBehaviour {
    public Animator myAnim;
    private int myAnimCount;

At startup I do some calculating to get the number of frames:

   void Start()
   {
      //setup animation…
      var animInfo = myAnim.GetCurrentAnimatorClipInfo(0);
      if(animInfo.Length > 0)
      {
         var mainInfo = animInfo[0];
         myAnimCount = Mathf.FloorToInt(mainInfo.clip.frameRate * mainInfo.clip.length);
      }
   }

Then while running I can set to a specific frame (a random one in this case):

      int frame = Random.Range(0, myAnimCount - 1);
      float normalizedTime = frame / (float)(myAnimCount) + 0.001f;
      myAnim.Play("EmojiAnim", 0, normalizedTime);

This last bit is the meat. First I pick a frame randomly. Then I calculate what I’m calling “normalizedTime”. This is basically a percentage of how far through the animation I want to be. I do that by dividing the frame I want by the total, then adding a small amount to account for rounding errors. Lastly I play the anim starting at that time. Because speed is 0, the “play” just sets it to that point and holds.
There are a couple other ways you could do this. The advantages of this method are that either number of frames or length in time can change without causing any issues.

The Why Part

Unity’s animation system was built specifically for 3D animations. Those based on moving/warping/modifying objects. They then added support for 2D objects doing the same thing, as well as 2D flipbook animations. A flipbook is an animation based on a collection of still frames (like an old-school cartoon). This support has some mixed results. Here’s a breakdown of the types of animations you might have…


As discussed above, the types of animations on the left involve moving objects in the scene. The ones on the right are sprite based, but still have two groups. The Movement group is animations such as walk or run cycles. Animations where you generally play a collection of frames, then transition to some other collection (or loop). The Still Frames category is one where you’re primarily jumping to specific frames and holding. A simple example is if you had 3 sprite frames for a stop light.
Where I run into this situation more often would be things like an enemy prefab that I’d like to have 10 different variations of (based solely or primarily on art). In Unity’s 2D Roguelike Tutorial they run into this situation while creating their level background and border. They created a ton of prefabs, where it would have been much simpler to create a single prefab that allowed you to set it to any frame of its animation. In some instances, what they did in that tutorial would actually be simplified using the new-ish tilemaps, but not all cases.

The End Part

Hopefully this is helpful to you, as it was a bit of a head-scratcher when I first ran into it.  As always, if you see any issues, please let me know in the comments.

Do something. Make progress. Have fun.

1 comment on Jump To Frame in 2D Unity

Comments are closed.