Animating Sprites

 estimated time : 7 mn
ingredients needed : Unity, Playmaker
(this recipe is part of the footvolley game menu )

Detailed Steps

Sprite sheets.
Slice a sheet in the editor mode.
Create an animation.
Looping an animation.
Making transition between animations.
Moving between transitions by script.

 

What is a sprite sheet ?

mario_jump’s tilesheet

A sprite sheet is an effective way to combine a lot of 2D animations, into a single file instead of having a living hell of 30 different files called “player_move00”, “player_move01” and so on..

Instead you put all your sprites into one or multiple big images, and you’ll later split all these sprites in the editor.

 

Adding the sprite sheet

Select your sprite sheet from the asset, be sure that your sprite sheet image is set as a sprite.
You can retrieve the player animated sprite and other ones as an exclusive content on my patreon , otherwise you can use any sprite of course to use it.
As there are multiple sprites on the sheet, we set the sprite mode as “Multiple”.

you got various settings here, let’s review them a little:

  • Pixel per unit :
    This the pixel:unit ratio, i’d avoid using small units because if you  change you art style (using big hand drawn images instead of small pixels) in the middle of your project -and while prototyping you’ll be more likely doing it- it’ll be hard to adjust if you’re already on small units.
  • Texture Type :
    Full Rect
     is a single quad rendering, which you may think is nice for sprites, but results into huge overdraw, as  empty regions of the sprites are actually still rendered, consuming the GPU fill rate.
    Tight mode avoids this issue by constructing a mesh that follows the sprite edges. But you can’t control the generation of the mesh, and sometimes Unity generates more meshes than needed.
    I usually keeps the Tight mode.

Then apply the changes and enter into the “Sprite editor”.

 

00:20 Sprite editor mode

We choose “slice” to cut the sprites in multiple sprites.
Verify each sprites to be sure that the wanted sprite is contained in the box.

When clicking “Apply” we validate that each individual sprites is in its place.
In our project directory we can see that our sprite sheet is divided into smaller sprites, each with a different name.

 

00:30 Creating animation

Into the project tab, we go in our “Animation” directory, and create a new “Animation” (right-click/Create/Animation).

Note that there is no need to be in the Animation directory.
But it’s always better to keep things in the right places.
Makes it easier to retrieve things later.

Give to our animation a coherent name, here “player_idle”, then drag & drop it into our gameObject containing the sprite renderer.

By inserting an animation into a gameObject, it automatically creates an animator component named by default like the gameObject which it was inserted, rename it (here “Player_anim”).
Adding an animator into a selected object gives the animator component the access to all of the objects contained in the gameObject and its children.

 

01:05 Animation view

In our Animation window (Window/Animation), we actually see the “Player_Idle” animation steps, with currently nothing on it. We add the property “sprite” of the Sprite render component. Then we go back in our Asset project directory and drag & drop one by one our previous sliced sprites into the timeline.
Zoom in on the timeline to have a better view of the inserted sprites. We set the Samples speed to 30 fps.

The sample speed is the actual number of images that it’ll display in a second, typically a 30fps is a good rate in animation.

 

02:10 Looping animation

Then we continue to add other needed sprites; If you hit “Play” in the Animation navigate bar, you’ll notice that it will play the animation from frame 0 to frame 30 and then stops. But as an idle animation we need it to loop.
Go in the animator window, select your wanted animation state (here “player_idle”), double-click on it.
Then you’ll notice in the inspector window a new property : “Loop time”.
Just checks it and from now when the animation is finished it’ll start back to the zero frame and play again.

By playing with the animation’s navigation bar you’re able to have a better view of your in-game animation, and tweak the sprite position to give more life to it.

 

02:36 Moving animation

As our Idle animation is set, it’s time to work on the moving animation.

Onto our animation window, we can directly click on our current animation (player_idle) and see that we can choose to create a new clip; let’s create another one. A new window appears asking us to name our new animation, let’s call it “player_move”.

By saving it, our animation window is currently displaying our new “player_move” timeframe. We now just reproduce the same steps that for the creation of our player_idle anim. Add a sprite property, and drag and drop the wanted sprites into the timeline.

 

03:47 Animator states

Now let’s have a look at our Animator window; We see that we have one “Entry” state, that is linked to our “player_idle” animation state. Meaning that when the animator starts it will launch first our “player_idle” anim, and as our idle anim is a loop animation, it will play forever (for now).

We can change animation states by making transition between each animations from the animator window.

 

03:55 Animator transitions

Let’s make our first transition by right-clicking on “player_idle”, choosing “Make transition” and drag & drop the transition arrow to the “player_move” state.

As our idle animation is a loop, it will not enters directly at the end of its last frame to the move animation (hopefully because we don’t want that). We need to tell to the animator when the transition need to be executed. For this reason we’ll create a parameter (a variable).

As we want to see our moving animation when the player is actually moving, we will base our transition on our player speed variable. Meaning that if our player speed is greater than zero, is that he’s moving.

So let’s create a float parameter and name it “player_speed”.
Now by clicking on the link, we see in our inspector window a “Conditions” menu.
Add a condition by clicking on the “+”. It will automatically fills the condition with our only parameter available at the moment : player_speed.
In the condition operator just select “Greater”. We now have as condition : “player_speed parameter greater than 0”.

It should do it, if our player is moving, its speed will rise above 0; and then, our player_move animation will start.
But when we stops moving, unfortunately, our player will not going back to its idle animation a we’d like to. We’ll have to make another transition to the idle state for that.

Let’s create another transition, but this time from “player_move” state to “player_idle”.
And with the condition “player_speed is less than 0,1”.

Ho ! I almost forgot : we need to uncheck the property “Has Exit Time” in each of our transitions.
This property is located in the inspector tab of the transition arrow.
It’s made for smoothing transitions, by relying more on time than on parameters to pass from one state to another.
It helps moving from an idle 3D animation (with much more frames than 2D) to a running animation with more ease for instance.
As we’re working with 2D animations, it will just cause us more visual troubles.

 

04:52 Passing player speed

We’ll make sure our animator will see the actual player_speed, by passing it the value by script.
Let’s open our player_controller script.

We need to found our animator component, and sent our player moving speed into its player_speed parameter.
In order to get the good value all the time, we’ll pass it through the update() method.

 

//in the declaration section
//we declare our Animator component as "anim"
private Animator anim;
...
 
void Start(){
...
//we retrieve the animator component by using GetComponentINCHILDREN, because
//our player controller script is located in our main player gameObject
//and the animator component in located in a children object, remember?
anim = GetComponentInChlidren();
}
 
void Update(){
 if(canMove.Value){
 ...
//there we pass the move vector3 to the "player_speed" float of the animator.
//We use the sqrMagnitude, the squared magnitude is much faster to calculate.
//We can decompose our vector in a direction and a lenght.
//The magnitude is its length, in our case the actual player speed.
//We use it because a magnitude is always positive, meaning that even if
//the player goes to the left (which includes negative coordinates)
//the sqrMagnitude will sent a positive result, and as our animator condition
//is based on "greater than 0", it comes in handy
 anim.SetFloat("player_speed", move.sqrMagnitude);
 }
...
}

06:19 Tweaking

If you test the animation right now, you’ll notice a little lag when our player passes from one transition to another, it’s because of the transition settings.
Select a transition arrow, and reduce in the inspector view the time allowed to pass smoothly from a transition to another by dragging the little arrows.
Reduce it for all your transitions, and the animation should come instantly.

Leave a Reply