U
08 / 22 · 11 min
FAQ

How to make a 3D game in Unity: five stages, one project

the short answer

How do I make a game in Unity as a beginner?

Build one 3D action game — a Knight, a Mage and an Archer in one arena — across five stages, from an empty project to an APK on your phone, with no code assumed beforehand. Each stage ends in something you can press and test, so the project gets finished instead of restarted.

This is the whole route: an empty Unity project at one end, and a 3D action game at the other — a Knight, a Mage and an Archer fighting in one arena, installed on the phone in your pocket. Five stages, one project, and no code you were expected to know beforehand. Every stage ends with something you can look at and press, so at no point do you have to wonder whether what you built actually works.

The reason a first game never gets finished is rarely difficulty. It is that the project on screen is never quite the project you wanted, so you start over — in a new engine, with a bigger idea, on page three of a tutorial series nobody reaches the end of. One finished project teaches more than ten abandoned ones for a plain reason: only a finished one drags you through the annoying tail, the build settings, the resolution nobody tested, the frame that falls to 30 when three enemies are on screen at once.

Sixty seconds of setup

  1. 1

    Unity Hub > Installs > Install Unity, and pick the Unity 6 LTS entry. In the module list, tick Android Build Support and Microsoft Visual Studio Community: the Hub installs the editor and the IDE together, so there is no separate Visual Studio configuration step to get wrong.

  2. 2

    New project, template Universal 3D, on an SSD, with a short name and no spaces. Ask for the Android module here rather than in File▸Build Profiles five stages later — adding a module after the fact is a re-install, and stage 5 is a bad place to discover you skipped it.

  3. 3

    Sign in with a free Unity ID when the editor asks. What activates is the Personal licence, and it is enough for all five stages — nothing to buy, nothing else to install. Unity does not open at all before that sign-in, which is why it is step three and not a footnote.

The map: five stages, one scene

Each stage is one tab of the course, and each name below links to that tab with its lessons listed. The counts and minutes come straight from the curriculum, so they cannot be out of date here.

Stage 1 · Basics & Arena — 11 lessons, 100 min

  • A floor with a material on it, and a grid of blocks that code generated rather than your mouse — so it can be a different grid later.

  • Three characters — Knight, Mage, Archer — swapped with 1, 2, 3, plus an intro screen with music that loads the arena.

Stage 2 · Heroes & Foes — 9 lessons, 114 min

  • The Knight has a body: a CharacterController, gravity, a jump that lands on the blocks from stage 1, and animation that follows what it is doing.

  • Three skills on Q/E/R with cooldowns, projectiles that come back out of a pool, and enemies that chase, take damage and die.

Stage 3 · Camera & Input — 6 lessons, 67 min

  • A third-person camera that orbits without clipping through the arena walls, and shakes when something lands — after you have written the follow by hand once, so you know what the package is doing.

  • One input map feeding keyboard, gamepad and an on-screen stick: the same fight, playable with a single thumb.

Stage 4 · World & Waves — 7 lessons, 83 min

  • The grey box becomes somewhere: terrain, a baked light with skybox and fog, props from a 1×1 m module kit, footsteps and a mixer — and the frame rate held while doing it.

  • The demo becomes a game: waves from four spawn points, a victory panel, a defeat panel, and a restart that does not need the app closed.

Stage 5 · Mobile Export — 7 lessons, 83 min

  • Player Settings that ship: package name, IL2CPP and ARM64, a keystore, and an APK you can hand to somebody who then installs it.

  • A save file that survives the app being closed, URP tuned for the phone instead of the editor, and 60 FPS on the device in your hand.

Stage 1: a floor, blocks, and three characters

Stage 1 looks small on purpose and is not a warm-up: it is the arena the rest of the course happens in. You finish it with a floor, a grid of blocks spawned by two loops, three characters you can walk around as, and an intro screen with music that loads the fight. All of that exists before anything looks good.

The order is deliberate: four short C# lessons, then the editor, then the scene. Not to teach you programming — to make a Unity script readable. What a variable holds, why Update runs once per frame, what a class becomes once you have seen it sitting in the Inspector, and how much if, for and List a first game needs, which is less than you fear. Then the five windows you actually live in. Only then an object on a floor. C# before Unity, Unity before the game, and each of those steps one sitting rather than one month.

ArenaBuilder.cs — the block grid, in two loops
using UnityEngine;

public class ArenaBuilder : MonoBehaviour
{
    public GameObject block;
    public Vector2Int size = new Vector2Int(6, 6);
    public float spacing = 2f;

    void Start()
    {
        for (int x = 0; x < size.x; x++)
        {
            for (int z = 0; z < size.y; z++)
            {
                Vector3 pos = transform.position + new Vector3(x * spacing, 0f, z * spacing);
                // The fourth argument makes the block a child of this object.
                Instantiate(block, pos, Quaternion.identity, transform);
            }
        }
    }
}

Thirty-six blocks from a loop inside a loop. That is the point of generating rather than placing: when stage 4 wants a wider arena, the grid changes with one number, and nobody drags a cube twice.

Stages 2, 3 and 4: the first hit, the camera, and somewhere to fight

Stage 2: mechanics that pay for themselves

The character gets a CharacterController, gravity, and a jump that actually lands on the stage 1 blocks; then the Animator state machine takes the legs away from the script, so idle, run, jump and attack come from one blend tree plus transitions driven by variables the movement code already writes. Skills are the lesson worth naming out loud: each one is a ScriptableObject asset holding its cooldown, damage and projectile.

SkillData.cs — the numbers live in an asset, the logic lives in a script
using UnityEngine;

[CreateAssetMenu(menuName = "Game/Skill")]
public class SkillData : ScriptableObject
{
    public string skillName;
    public float cooldown = 1f;
    public int damage = 10;
    public GameObject projectile;
}

// The caster keeps one gate per slot; the asset only supplies the numbers.
public class SkillCaster : MonoBehaviour
{
    public SkillData[] skills;
    float[] nextReadyAt;

    void Awake() => nextReadyAt = new float[skills.Length];

    public bool TryCast(int slot)
    {
        if (Time.time < nextReadyAt[slot]) return false;
        nextReadyAt[slot] = Time.time + skills[slot].cooldown;
        return true;
    }
}

That split is what keeps paying. The number someone wants to tune sits in the Inspector rather than inside the class the projectile logic also lives in, so rebalancing Slash cannot break the thing that fires it. A fourth skill is a new asset in a folder plus one more entry in an array that already exists — which is why an hour with ScriptableObject is worth more than a week of if-chains.

Stage 3: the part people skip

Stage 3 decides whether anyone other than you can play it. You write a follow camera by hand once — Lerp toward an offset in LateUpdate — and only then meet Cinemachine, so you know precisely what the virtual camera and its brain are doing for you, and what to blame when the view clips through a wall. Then one Input System action map replaces every key check in the project: a named Move action, fed by a keyboard, a gamepad stick, and an on-screen joystick on a Canvas. That last binding is the difference between a Unity project and a game on a phone.

Stage 4: from demo to game

Stage 4 does two things with the same Arena.unity. It dresses it — terrain, a baked directional light with a skybox and fog, props from a 1×1 m module kit and prefab variants, footsteps and a mixer — and it keeps the dressed scene fast with LOD groups, batching and occlusion, because a pretty arena at 20 FPS is not playable. Then GameDirector makes it a game: waves out of four spawn points, a victory panel, a defeat panel, and a restart. Nothing there is invented from zero; it is the systems from stages 1 to 3 wired to each other, and that wiring is what people mean by a game loop.

  • Damage goes through an event on CharacterStats rather than a reference to whoever got hit, so a health bar, a damage number and a white flash all subscribe to the same fact. That is the pattern the rest of the stage leans on.

  • Enemies walk a baked NavMesh instead of a hand-written chase. Which is the honest way to spend the extra fifteen minutes: a route you can look at in the Scene view, and re-bake when stage 4 moves the rocks.

Stage 5: onto a real phone

The last stage is a few hours of settings and one moment that pays for the whole course: the game running on a device that is not your computer. Switch the build target to Android, list the scenes, set the package name, IL2CPP and ARM64, and press Build. For testing that already gives you an APK you can install over USB or send to somebody, who installs it and hands it back. A Google Play upload wants an AAB instead, built by ticking one box in the same window.

  1. 1

    Switching platform re-imports every texture into a format Android reads, so start it before making coffee. Then File▸Build Profiles and Add Open Scenes: a scene that is not on that list does not exist in the game, which is the most common reason a build opens onto a black screen.

  2. 2

    A debug build signs itself, so testing needs no keystore; the signed release build is the one Google Play accepts. Keep the keystore file and its password — losing it means losing the app's identity, not just a settings window.

  3. 3

    When it misbehaves on the device, adb logcat is the conversation the phone is having. One filtered command, and the reason the game closed itself is on the screen — the build guide has it, along with the IL2CPP stripping that causes most launch crashes.

  4. 4

    Frame rate is the last boss: Application.targetFrameRate is not set to 60 by itself on every phone, and the editor's frame rate tells you nothing about the device. The fixes are the boring ones from the performance lesson — compressed textures, fewer draw calls, LOD on props, URP rather than the built-in pipeline — measured on the phone, not near it.

Five mistakes that keep the first game unfinished

  • Scope. The first idea is always too big, because it is the one you know best. An open-world survival game needs a hundred systems; one arena with three characters and a wave loop needs roughly ten, and those ten are the ten every game needs. Cut until the plan embarrasses you a little — that is about the right size.

  • Switching engine mid-project. The grass is not greener, it is a different set of problems. Every engine has a wall at about the second month, and moving does not carry you over it — it only restarts the count. Whatever you are holding now, finish one thing in it.

  • Never publishing. A build nobody plays keeps every decision open, so you never have to say which one was wrong. Publishing is the only test that counts: a person who is not you holds the phone and gets confused without you watching. Uncomfortable, and that discomfort is the entire product.

  • Waiting for art. The grey-box stage is not the ugly phase to skip, it is the phase where the game has to be fun. A room of capsules and cubes that is not playable stays unplayable with beautiful characters in it, and costs more to change. Make the cube jump feel right, then drop a model onto it without touching the code.

  • Learning in circles. A ninth tutorial on CharacterController feels like progress and buys none, because the tenth thing you do not know surfaces only when you hit the ninth. Reading a manual is study; getting a capsule to step over a block without falling through the floor is engineering. Do the second one, and look things up when the project demands it.

What counts as finished

  • ✓The game starts on a menu, plays a wave, and can be lost — then restarted from a button, not by closing the app.
  • ✓The build is on a phone and the editor is closed: the game runs with no computer attached.
  • ✓Somebody who has never seen the project plays two minutes without asking you what to press.
  • ✓It holds 60 FPS on that device, or you can name where it drops and why.
  • ✓Closing the app and opening it again brings progress back — the save file survives, and so does the setting you changed.
  • ✓You can say, in one sentence, what is still missing. That sentence is the first thing you fix in the next project — which is the point: the next one starts faster because this one got finished.

The next step is one page long: open the first tab, Basics & Arena, and start at the first lesson. It assumes you have never written code before, and it ends with a floor in your scene and three characters standing on it.

the lesson that builds this

C# in 60 seconds: variables

This post is a standalone recipe. In the course, the same thing is built as part of the one project that runs through all five tabs — Basics, lesson 01.