Home

Tutorial 4: 2D Platform Game — Part 1

Welcome! In this tutorial, we’ll build a simple 2D platformer using the Unity engine. You don’t need to be a pro — we’ll guide you through each step in a clear, friendly way. We’ll use Unity’s built-in 2D physics and also dip our toes into animations (hello, sprite sheets!). To follow along, you’ll need a few assets: images, sounds, and more. Download the .zip archive here — it's everything you need to get started.

Step 1. Ground and Player Setup

Start Unity and create a new 2D project. Then we’ll build the foundation of the game: a ground object and the player.

First, import largeGround from the archive (download here if needed). Unpack the .zip and drag largeGround into the scene. Rename the new GameObject to Ground.

Select Ground in the Hierarchy. In the Inspector:

Now let’s add the player. Import the ratIdle sprite sheet (from the same archive). Unity will likely slice it automatically. If not, do the following:

Expand the sprite sheet — it should now have 20 frames. Drag the first frame into the scene. Rename the new GameObject to Rat.

Select the Rat GameObject and make these changes:

Unity scene with Ground and Rat setup
Scene with Ground and Rat.

Step 2. Moving and Jumping

It’s time to make our rat move! Let’s create a new script that handles both running and jumping.

In the Assets folder, right-click and create a new C# script. Name it PlayerMove. This script will use Rigidbody2D to move the player using built-in physics. We’ll also add jump support by applying force on the Y-axis.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    // Which layers count as "ground" (set this in Inspector)
    public LayerMask whatIsGround;

    // Position used to check if the player is standing on ground
    public Transform groundCheck;

    // Is the player currently on the ground?
    public bool isGrounded;

    // How high the player jumps
    public float jumpForce;

    // How fast the player moves left/right
    public float speed;

    // Reference to the Rigidbody2D component
    Rigidbody2D rb;

    void Start()
    {
        // Get the Rigidbody2D component attached to this object
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // If Jump button is pressed and the player is on the ground
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            // Add force upward to jump
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
            // Prevent double jumping — will be reset in FixedUpdate
            isGrounded = false;
        }
    }

    void FixedUpdate()
    {
        // Check if GroundCheck touches ground layer
        isGrounded = Physics2D.OverlapPoint(groundCheck.position, whatIsGround);

        // Get horizontal input (left/right or A/D)
        float x = Input.GetAxis("Horizontal");

        // Build movement vector (keep vertical speed)
        Vector3 move = new Vector3(x * speed, rb.linearVelocity.y, 0f);

        // Apply it to the Rigidbody
        rb.linearVelocity = move;
    }
}

Attach the PlayerMove script to the Rat GameObject. In the Inspector, set Speed to 3 and Jump Force to 5.

Now create a child object to help detect the ground. Right-click on the Rat in the Hierarchy → Create Empty, rename it to GroundCheck, and move it just below the rat's feet (but outside its collider).

To make jumping work, we also need to define what the “ground” is. Select the Ground object and set its Layer to Ground. If you don’t see this layer, create a new one with that name first.

Now select Rat again. In the PlayerMove component:

💡 Tip: If the Ground layer doesn’t appear in the list, make sure you’ve selected the ground object and added a layer named Ground to it.

Press Play — the rat should now move left/right (with arrow keys or A/D) and jump when on the ground.

Unity inspector with PlayerMove script setup and GroundCheck under Rat
PlayerMove script configured on Rat.

Step 3. Facing the Right Direction

The rat can now move and jump — but it always looks in one direction. Let’s make it turn based on movement input. To do this, we’ll add a new variable to our script and create a function that flips the player’s sprite when the direction changes.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove : MonoBehaviour
{
    // Which layers count as "ground" (set this in Inspector)
    public LayerMask whatIsGround;

    // Position used to check if the player is standing on ground
    public Transform groundCheck;

    // Is the player currently on the ground?
    public bool isGrounded;

    // How high the player jumps
    public float jumpForce;

    // How fast the player moves left/right
    public float speed;

    // Reference to the Rigidbody2D component
    Rigidbody2D rb;

    // Controls which direction the rat is currently facing
    public bool isLookingLeft;

    void Start()
    {
        // Get the Rigidbody2D component attached to this object
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // If Jump button is pressed and the player is on the ground
        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            // Add force upward to jump
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
            // Prevent double jumping — will be reset in FixedUpdate
            isGrounded = false;
        }
    }

    void FixedUpdate()
    {
        // Check if GroundCheck touches ground layer
        isGrounded = Physics2D.OverlapPoint(groundCheck.position, whatIsGround);

        // Get horizontal input (left/right or A/D)
        float x = Input.GetAxis("Horizontal");

        // Build movement vector (keep vertical speed)
        Vector3 move = new Vector3(x * speed, rb.linearVelocity.y, 0f);

        // Apply it to the Rigidbody
        rb.linearVelocity = move;

        // If moving left and not already facing left — flip
        if (x < 0 && !isLookingLeft)
    TurnTheRat();

        // If moving right and currently facing left — flip
        if (x > 0 && isLookingLeft)
    TurnTheRat();
    }

    // Flip the rat by inverting its X scale
    void TurnTheRat()
    {
        // Flip the direction flag
        isLookingLeft = !isLookingLeft;

        // Flip the sprite visually
        transform.localScale = new Vector3(
            transform.localScale.x * -1,
            transform.localScale.y,
            transform.localScale.z
        );
    }
}

Select the Rat object in the Hierarchy. In the PlayerMove script component, enable the checkbox Is Looking Left — this should match the initial orientation of the sprite (if your rat faces left by default).

That’s it! Now the rat moves, jumps, and turns to face the direction it’s running. A tiny touch — but it brings the whole scene to life.

Step 4. Preparing for Animation

Let’s start animating our rat! First, we need to add an Animator component and create a controller.

In the Hierarchy, select the Rat GameObject. In the Inspector, click Add Component and choose Animator.

Then, go to the Assets window, right-click and create a new Animator Controller. Name it RatAnimator.

Finally, assign the RatAnimator controller to the Controller field in the Animator component on the Rat GameObject.

Animator component and controller assigned to Rat
Animator added to Rat, and RatAnimator controller assigned.

Step 5. Creating the Idle Animation

Let’s bring the rat to life with its first animation — the idle loop.

Open the Animation window if it’s not already visible. You can enable it via Window → Animation → Animation and dock it wherever you like (I’ve placed it above the Assets window).

Select Rat in the Hierarchy. In the Animation window, click Create and save the new animation as IdleRatAnimation.

Now let’s add frames from the sprite sheet. In the Assets window, expand ratIdle. Select all 20 frames: click the first frame, then hold Shift and click the last one. Drag the selected frames into the Animation timeline.

Open the Animator window (Window → Animation → Animator) if it’s not already visible. Double-click the IdleRatAnimation state — or click on it directly in the Assets.

In the Inspector panel, make sure Loop Time is enabled. You can also adjust the Speed of the animation — for example, try setting it to 0.5 to make the movement smoother.

IdleRatAnimation setup in Unity Animator and Animation windows
IdleRatAnimation added to Animator and set to loop. Animation speed set to 0.5 for smoother playback.

Step 6. Creating the Run Animation and Transitions

Time to animate the rat's movement! Let’s create a running animation and set up transitions.

First, import the ratRun sprite from the archive into the Assets folder.

Select Rat in the Hierarchy. In the Animation window, click on the dropdown next to IdleRatAnimation and choose Create New Clip. Name the new animation RunRatAnimation.
(Make sure Rat is selected in the Hierarchy, or Unity won’t allow adding a new animation.)

In the Assets, expand ratRun and select all 20 frames: click the first, hold Shift, and click the last. Drag all selected frames into the Animation window to populate the timeline.

Now open the Animator window. If you don’t see it, enable it from Window → Animation → Animator.

By default, IdleRatAnimation is the starting state. We’ll create a float parameter to control transitions between idle and run.

Now configure the transitions:

Animator transitions between Idle and Run with Speed parameter
Animator transitions and Speed parameter. Remember to disable Has Exit Time and set the correct conditions.

Step 7. Switching Animations in Code

To control the animation transitions, we’ll create a simple script that passes movement information to the Animator. This will switch between Idle and Run based on the rat’s velocity.

In the Assets folder, create a new C# script and name it PlayerAnim. Then paste the following code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnim : MonoBehaviour
{
    // Reference to Animator
    Animator anim;

    // Reference to Rigidbody2D
    Rigidbody2D rb;

    void Start()
    {
        anim = GetComponent<Animator>();
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // Update Animator with the current speed (absolute value of horizontal velocity)
        anim.SetFloat("Speed", Mathf.Abs(rb.linearVelocity.x));
    }
}

Attach the PlayerAnim script to the Rat GameObject.

That’s it! Now when you run the scene, the rat will automatically switch between idle and running animations based on movement.

Step 8. Adding a Jump Animation

Let's create a jump animation for our rat. We don’t have a dedicated jump sprite, but we can reuse the ratRun sprites at a slower speed to simulate a jumping motion.

Select the Rat in the Hierarchy. In the Animation window, click the dropdown and select Create New Clip. Name the new animation JumpRatAnimation.

In the Assets, expand the ratRun sprite sheet. Select all 20 frames (first frame → hold Shift → last frame), then drag & drop them into the Animation timeline.

Now open the Animator window. We’ll add a new animation parameter and connect the jump logic.

Configure the transitions as follows:

Finally, select the JumpRatAnimation state and set its Speed to 0.2 to make the run-like animation look like a jump.

Animator window with jump animation and transitions configured
JumpRatAnimation added with transitions. Speed set to 0.2, condition isJumping controls the animation flow.

Step 9. Jump Detection in Code

Now we’ll connect the jump animation to the actual state of the rat. We’ll do this by accessing the isGrounded variable from the PlayerMove script. If the rat is not on the ground (including when falling), we’ll trigger the jump animation.

Open the PlayerAnim script and update it like this:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnim : MonoBehaviour
{
    // Reference to the Animator component
    Animator anim;

    // Reference to the Rigidbody2D component
    Rigidbody2D rb;

    // Reference to the PlayerMove script (to access isGrounded)
    PlayerMove pm;

    void Start()
    {
        // Get the Animator component on this GameObject
        anim = GetComponent<Animator>();

        // Get the Rigidbody2D component
        rb = GetComponent<Rigidbody2D>();

        // Get the PlayerMove script
        pm = GetComponent<PlayerMove>();
    }

    void Update()
    {
        // If the rat is on the ground
        if (pm.isGrounded)
        {
            // Not jumping anymore
            anim.SetBool("isJumping", false);

            // Set Speed to current horizontal movement
            anim.SetFloat("Speed", Mathf.Abs(rb.linearVelocity.x));
        }
        else
        {
            // While jumping or falling, set Speed to 0
            anim.SetFloat("Speed", 0);

            // Trigger jump animation
            anim.SetBool("isJumping", true);
        }
    }
}

That’s all — no extra setup needed. Now the jump animation will automatically play whenever the rat is in the air — either jumping up or falling down.

Step 10. Adding Footstep Sounds

Now let’s add a bit of life to the rat — we’ll make it play footstep sounds while running. This will be done using an animation event that triggers a function from a new script.

In the Assets folder, create a new C# script and name it PlayerSound. Add the following code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSound : MonoBehaviour
{
    // The audio clip for footsteps
    public AudioClip footsteps;

    // Public function to play the sound — called from animation event
    public void FootStepsAudio()
    {
        // Play the sound at the rat’s position
        AudioSource.PlayClipAtPoint(footsteps, transform.position);
    }
}

Select the Rat object in the Hierarchy and add the PlayerSound script to it. Then import the ratStep sound from the archive, and assign it to the Footsteps field in the component.

Now switch to the Animation window and select RunRatAnimation. Choose a frame where a footstep should happen and click Add Event in the timeline. In the Inspector (right panel), set the function to FootStepsAudio().

Animation Event added to RunRatAnimation with FootStepsAudio function
Animation Event calling the FootStepsAudio() function during RunRatAnimation.

That’s it! When the rat reaches that frame during running, it will now play a footstep sound. You can add multiple events to sync with each step.

Step 11. Duplicating Platforms and Camera Follow

Let’s expand the level slightly and set up the camera to follow the rat. This will give us more room for testing and prepare us for the next part.

First, turn the original ground into a prefab. Select Ground in the Hierarchy and drag it into the Assets folder to create a prefab.

Now drag the prefab back into the scene a few times to create more platforms. Position them at different horizontal (and optionally vertical) positions to create a jumping challenge.

Then, select the Main Camera in the Hierarchy and drag it onto the Rat object. This makes the camera a child of the rat, so it will follow the rat as it moves.

You can optionally set the camera’s X-position to 0 in the Transform, to keep the movement smoother and centered during flips.

Scene with duplicated platforms and camera following the rat
Scene extended with multiple platforms. Camera made a child of the rat for automatic following.

That’s it — the first part is complete! You now have a moving, jumping, animated rat with sound, camera tracking, and an extended level to explore.