Skip to main content

Creating 2D Animation For A Side Scroller In Unity3D

Update 3-13-14
Unity kinda released some really nice 2D tools, I really don't know how relevant or helpful this is now.

I've been working on a 2D side scroller. Being my cheap self I'm not going to bother buying some helpful tool that would probably speed up everything a substantial amount, and created my own method of 2D animation for things in Unity3D. This code does not work with a sprite sheet, but I hope it makes it easy enough for you to incorporate one if you wanted to.

Warnings:
 The animation is displayed by updating the meshes material's texture each frame (this can mess up at high frame speeds).
This code is assuming the 2D sprites are moving along the X and Y axis.
When changing directions, it is scaling the transform negatively across it's x axis.
Its assuming default direction facing is right.


 using UnityEngine;  
 using System.Collections;  
   
 public enum Directions{left,right}  
 public class FlatCharacterAnimation : MonoBehaviour {  
        
      public FlatAnimation[] animations;  
        
      public string defaultAnimation;  
        
        
      FlatAnimation currentAnimationPlaying;  
        
      string animationCurrentlyPlaying = "";  
      Texture2D[] framesToPlay;  
      float frameSpeed;  
      int currentFrame = 0;  
      Directions directionCharactersFacing = Directions.right;  
      bool animationIsPlaying;  
        
      #region FlatAnimationClass  
      [System.Serializable]  
      public class FlatAnimation{  
           public string name ="";       
           public Texture2D[] frames;  
           public float frameSpeed;  
             
           public Texture2D[] GetFrames(){  
                return frames;  
           }  
        
             
      }  
      #endregion  
        
      public Directions GetDirectionFacing(){  
           return directionCharactersFacing;       
      }  
        
        
      public void Play(string animation){  
           if(animation != animationCurrentlyPlaying){  
                ChangeAnimation(GetAnimation(animation));  
                animationIsPlaying = true;  
           }  
      }  
        
      public void Play(string animation, Directions direction){  
           if(animation != animationCurrentlyPlaying){  
                ChangeAnimation(GetAnimation(animation));  
                animationIsPlaying = true;  
           }  
             
           if(direction != directionCharactersFacing)               //make sure players facing right direction, if not, changes direction  
                ChangeDirectionPlayersFacing(direction);  
      }  
        
      FlatAnimation GetAnimation(string animationName){  
           for(int i = 0; i < animations.Length; i++){  
                  
                if(animations[i].name == animationName){  
                     return animations[i];  
                }   
           }  
           Debug.LogWarning("The animation you are trying to play does not exist! Try checking spelling and capitalization");  
   
           return null;  
      }  
        
   
        
      void ChangeAnimation(FlatAnimation newAnimation){  
           animationCurrentlyPlaying = newAnimation.name;  
           framesToPlay = newAnimation.frames;  
           frameSpeed = newAnimation.frameSpeed;  
           currentFrame = 0;  
      }  
        
      void ChangeDirectionPlayersFacing(Directions direction){  
           Vector3 scale;  
           directionCharactersFacing = direction;  
           switch(direction){  
                case Directions.left:  
                     //Debug.Log("Left Direction");  
                     scale = gameObject.transform.localScale;  
                     scale.x *= -1;  
                     gameObject.transform.localScale = scale;  
                break;  
                  
                case Directions.right:  
                     //Debug.Log("Left Direction");  
                     scale = gameObject.transform.localScale;  
                     scale.x *= -1;  
                     gameObject.transform.localScale = scale;  
                break;  
                  
           }  
      }  
        
      float nextFrameTime;  
      void UpdateAnimation(){  
             
           if(nextFrameTime < Time.time &&framesToPlay != null){  
                //Debug.Log ("current frame: " + currentFrame + "currentAnimationFrames Legth: "+currentAnimationFrames.Length);  
                nextFrameTime = frameSpeed+Time.time;  
                if(currentFrame == framesToPlay.Length-1){  
                     currentFrame = 0;  
                } else if(currentFrame < framesToPlay.Length){  
                     currentFrame += 1;  
                }  
                gameObject.GetComponent<MeshRenderer>().material.mainTexture = framesToPlay[currentFrame];  
                  
           }  
      }  
        
      // Use this for initialization  
      void Start () {  
        
      }  
        
      // Update is called once per frame  
      void Update () {  
           if (animationIsPlaying){  
                UpdateAnimation();       
           }  
      }  
 }  


Setting this up:

Its more than just dragging and dropping the script, but it doesn't take much time. To begin, in case any of you still have graphics and code on the same Game Object, stop it, please. To create your graphics object for this, you can do it three ways.
  1. Create a Primitive Cube. Use this method if your shader for the material is going to ignore light. Scale one of the axis to 0. Reasons for creating a cube over a plane is that a cube has fewer faces than the default plane for some reason in unity. The shader you would use for this on the material would be Unlit>Transparent.
  2. Create a Primitive  Plane. Use this method if your material will not ignore light. This method will have more faces, but in most cases it will not be considered to serious. Make sure the y axis stays 1. The shader you would use on the material for this option would be Transparent/Cutout/YourOption
  3. Create Your Own Object To Render It. Takes time, more faces than a cube usually, but can be less faces that a plane.
If your developing for a mobile device, consider using option 1. Not so much for the poly count, but for the shader. Unlit shaders take less power to process.

In my example I'm going to be using option 2, and these are the steps.
  1. Create an Empty Game Object (Cntrl+Shift+N), and rename Enemy
  2. Create a Primitive Plane and parent it to Enemy. Rename Plane to graphics.
  3. Set rotations on plane to (90, 180, 0),  
  4. Add Flat Character Animation (Script Above) to graphics object.
  5. Re-size Animations Size to however animations you need.
  6. For each animation, set the name(IMPORTANT), frames, and Frame Speed.
Frame speed works in reverse to frame rate, don't get these confused. If you want the frame rate to be 30 seconds, set the frame speed to .033 (1/30).

Frames are the individual pictures you want to play in sequence for the animation.

To play the animation, grab the instance of the flat character animation, and call either Play(string nameOfAnimation); or Player(string nameOfAnimation, Directions, directionToFace);

Example of the Inspector


Example of the Object in the scene


Check out the game this code was made for!
Treva's Adventure Web game

Comments

Popular posts from this blog

How To Make a Hellish Looking Sky Box

I came across this problem while constructing my scene of Hell in a little project I've been working on, and could not find a reasonable sky box on the web for what I want. Maybe I was not looking hard enough, but I ended up making nice substitute. If you think the sky box looks familiar, then your right. The Sky box I'm using is already packaged with Unity3D! To import the sky boxes Unity has made for you,  simply go to Assets>Import Package>Skyboxes.  The sky boxes will appear in your projects tab under a folder named "Standard Assets". To make this sky box, first you must find the folder containing all the sky box materials and open it up. In it will be a list of sky boxes for your disposal. To get this skybox, I decided to tweak the "StarryNight Skybox" (But the "MoonShine Skybox" looks pretty cool also!).  Select the sky box and view it under the inspector tab. Underneath the properties there will be a tint color variable allowin...

How To Make A Gun Shot Sound (SFX On Unity 3D)

When it comes to audio in Unity, there are four components: Audio Clip , Audio Source , Audio Listener , and Audio Re-verb Zone . Audio Clips are the actual audio file imported into your game. Unity supports file formats: .aif, .wav, .mp3, and .ogg. When imported, you can compress them greatly, with the price of loosing some quality. You can do this by first selecting the audio clip, view it in the inspector. Under the Audio Importer component, you can switch the audio format from Native to the audio clip, to a compressed format applied by Unity. You can change how compressed the file is by dragging the bar at the bottom, then hitting apply. You can get plenty of free good SFX from a site called  freesound.org . All you have to do is create an account for free , and download all the sounds you want. I found a nice gun shot sound here . Simply download and load into your Project. Audio Source actually plays the audio clip in your scen...

Handling Music and Sound Effects In Your Games

Initiative  While developing Treva's Adventure I had to figure out a way to handle multiple music tracks and sound effects in a clean manner or suffer horribly.  What was going to help me achieve a simple solution was taking all the different sounds and centralizing them in a single class in order to black box them.   Any other code trying to play a sound wouldn't even know the sound file's name.   All code trying to play a music track would reference a enum that defines all the track names. Defining The Class Creating The Enum When I first started defining types in my enumeration,  I was naming the types to be exactly like the file name.  For a scary sound effect I had found a file named "ghost breath".  So around my code would be scattered lines like SoundManager.Play(SoundEffectType.GhostBreath);  This was fine until I found a sound that better fit the situation it was being used in,  and decided to use "ghost breath" for a...