Guide

Unity fundamentals explained

You drag a sprite into the Hierarchy, attach a Rigidbody2D, write a dozen lines of C# in PlayerController.cs, and press Play. The character jumps, collides with platforms, and triggers a coin pickup sound. That workflow is Unity Engine in miniature — a cross-platform game engine where everything in a scene is a GameObject and behavior arrives through attachable components. Unity 6 (2023 LTS line and beyond) ships the Universal Render Pipeline (URP), the modern Input System, 2D and 3D physics, UI Toolkit alongside legacy uGUI, and one-click builds for mobile, desktop, console, and WebGL. It powers mobile hits, indie darlings, and AAA-adjacent titles alike. This guide covers the component model, C# scripting and lifecycle, prefabs and scenes, input, physics, UI, ScriptableObjects, packages and rendering, a Harbor Arcade coin-collector worked example, an engine decision table, common pitfalls, and a practitioner checklist — alongside our Godot fundamentals guide and game loop guide.

What Unity is (and how it differs from Godot or Unreal)

Unity is a general-purpose real-time engine maintained by Unity Technologies. Unlike Godot’s scene-tree of typed nodes or Unreal’s Actor hierarchy with Blueprints, Unity uses an entity-component pattern: empty GameObjects gain capabilities by stacking components (Transform, SpriteRenderer, BoxCollider2D, custom scripts). Composition beats deep inheritance — reuse a “Enemy” prefab by swapping scripts and tuning inspector fields rather than subclassing engine types.

Unity’s primary scripting language is C# compiled against .NET Standard / .NET Framework profiles depending on version. The editor runs on Windows, macOS, and Linux. Licensing shifted in 2024: a free Personal tier covers most indies under revenue thresholds; Pro and Enterprise add analytics, support, and compliance tooling. Unity’s asset store, mobile ad SDK ecosystem, and console export pipelines remain reasons teams pick it over open-source alternatives when time-to-store matters.

Core subsystems at a glance

  • GameObjects and components — scene hierarchy; add/remove behavior without subclassing engine classes.
  • C# scriptingMonoBehaviour lifecycle hooks; coroutines; async/await in newer runtimes.
  • Prefabs — reusable, versioned object templates; prefab variants for incremental overrides.
  • Rendering — Built-in (legacy), URP (mobile/PC default), HDRP (high-end); Scriptable Render Pipeline architecture.
  • Physics — 3D PhysX and 2D Box2D wrappers; Rigidbody, CharacterController, trigger colliders.
  • Input — new Input System (action maps, rebinding) vs legacy Input.GetAxis.
  • UI — uGUI (Canvas-based) and UI Toolkit (USS/UXML, growing for editor and runtime).
  • Package Manager — modular features (Cinemachine, Addressables, Netcode) installed per project.

GameObjects, components, and the scene hierarchy

Every object in a level is a GameObject. At minimum it carries a Transform (position, rotation, scale). Rendering needs a MeshRenderer or SpriteRenderer; collision needs Collider shapes; audio needs AudioSource. Custom MonoBehaviour scripts appear as components too, exposing public fields the Inspector serializes into YAML scene files.

Parent-child relationships inherit transforms: a weapon model parented to a hand bone moves with the character rig. Tags and Layers classify objects for physics matrix filtering and raycasts — mirror the collision-layer discipline described in our game physics guide. Empty GameObjects often act as anchors (spawn points, camera rigs, audio listeners).

Scenes and build order

A scene is a self-contained level or menu stored as a .unity file. The Build Settings list defines load order; index 0 is the boot scene. Use SceneManager.LoadScene for full swaps or additive loading for open worlds. Keep scenes small enough for fast iteration — large projects split environments into additive addressable chunks.

C# scripting and the MonoBehaviour lifecycle

Scripts inherit MonoBehaviour and attach to GameObjects. Unity calls lifecycle methods in a defined order each frame:

  • Awake — object constructed; cache component references here.
  • OnEnable / OnDisable — object toggled active; subscribe/unsubscribe to events.
  • Start — first frame before Update if enabled; safe for cross-object lookups.
  • Update / FixedUpdate / LateUpdate — frame logic, physics, camera follow.
  • OnCollisionEnter / OnTriggerEnter — physics callbacks.
  • OnDestroy — cleanup when object removed.

Apply forces and read physics state in FixedUpdate (fixed timestep), not Update, to stay aligned with the physics engine — the same rule as Godot’s _physics_process. Use Time.deltaTime in Update for frame-rate-independent motion. Coroutines (StartCoroutine) yield across frames for delays and sequences without async complexity; prefer C# async only where supported and understood (WebGL has constraints).

Serialization and inspector-driven design

Public fields and [SerializeField] private fields appear in the Inspector, letting designers tune speeds and references without recompiling. [Header], [Tooltip], and [Range] attributes document tuning knobs. Avoid heavy logic in property getters that run every Inspector repaint in edit mode.

Prefabs, ScriptableObjects, and data-driven design

Prefabs store GameObject hierarchies as reusable assets. Editing a prefab propagates to all instances unless overridden. Prefab variants inherit from a base enemy and override only health or mesh — cleaner than duplicating whole prefabs. Instantiate at runtime with Instantiate(enemyPrefab, spawnPoint.position, spawnPoint.rotation).

ScriptableObjects are data assets (not scene objects) ideal for item definitions, wave tables, dialogue lines, and audio clip maps. They load once, survive scene changes, and diff cleanly in version control compared to giant MonoBehaviour lists on scene objects. Pattern: a CoinDefinition ScriptableObject holds sprite, value, and pickup sound; pickup scripts reference the asset.

Input, physics, and UI

Input System

Install the Input System package and define an InputActionAsset with action maps (Move, Jump, Fire). Bind keyboard, gamepad, and touch in one place; enable rebinding UI for accessibility. Read values via playerInput.actions["Move"].ReadValue<Vector2>() or generated C# wrapper classes. Disable legacy input when migrating to avoid double reads.

2D and 3D physics

2D games use Rigidbody2D with Collider2D shapes; platformers often set bodyType to Dynamic with constrained rotation. Use Physics2D layer collision matrix to ignore player-player contact. 3D projects use CharacterController for kinematic walkers or Rigidbody for physics-driven motion. Triggers (isTrigger) detect overlap without solid collision — standard for pickups and zones.

User interface

uGUI places Canvas elements (Text, Image, Button) in screen space. Wire button onClick to public methods. Scale with Canvas Scaler (reference resolution + match width/height). UI Toolkit uses UXML layout and USS stylesheets — closer to web CSS, better for complex menus and editor tools. Pick one stack per project screen to avoid event-system conflicts.

Packages, rendering, and build pipeline

Unity modularizes features through the Package Manager: Cinemachine for cameras, Addressables for remote content, Netcode for GameObjects for multiplayer prototypes. Choose a render pipeline at project creation: URP balances mobile and PC; HDRP targets high-fidelity PC/console. Pipeline assets control lighting, shadows, and post- processing globally.

Build Profiles (Unity 6) consolidate platform settings: texture compression (ASTC on mobile), scripting backend (IL2CPP for iOS/consoles), managed stripping levels, and keystore references. IL2CPP improves performance and obscures C# but lengthens build times — budget CI accordingly. Test device builds early; shader variants and overdraw show up only on real GPUs.

Worked example: Harbor Arcade coin collector (Unity 6, 2D URP)

Harbor Arcade needs a mobile-friendly mini-game: the player moves a character, collects ten coins, and unlocks an exit door. Scope fits one week in Unity 6 with 2D URP and Android export.

  1. Project setup — 2D URP template, orthographic camera sized for 16:9 reference (1920×1080), pixel-perfect camera optional for crisp art.
  2. Player prefabSpriteRenderer + Rigidbody2D (Dynamic, freeze rotation Z) + CapsuleCollider2D. PlayerController reads Input System Move vector, sets rb.velocity in FixedUpdate, flips sprite on X.
  3. Coin prefab — trigger CircleCollider2D; CoinPickup script references CoinDefinition ScriptableObject; on trigger, calls GameManager.AddScore(value) and plays one-shot audio.
  4. Level scene — Tilemap palette for ground; placed coin instances; ExitDoor trigger checks GameManager.Score >= 10 before enabling animator “Open” state.
  5. GameManager singleton — DontDestroyOnLoad optional; raises OnScoreChanged event; persists best score with PlayerPrefs.
  6. HUD — uGUI Text bound to score event; no polling in Update.
  7. Build — Android IL2CPP, ARM64 only, minimum API 24; test on mid-tier device for thermal throttling during sustained play.

Design choices mirror our platformer design guide: early coins sit on flat ground; later coins require a jump gap once the move feel is learned. Coyote time implemented as a 0.12s grace timer after leaving ground contact.

Engine decision table

NeedPrefer UnityConsider alternative
Mobile F2P with ads, IAP, analytics SDKsUnity — mature store integrations and profiling toolsGodot (lighter, fewer native SDKs)
2D indie game, zero license cost, MIT-style freedomUnity Personal may suffice under revenue capsGodot 4 — no royalties, smaller export size
High-end 3D, photoreal console titleUnity HDRP can work for mid-tier AAAUnreal Engine 5 — Nanite, MetaHuman, console-first defaults
Browser-first HTML5 arcadeUnity WebGL (large download, WASM)Phaser, Godot web export, or custom canvas
Team deep in C# and Visual StudioUnity — first-class C# debuggingGodot C# branch if open source is mandatory
Procedural roguelike with rapid content iterationEither engine; Unity Addressables help asset streamingMatch team skill — see roguelike design guide

Common pitfalls

  • Physics in Update instead of FixedUpdate — causes jitter and frame-rate-dependent jump height.
  • GetComponent every frame — cache references in Awake/Start; GetComponent is relatively expensive.
  • Instantiate without pooling — bullet-hell and mobile projects GC-stutter; reuse with object pools.
  • Ignoring script execution order — race conditions when Manager Start runs after dependent objects; set order or use Awake.
  • Massive unoptimized WebGL builds — strip unused engine modules, compress textures, test on throttled networks.
  • Singleton abuse — global statics hide dependencies; prefer explicit references or lightweight service locators.

Production checklist

  • Pin Unity editor version in README; commit ProjectSettings/ProjectVersion.txt.
  • Input action maps documented; keyboard, gamepad, and touch tested on target hardware.
  • Physics layer matrix written down; debug gizmos verified on representative levels.
  • Profiler pass on lowest-spec target device; eliminate Update scripts over 1 ms.
  • Addressables or asset bundles planned if build size exceeds store limits.
  • IL2CPP build tested before milestone locks; allow extra CI time for linking.
  • Store metadata (icons, privacy policy URL, age rating) prepared before submission.
  • Crash analytics (Backtrace, Unity Cloud Diagnostics) wired before soft launch.

Key takeaways

  • GameObjects + components are Unity’s core abstraction — compose behavior instead of deep inheritance trees.
  • C# MonoBehaviour lifecycle separates initialization, frame logic, and physics; respect FixedUpdate for forces.
  • Prefabs and ScriptableObjects keep scenes lean and data designer-friendly.
  • URP + Input System + Package Manager form the modern Unity stack; choose pipeline early.
  • Engine proficiency does not replace design — pair Unity skills with pacing, juice, and clear goals from our game design guides.

Related reading