2D Game Design Workshop - Part 1

Unity Fundamentals: Movement, Physics, and Collisions

Lucas P. Cordova, Ph.D.

Willamette University

Workshop Overview

In this three-part series, you’ll learn the fundamentals of 2D game development in Unity. By the end of Part 1, you’ll have created a simple car game with movement controls, physics interactions, and a dynamic camera system.

Learning Objectives

By completing Part 1, you will:

  • Set up a Unity 2D project with proper layout
  • Understand sprites, transforms, and their properties
  • Create and attach MonoBehaviour scripts
  • Implement frame-rate independent movement using Time.deltaTime

Step 1: Create Your Unity 2D Project

Creating Your Unity 2D Project

  1. Open Unity Hub and click the “New Project” button
  2. Select the 2D (Core) template from the available options
  3. Name your project “2DCarGame_Part1”
  4. Choose a save location that you can easily find later
  5. Set Unity Version to 6.0 or your latest LTS version
  6. Click “Create Project” and wait for Unity to initialize

Step 2: Configure Your Workspace

Optimizing for 2D Development

  1. Select the Tall Layout:
    • Go to Window → Layouts → Tall
    • This gives you more vertical space for the Scene view
  2. Rearrange the Game View:
    • Click and drag the “Game” tab
    • Drop it at the bottom of the Unity interface
    • This allows you to see both Scene and Game views simultaneously
  3. Adjust the Scene View for 2D:
    • Click the “2D” button in the Scene view toolbar
    • Set the camera to orthographic view if not already

Pro Tip

Save your custom layout by going to Window → Layouts → Save Layout. Name it “2D Development” for easy access in future projects.

Step 3: Create Your Car Sprite

Adding the Capsule Sprite

  1. In the Hierarchy panel, right-click in empty space

  2. Navigate to 2D Object → Sprites → Capsule

  3. A capsule sprite will appear in your scene

  4. Rename the GameObject:

    • Select the Capsule in the Hierarchy
    • Press F2 (or right-click → Rename)
    • Type “Car” and press Enter

Step 4: Position and Customize Your Car

Positioning Your Car

  1. Select the Car GameObject in the Hierarchy

  2. In the Inspector, reset the Transform:

    • Click the three dots menu on the Transform component
    • Select “Reset”
  3. Your car should now be at position (0, 0, 0)

Visual Customization

You can change the car’s color by:

  1. Selecting the Car in the Hierarchy
  2. In the Inspector, find the Sprite Renderer component
  3. Click the Color property and choose your preferred color

Step 5: Understanding Transform Properties

Transform Component Basics

The Transform component is fundamental to all GameObjects in Unity. Let’s explore its three main properties:

  • Controls the GameObject’s location in 3D space
  • Uses X, Y, and Z coordinates
  • In 2D games, we primarily use X (horizontal) and Y (vertical)
  • Z is typically used for layering (what appears in front/behind)
  • Defines the GameObject’s orientation
  • In 2D, we mainly use Z rotation (rotating around the Z-axis)
  • Measured in degrees (0-360)
  • Positive values rotate counter-clockwise
  • Determines the size of the GameObject
  • Default is (1, 1, 1) for original size
  • (2, 2, 1) would double the width and height
  • Keep Z scale at 1 for 2D objects

Step 6: Practice with Transform

Hands-On Transform Practice

Try these experiments with your Car selected:

  1. Position: Change X to 3, notice the car moves right
  2. Rotation: Change Z to 45, see the car rotate
  3. Scale: Change X and Y to 2, observe the car doubles in size
  4. Reset the Transform when done experimenting

Step 7: Enable the Input System

Switching to Modern Input

Why the New Input System?

The new Input System provides better performance, flexibility, and support for multiple input devices compared to the legacy system. It is recommended for all new projects. While both are supported, we will use the new Input System in this workshop and in the class. Setting the project to support both systems ensures compatibility with older assets.

  1. Open Project Settings:

    • Edit → Project Settings
  2. Navigate to Player:

    • In the left panel, select “Player”
  3. Under Configuration:

    • Find “Active Input Handling”
    • Set it to “Input System Package (New)” or “Both”
  4. Unity will prompt to restart - click “Yes”

Step 8: Create the Movement Script

Creating a MonoBehaviour Script

  1. In the Project panel, navigate to the Assets folder
  2. Right-click in empty space within Assets
  3. Select Create → MonoBehaviour Script
  4. Name the script “Cruise” (press Enter to confirm)
  5. Wait for Unity to compile the new script

Attaching the Script to Your Car

  1. Select the Car GameObject in the Hierarchy
  2. Drag the Cruise script from the Project panel onto the Car in the Inspector
    • Alternatively: Click “Add Component” and search for “Cruise”
  3. You should now see the Cruise component in the Inspector

Step 9: Basic Script Structure

Setting Up the Script

Double-click the Cruise script to open it in your code editor. Replace the default code with:

using UnityEngine;
using UnityEngine.InputSystem;

public class Cruise : MonoBehaviour
{
    // Movement variables will go here
    
    void Update()
    {
        // Movement code will go here
    }
}

New Input System

We’re using Unity’s new Input System (UnityEngine.InputSystem) which provides better performance and more flexibility than the legacy input system. It also allows us to easily support multiple input devices.

Step 10: Add Movement Variables

Adding SerializeField Variables

Update your Cruise script with these movement variables:

using UnityEngine;
using UnityEngine.InputSystem;

public class Cruise : MonoBehaviour
{
    [SerializeField] float moveSpeed = 1f;
    [SerializeField] float steerSpeed = 5f;
    
    void Update()
    {
        // Movement code coming next
    }
}

Step 11: Understanding SerializeField

Understanding [SerializeField]

[SerializeField] makes private variables visible in the Unity Inspector, allowing you to:

  • Adjust values without recompiling code
  • Test different settings quickly
  • Keep variables private while still being editable
  • See real-time value changes during play mode

Our Variables:

  • moveSpeed: Controls how fast the car moves forward/backward (units per frame, will be adjusted with deltaTime)
  • steerSpeed: Controls how fast the car rotates (degrees per frame, will be adjusted with deltaTime)

Step 12: Implement Basic Movement

Adding Keyboard Controls

Update your Cruise script with the movement code:

using UnityEngine;
using UnityEngine.InputSystem;

public class Cruise : MonoBehaviour
{
    [SerializeField] float moveSpeed = 1f;
    [SerializeField] float steerSpeed = 5f;

    void Update()
    {
        float move = 0f;
        float steer = 0f;

        // Forward movement (W or Up Arrow)
        if (Keyboard.current.wKey.isPressed || Keyboard.current.upArrowKey.isPressed)
        {
            move = 1f;
        }
        // Backward movement (S or Down Arrow)
        else if (Keyboard.current.sKey.isPressed || Keyboard.current.downArrowKey.isPressed)
        {
            move = -1f;
        }

        // Left steering (A or Left Arrow)
        if (Keyboard.current.aKey.isPressed || Keyboard.current.leftArrowKey.isPressed)
        {
            steer = 1f;
        }
        // Right steering (D or Right Arrow)
        else if (Keyboard.current.dKey.isPressed || Keyboard.current.rightArrowKey.isPressed)
        {
            steer = -1f;
        }

        // Apply movement and rotation (without deltaTime for now)
        transform.Translate(0, move * moveSpeed, 0);
        transform.Rotate(0, 0, steer * steerSpeed);
    }
}

Step 13: Understanding the Input Code

Key Components

Understanding the Input System Code:

  • Keyboard.current: References the current keyboard device
  • .isPressed: Returns true while the key is held down
  • We support both WASD and arrow keys for accessibility

Step 14: Test Your Movement

Testing Your Controls

  1. Save your script (Ctrl/Cmd + S)

  2. Return to Unity and wait for compilation

  3. Press Play button to enter Play Mode

  4. Test both control schemes:

    • W or ↑: Move forward
    • S or ↓: Move backward
    • A or ←: Turn left
    • D or →: Turn right
  5. Note: Both WASD and arrow keys work, so players can use their preferred control scheme

Movement Speed Issue

You’ll notice the car moves VERY fast! This is because movement is happening every frame (30-120 times per second). We’ll fix this in the next step with Time.deltaTime.

Step 15: Understanding Frame Rate Dependence

The Problem with Frame-Dependent Movement

Without Time.deltaTime:

  • A computer running at 30 FPS moves the car slower
  • A computer running at 120 FPS moves the car 4x faster
  • Game becomes unplayable across different devices

Step 16: What is Time.deltaTime?

Making Movement Frame-Independent

Time.deltaTime represents the time in seconds since the last frame:

  • At 60 FPS: ~0.0167 seconds per frame
  • At 30 FPS: ~0.0333 seconds per frame
  • Multiplying movement by deltaTime ensures consistent speed regardless of frame rate

Step 17: Implement Time.deltaTime

Update Your Movement Code

Update your Cruise script to include Time.deltaTime. This will need to be adjusted later when we change speed values:

using UnityEngine;
using UnityEngine.InputSystem;

public class Cruise : MonoBehaviour
{
    [SerializeField] float moveSpeed = 5f;
    [SerializeField] float steerSpeed = 100f;

    void Update()
    {
        float move = 0f;
        float steer = 0f;

        if (Keyboard.current.wKey.isPressed || Keyboard.current.upArrowKey.isPressed)
        {
            move = 1f;
        }
        else if (Keyboard.current.sKey.isPressed || Keyboard.current.downArrowKey.isPressed)
        {
            move = -1f;
        }

        if (Keyboard.current.aKey.isPressed || Keyboard.current.leftArrowKey.isPressed)
        {
            steer = 1f;
        }
        else if (Keyboard.current.dKey.isPressed || Keyboard.current.rightArrowKey.isPressed)
        {
            steer = -1f;
        }

        // Calculate frame-independent movement
        float moveAmount = move * moveSpeed * Time.deltaTime;
        float steerAmount = steer * steerSpeed * Time.deltaTime;

        // Apply movement and rotation
        transform.Translate(0, moveAmount, 0);
        transform.Rotate(0, 0, steerAmount);
    }
}

Step 18: Adjust Speed Values

Setting Appropriate Speeds

With Time.deltaTime, you’ll need to increase your speed values:

  1. Select your Car in the Hierarchy

  2. In the Inspector, find the Cruise component

  3. Set new values:

    • Move Speed: 5 (units per second)
    • Steer Speed: 100 (degrees per second)

Testing Frame Independence

To verify frame independence is working:

  1. In Play Mode, open the Stats window (click “Stats” in Game view)
  2. Note your FPS
  3. Go to Edit → Project Settings → Quality
  4. Change VSync Count between “Don’t Sync” and “Every V Blank”
  5. Your car should move at the same speed regardless of FPS changes