Skip to content
Learni
View all tutorials
Unity

How to Create Your First 2D Unity Game in 2026

Lire en français

Introduction

Unity is the most popular game engine for beginners and pros, powering over 50% of mobile games in 2026. This tutorial guides you step-by-step to create your first 2D game: a blue square (player) that moves with arrow keys, collects yellow coins (+1 score), and displays the total at the top. No fluff: we install, code, and test. At the end, you'll have a playable executable. Why is this crucial? Unity handles physics, rendering, and multi-platform builds without boilerplate. Think of it like assembling a puzzle: the scene is your board, scripts are your moving pieces. Estimated time: 45 min. Ready to ship your first game?

Prerequisites

  • Unity Hub 3.10+ (download from unity.com)
  • Unity Editor 2023.2 LTS or 6000.0 (via Hub)
  • Basic C# knowledge (variables, if/else)
  • Recent Windows/Mac/Linux
  • VS Code or Visual Studio (for editing scripts)

Install Unity and Create the Project

terminal-install.sh
# 1. Download Unity Hub from unity.com
# 2. Install Unity Editor 2023.2 LTS via Hub > Installs > Add
# 3. Create project:
unityhub://2023.2.20f1/2d/core
# Or via Hub interface: New Project > 2D Core Template > Name: 'MyFirstGame' > Create

These commands/instructions launch Unity Hub to install the stable LTS editor and create an optimized 2D template (orthographic camera, ready UI Canvas). Avoid preview versions: they often crash on beginner projects. The template already includes Physics 2D.

Set Up the Main Scene

Open Scene (double-click in Project > Assets > Scenes > SampleScene).

  1. Hierarchy: Delete Sample Cube. Right-click > 2D Object > Sprite > Square → rename to 'Player'. Position (0,0,0), Scale (0.5,0.5,1).
  2. Add Rigidbody2D (Component > Physics 2D > Rigidbody2D): Gravity Scale = 0 (no falling).
  3. Add BoxCollider2D: Is Trigger = false.
Create 'Coin': Right-click > 2D Object > Sprite > Circle, Scale (0.3,0.3,1), Position (3,0,0). Add CircleCollider2D (Is Trigger = true).

Set camera background to black: Main Camera > Background = Solid Color > Black. Save with Ctrl+S.

Player Movement Script

Assets/Scripts/PlayerController.cs
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float speed = 5f;
    private Rigidbody2D rb;

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

    void Update()
    {
        float horizontal = Input.GetAxis("Horizontal");
        float vertical = Input.GetAxis("Vertical");
        Vector2 movement = new Vector2(horizontal, vertical) * speed;
        rb.velocity = movement;
    }
}

Attach this script to the Player: it reads arrow key/WASD inputs via GetAxis (smooth, -1 to +1 range), applies speed to Rigidbody2D for fluid physics. [SerializeField] lets you edit speed in the Inspector without recompiling. Pitfall: Forgetting rb = GetComponent() will crash in Start(). Test: Hit Play and move the square!

Attach the Script and Test Movement

Attach: Select Player > Add Component > type 'PlayerController' > attach the script. Set Speed=5 in Inspector.

Test: Play (Ctrl+P). Arrow keys = movement. Stop = auto Rigidbody friction.

Improve: Add screen limits. Window > Analysis > Physics Debugger (see green colliders).

Coin Collection Script

Assets/Scripts/Coin.cs
using UnityEngine;

public class Coin : MonoBehaviour
{
    [SerializeField] private int value = 1;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.CompareTag("Player"))
        {
            GameManager.Instance.AddScore(value);
            Destroy(gameObject);
        }
    }
}

On Coin (CircleCollider Is Trigger=true): OnTriggerEnter2D detects collision with 'Player' tag. Adds score via singleton GameManager, destroys coin. CompareTag is optimized over == "Player". Pitfall: Forgetting Player tag (Hierarchy > Player > Tag > Add Tag > Player > assign).

Prepare UI Score and Player Tag

  1. Player Tag: Tag dropdown > + > Player > assign to Player.
  2. UI Score: Right-click Canvas > UI > Text - TextMeshPro. Rename to 'ScoreText', Anchor Top-Center, Text="Score: 0", Font Size=36.
  3. Position at top-center of screen. Play: movement works, Player-Coin collision ignores score (next script).

GameManager Script for Score

Assets/Scripts/GameManager.cs
using UnityEngine;
using TMPro;

public class GameManager : MonoBehaviour
{
    public static GameManager Instance;
    [SerializeField] private TextMeshProUGUI scoreText;
    private int score = 0;

    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    public void AddScore(int points)
    {
        score += points;
        scoreText.text = "Score: " + score;
    }
}

Persistent singleton: Awake ensures unique Instance. AddScore updates TMPro UI. [SerializeField] links ScoreText in Inspector (drag from Hierarchy). Pitfall: Forgetting TMPro import or drag → NullRef. Create Empty GameObject 'GameManager', attach script, link ScoreText.

Infinite Coin Respawn Script

Assets/Scripts/CoinSpawner.cs
using UnityEngine;

public class CoinSpawner : MonoBehaviour
{
    [SerializeField] private GameObject coinPrefab;
    [SerializeField] private float spawnInterval = 2f;
    [SerializeField] private Vector2 spawnArea = new Vector2(8f, 4f);

    void Start()
    {
        InvokeRepeating(nameof(SpawnCoin), 1f, spawnInterval);
    }

    void SpawnCoin()
    {
        Vector2 pos = new Vector2(
            Random.Range(-spawnArea.x/2, spawnArea.x/2),
            Random.Range(-spawnArea.y/2, spawnArea.y/2)
        );
        Instantiate(coinPrefab, pos, Quaternion.identity);
    }
}

Attach to Empty 'Spawner' (Position 0,0). Drag Coin as prefab (drag Coin > Project > Assets/Prefabs). SpawnArea defines zone (-4 to +4 X/Y). InvokeRepeating = reliable timer. Pitfall: No prefab → Instantiate null. Make Coin prefab first.

Finalize: Coin Prefab and Spawner

Coin Prefab: Drag Coin from Hierarchy to Assets/Prefabs. Delete original.

Spawner: Right-click Hierarchy > Create Empty > 'CoinSpawner'. Attach script, drag Coin Prefab, set Interval=2, Area=(10,5). Play: Coins spawn, collect them, score increases!

Polish: Add Sprite Renderer colors (Player=blue, Coin=yellow). Window > Package Manager > 2D Sprite if needed.

Build and Export the Game

terminal-build.sh
# Via Unity Editor:
# File > Build Settings > PC/Mac/Linux Standalone > Add Open Scenes
# Player Settings > Company/Name/Product
# Build > Choose 'Builds' folder

# Or CLI (optional):
/Applications/Unity/Hub/Editor/2023.2.20f1/Unity.app/Contents/MacOS/Unity \
-buildTarget Win64 -executeMethod AutoBuilder.BuildPlayer -quit -batchmode

Build Settings compiles a playable exe. Add icon (Player Settings > Icon). Test outside Editor. Pitfall: Forgetting scenes → empty build. CLI for CI/CD.

Best Practices

  • Version Control: Git init, Unity .gitignore (Assets, Library, etc.). Commit after each script.
  • Layers/Physics: Player layer 'Player', Coin 'Collectible' → Layer Collision Matrix for optimization.
  • Prefabs: Make everything reusable a prefab (Player, Coin, UI).
  • Input System: Migrate to new Input System (Package Manager) for multi-platform.
  • CPU Profile: Window > Analysis > Profiler for <16ms/frame.

Common Errors to Avoid

  • NullReference: Check GetComponent() and Inspector drags. Console > Clear on Play.
  • Physics Glitch: Use FixedUpdate for forces, Update for input. Gravity Scale=0 if unneeded.
  • UI Not Visible: Canvas Scaler > UI Scale Mode = Scale With Screen Size.
  • Build Fails: Scripting Backend = IL2CPP for perf, Api Compatibility .NET Standard 2.1.

Next Steps