Build a 2D Top Down Game – Zero to Published – Part 2

This is a continuation from part 1.  If you have not completed part 1, please go back to part 1 and complete it as this is an addative series where each part builds on the previous part.  Part 1 covered the basics of creating a character controller that supports keyboard input and touch.  Part 2 will primarily cover animation.

Part 1:  Getting Started

Part 2: Animations

Part 3: Prefabs

Part 4: Enemies

Part 5: Modular Scripting

Part 6: Timed Prefab Instantiation

Part 7: Health Bars

Part 8: Finishing Touches

Part 9: Publishing

Wire up the Animator, Animator Controller and the Spider

  1. Select the spider.
  2. Add Component -> Miscellaneous -> Animator
  3. Navigate to your animations folder
  4. Right Click, New Animator Controller.
  5. Name the controller SpiderController
  6. Drag the Controller onto the Spider’s Animator Component’s controller block
  7. setupAnimator
  8. Make sure root motion is turned off.

Create your Idle and Run Animations

Note: Make sure the Animator, Animation and Inspector tabs are open and the spider is highlighted.  Don’t forget you can re-arrange your tabs by clicking, holding and dragging the panels around to a view that works for you.

animatorselected

  1. Select the drop down near the play button and select ‘Create New Clip”.
  2. Name the clip “SpiderIdle”.
  3. Open the project tab, find the spider and pick your favorite image of the spider to be your idle animation.
  4. Drag and drop this image onto the Animator.
  5. Set the sample to 1.

createNewAnimationClip

 

Repeat For Running

  1. Select the drop down near the play button and select ‘Create New Clip”.
  2. Name the clip “SpiderRun”.
  3. Open the project tab, find the spider.  Highlight all images and drag them on to the animator.
  4. Set the sample to 10.

Note: You can adjust sample to match your max speed better. The higher the number the faster the frames play together.

Create an animation parameter and transitions relying on it

  1. Create a float for speed.
  2. createNewAnimationClip
  3. Right click the orange SpiderIdle in the state machine.
  4. Select Make Transition.
  5. Click on “spiderRun”
  6. Do the same thing from SpiderRun to SpiderIdle.
  7. Select the transition from Idle to Running.  Set the requirement for Speed greather than .01.
  8. Select the transition from Running to Idle.  Set the requirement for Speed less than .01.

animationTransitions

Hook up your Character Script to the Animator.

We need to open up the CharacterScript we worked on in part 1 and add a cached reference to our Animator component so that we can modify the parameter we built in the animator earlier in this article.

using UnityEngine;
using System.Collections;
using System;

public class CharacterScript : MonoBehaviour
{
	//max speed of character
	public float maxSpeed = 5.0f;

	private Animator animator;
	private Rigidbody2D cachedRigidBody2D;

	void Awake()
	{
	}

	/// <summary>
	/// Initialization function that needs to interact 
	/// with other components or objects that must be 
	/// initialized prior to working with them.
	/// </summary>
	private void Start()
	{
		//cached animator
		this.animator = this.GetComponent<Animator>();

		//cached rigidbody
		this.cachedRigidBody2D = this.GetComponent<Rigidbody2D>();
	}

	public void Move(Vector2 movement)
	{
		//move the rigid body, which is part of the physics system
		//This ensures smooth movement.
		this.cachedRigidBody2D.velocity = new Vector2(movement.x * maxSpeed, movement.y * maxSpeed);

		//take the absolute value and add, because x or y 
		//may be negative and potentially cancel eachother out.
		floatspeed = Mathf.Abs(movement.x) + Mathf.Abs(movement.y);

		//set the speed variable in the animation component to ensure proper state.
		this.animator.SetFloat(“Speed”, speed);
	}
}

Make sure your spider faces the correct direction!

We need to add the following code to our character script.

Add a new public variable at the class level:

 

//adjustment for rotation based on sprite starting orientation.

public float facingAngleAdjustment = -90.0f;

Modify the Move Function to look like below:

public void Move(Vector2 movement)
{
	//move the rigid body, which is part of the physics system
	//This ensures smooth movement.
	this.cachedRigidBody2D.velocity = new Vector2(movement.x * maxSpeed, movement.y * maxSpeed);

	//take the absolute value and add, because x or y 
	//may be negative and potentially cancel eachother out.
	floatspeed = Mathf.Abs(movement.x) + Mathf.Abs(movement.y);

	//set the speed variable in the animation component to ensure proper state.
	this.animator.SetFloat("Speed", speed);

	//convert the vector into a radian angle, 
	//convert to degrees and then adjust for the 
	//spider's starting orientation
	float angle = Mathf.Atan2(movement.y, movement.x) * Mathf.Rad2Deg + facingAngleAdjustment;

	//don't rotate if we don't need to.
	if (speed>0.0f)
	{
		//rotate by angle around the z axis.
		this.cachedTransform.rotation = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1));
	}
}

Summary

We have covered animation, mechanim, and orienting characters the correct direction.  We now have a completely functional character that can move around the scene, animate and orient itself properly.  All we need now is an environment it can interact in!  We will cover those things in part 3.

22 thoughts on “Build a 2D Top Down Game – Zero to Published – Part 2

  1. Now that you hit the big time and are listed in the MSDN newsletter. You should really clean up your code and update the project to the latest version of unity. Your animation code is impossible to follow, as their doesn’t seem to be clips, and or the interface like you have.

    The code problems are you can’t copy and paste, and you double up code several times. Example: publicvoidmove(floatheading) is impossible to read/ copy/paste. Another problem is you double up on code; Here is the code, now update your code with this code which is the code I just gave you. Example is the Move function.

    Also when you call a script CharacterInputScript and CharacterScript which is a script its gets impossible to tell, in fact you made a mistake on a couple of those and had to track down which script that is a script you were talking about and made sure they lined up in code, as Unity does not like things to be named differently. Fix: Call one CharacterInput and one Character as you are already deriving a base script for your Input I believe.

    Honestly I am SUPER excited for this series as I’ve been having trouble doing a 2D game in Unity as its geared towards 3D. I’m going to power through it, but its on my years of coding experience and not the well flowing article. Clean this up and I hope you get the traffic you deserve from the mentions in websites as this looks to be a very fun series.

    • Very good valid points. I have actually just downloaded a new code formatter as the old on did a terrible job. I will hopefully be able to go back through the articles and repost with the new formatter.

  2. Create your idle and run animations: – “Make sure the Animator, Animation and Inspector tabs are open and the spider is highlighted”

    Animator (check)
    Inspector (check)
    Animation ? What’s that ? I cannot find an Animation tab :'(

    • It sounds like the animations window has not been opened and added to your editor yet. If you open Unity and go to the Windows tab on the very top bar, there should be two animation related windows available to you. Click on the Animation option and it will either create a new freestanding window that you can then dock anywhere in your editor, or it will bring the animation window to the front of whichever section it is currently docked.

      I hope that helps!

  3. Create your idle and run animations: – “Make sure the Animator, Animation and Inspector tabs are open and the spider is highlighted”

    Animator (check)
    Inspector (check)
    Animation ? What’s that ? I cannot find an Animation tab :'(

  4. Sir,

    Please check the code if it is right. When I try to build the code it says there is an error.

    (this.cachedTransform.rotation) <– error

    this.cachedTransform.rotation = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1));

    Thank you

    • Can you post the entirety of the code that you are using? Sorry this response has taken so long, the spam bots have located my blog.

  5. Sir,

    Please check the code if it is right. When I try to build the code it says there is an error.

    (this.cachedTransform.rotation) <– error

    this.cachedTransform.rotation = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1));

    Thank you

    • Can you post the entirety of the code that you are using? Sorry this response has taken so long, the spam bots have located my blog.

  6. I also get the error about cachedTransform.

    Assets/Scripts/CharacterScript.cs(57,18): error CS1061: Type `CharacterScript’ does not contain a definition for `cachedTransform’ and no extension method `cachedTransform’ of type `CharacterScript’ could be found (are you missing a using directive or an assembly reference?)

    ———-
    using UnityEngine;
    using System.Collections;
    using System;

    public class CharacterScript : MonoBehaviour
    {
    //max speed of character
    public float maxSpeed = 5.0f;

    //adjustment for rotation based on sprite starting orientation.

    public float facingAngleAdjustment = -90.0f;

    private Animator animator;
    private Rigidbody2D cachedRigidBody2D;

    void Awake()
    {
    }

    ///
    /// Initialization function that needs to interact
    /// with other components or objects that must be
    /// initialized prior to working with them.
    ///
    private void Start()
    {
    //cached animator
    this.animator = this.GetComponent();

    //cached rigidbody
    this.cachedRigidBody2D = this.GetComponent();
    }

    public void Move(Vector2 movement)
    {
    //move the rigid body, which is part of the physics system
    //This ensures smooth movement.
    this.cachedRigidBody2D.velocity = new Vector2(movement.x * maxSpeed, movement.y * maxSpeed);

    //take the absolute value and add, because x or y
    //may be negative and potentially cancel eachother out.
    float speed = Mathf.Abs(movement.x) + Mathf.Abs(movement.y);

    //set the speed variable in the animation component to ensure proper state.
    this.animator.SetFloat(“Speed”, speed);

    //convert the vector into a radian angle,
    //convert to degrees and then adjust for the
    //spider’s starting orientation
    float angle = Mathf.Atan2(movement.y, movement.x) * Mathf.Rad2Deg + facingAngleAdjustment;

    //don’t rotate if we don’t need to.
    if (speed > 0.0f)
    {
    //rotate by angle around the z axis.
    this.cachedTransform.rotation = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1));
    }
    }
    }

    • Hi Morris,

      It looks like in the code sample the private value cachedTransform was left off as a variable in that class. To fix your particular instance, you will need to add two things to the code:
      At the class level
      private Transform cachedTransform;

      Inside the method private void Start(){} add:
      this.cachedTransform = this.gameObject.Transform;

      Where did you find this section of code? I went back to Part 2 and noticed this sample is not from there. I need to go fix the location in which this code came from.

      Thanks,
      ~David

  7. I also get the error about cachedTransform.

    Assets/Scripts/CharacterScript.cs(57,18): error CS1061: Type `CharacterScript’ does not contain a definition for `cachedTransform’ and no extension method `cachedTransform’ of type `CharacterScript’ could be found (are you missing a using directive or an assembly reference?)

    ———-
    using UnityEngine;
    using System.Collections;
    using System;

    public class CharacterScript : MonoBehaviour
    {
    //max speed of character
    public float maxSpeed = 5.0f;

    //adjustment for rotation based on sprite starting orientation.

    public float facingAngleAdjustment = -90.0f;

    private Animator animator;
    private Rigidbody2D cachedRigidBody2D;

    void Awake()
    {
    }

    ///
    /// Initialization function that needs to interact
    /// with other components or objects that must be
    /// initialized prior to working with them.
    ///
    private void Start()
    {
    //cached animator
    this.animator = this.GetComponent();

    //cached rigidbody
    this.cachedRigidBody2D = this.GetComponent();
    }

    public void Move(Vector2 movement)
    {
    //move the rigid body, which is part of the physics system
    //This ensures smooth movement.
    this.cachedRigidBody2D.velocity = new Vector2(movement.x * maxSpeed, movement.y * maxSpeed);

    //take the absolute value and add, because x or y
    //may be negative and potentially cancel eachother out.
    float speed = Mathf.Abs(movement.x) + Mathf.Abs(movement.y);

    //set the speed variable in the animation component to ensure proper state.
    this.animator.SetFloat(“Speed”, speed);

    //convert the vector into a radian angle,
    //convert to degrees and then adjust for the
    //spider’s starting orientation
    float angle = Mathf.Atan2(movement.y, movement.x) * Mathf.Rad2Deg + facingAngleAdjustment;

    //don’t rotate if we don’t need to.
    if (speed > 0.0f)
    {
    //rotate by angle around the z axis.
    this.cachedTransform.rotation = Quaternion.AngleAxis(angle, new Vector3(0, 0, 1));
    }
    }
    }

    • Hi Morris,

      It looks like in the code sample the private value cachedTransform was left off as a variable in that class. To fix your particular instance, you will need to add two things to the code:
      At the class level
      private Transform cachedTransform;

      Inside the method private void Start(){} add:
      this.cachedTransform = this.gameObject.Transform;

      Where did you find this section of code? I went back to Part 2 and noticed this sample is not from there. I need to go fix the location in which this code came from.

      Thanks,
      ~David

  8. Hi,
    This is some great stuff to follow. There are actually a few errors in te code, i’m not sure if its purposeful to keep us on our toes(and has sure taught me a fair amount to look out for).

    In the Character Script there is a ‘floatspeed’ which should actually be ‘float speed’
    You also need to add what you have said here in the comments which it doesnt have in the actual walkthrough. Although in the comment it says ‘this.cachedTransform = this.gameObject.Transform;’ which didn’t work for me, the second ‘transform’ needs to be lower case.

    Thanks for great tuts.

  9. Hi,
    This is some great stuff to follow. There are actually a few errors in te code, i’m not sure if its purposeful to keep us on our toes(and has sure taught me a fair amount to look out for).

    In the Character Script there is a ‘floatspeed’ which should actually be ‘float speed’
    You also need to add what you have said here in the comments which it doesnt have in the actual walkthrough. Although in the comment it says ‘this.cachedTransform = this.gameObject.Transform;’ which didn’t work for me, the second ‘transform’ needs to be lower case.

    Thanks for great tuts.

  10. Pingback: Build a 2D Top Down Game – Zero to Published – Part 9 | DaCrook

Leave a Reply

Your email address will not be published. Required fields are marked *