The question

How do the design theories taught in game design — MDA, game loops, internal economy, game feel — map onto the concrete scripting patterns used in Unity 2D? Where does a design decision become a line of code?


The event chain: design concepts in motion

A typical Unity 2D game processes each meaningful event through a chain of responsibilities. Each step corresponds to a design concept:

Input → Physics → Logic → Economy → Feedback
StepDesign conceptUnity implementation
InputPlayer agency, real-time controlInput.GetAxisRaw, Input.GetKeyDown
PhysicsSimulated space (Swink’s second building block)Rigidbody2D.linearVelocity, AddForce
LogicMDA mechanics (rules, conditions, state)OnTriggerEnter2D, CompareTag, method calls
EconomyInternal economy (scores, health, lives, drains, sources)GameManager.AddScore(), TakeDamage()
FeedbackGame feel (audio, visual, animation)AudioSource.PlayOneShot, ParticleSystem.Emit, Animator.SetTrigger

The key insight from the mda-framework is that designers control the mechanics layer; the dynamics and aesthetics emerge from player interaction. In Unity terms: you write scripts for the Logic and Economy steps, then observe what players experience. Playtesting is how you close that gap.


Design concepts and their Unity counterparts

MDA mechanics → MonoBehaviour scripts

MDA defines mechanics as the rules, resources, and actions of a game. In Unity, mechanics are encoded in MonoBehaviour scripts:

  • Rules — conditionals and guard clauses in methods (if (currentState != GameState.Playing) return;)
  • Resources — private fields in GameManager (private int score, private int lives)
  • Actions — public methods with clear verbs (AddScore(int amount), TakeDamage(int amount))
  • TriggersOnTriggerEnter2D callbacks that fire when the game world detects a rule-relevant event

The mechanics produce dynamics through the object communication chain. A coin’s OnTriggerEnter2D calls GameManager.Instance.AddScore(10), which changes state, which in turn drives the UI and audio feedback. The student/designer never directly “produces” a dynamic — they write mechanics and observe what emerges.

See unity-object-communication and unity-collider2d-and-triggers.

Game loops → GameManager + lifecycle

Sellers’ game loop taxonomy distinguishes inner loops (immediate action/feedback), core loops (session-level goals), and outer loops (progression). In Unity 2D:

  • Inner loopUpdate() on PlayerMovement + Rigidbody2D physics + immediate audio/particle feedback
  • Core loop — the win/lose condition logic in GameManager, triggered by cumulative state changes (all coins collected, health reaches zero)
  • Designer’s loop — the edit → playtest → adjust cycle enabled by Unity’s Play Mode

The GameManager owns the state that defines when the core loop ends (isGameOver, coin counts, lives remaining). It exposes a public API so other scripts can report events without needing to know the win/lose logic themselves.

See unity-gamemanager-pattern and monobehaviour-lifecycle.

Internal economy → GameManager public API

Adams’ internal economy describes sources (score pickups), drains (damage, lives lost), converters, and feedback loops. The GameManager pattern implements this directly:

// Source — adds to the economy
public void AddScore(int amount) { score = Mathf.Max(0, score + amount); }
 
// Drain — removes from the economy
public void TakeDamage(int amount) { health = Mathf.Max(0, health - amount); }

Clamping with Mathf.Max(0, ...) and Mathf.Min(maxHealth, ...) enforces the economy’s valid range. Guard clauses (if (isGameOver) return;) prevent the economy from updating after the game ends — a common source of state corruption in student projects.

The GameManager never queries other scripts for their state. Other scripts call into it. This direction of dependency keeps the economy centralised and auditable.

See unity-gamemanager-pattern.

Game feel → the feedback step

Swink’s three building blocks are real-time control, simulated space, and polish. In Unity:

  • Real-time controlInput.GetAxisRaw into Rigidbody2D.linearVelocity with Time.deltaTime for frame-rate independence
  • Simulated space — the physics simulation (gravity, collision response, Rigidbody2D body types)
  • Polish — audio, particles, and animation driven from scripts in response to game events

Polish is the last step in the event chain. It should be triggered by the same game events that drive the economy, not separately. A coin pickup calls GameManager.AddScore(10) and then fires sfxSource.PlayOneShot(coinClip) and SpawnParticlePrefab(coinFX, worldPos) in the same method. This keeps feedback consistent with state.

See unity-audiosource, unity-particle-system-scripting, unity-animator-scripting.


Structural principles

Separation of concerns

Each script has one job. The fat class anti-pattern — a single script that handles input, physics, economy, and feedback simultaneously — is the most common structural failure in student Unity projects. It makes debugging difficult and playtesting feedback hard to act on (which mechanic caused this dynamic?).

The correct structure for a small Unity 2D game:

ScriptResponsibility
PlayerMovementInput → Physics
CoinPickupDetect collision → call GameManager
GameManagerOwn economy state; expose public API
FeedbackManagerAudio, particles, screen effects
UIManagerRead GameManager state; update display

Scripts communicate by reference + method call (see unity-object-communication). The GameManager is the exception: it uses a singleton so any script can reach it without an Inspector reference.

Direction of dependency

Dependencies should point toward the GameManager, not outward from it. CoinPickup knows about GameManager; GameManager does not know about CoinPickup. This keeps the economy testable in isolation and prevents coupling where removing a feature breaks unrelated systems.

Prototype mechanics first

Bond’s iterative design loop and Swink’s prototyping advice both recommend building the inner loop first — the core movement/collision/feedback cycle — before layering in the economy and outer loops. In Unity terms: get PlayerMovement + Rigidbody2D + one collision callback working before building GameManager. This matches the CRE132 lab sequence (Labs 1–4 before Labs 5–9).


Where design decisions become bugs

Some student bugs are configuration issues (wrong body type, missing Collider2D, tag mismatch). But the subtler bugs are design-logic failures:

Design errorCode symptom
No guard on win/lose stateScore increments after game over
Economy not clampedHealth goes negative; score wraps
Fat classOne script handles input + collision + sound → hard to playtest
Feedback wired to wrong eventAudio plays on wrong condition
No separation between physics and logicUpdate() moves Rigidbody2D directly → jittery physics

Understanding the event chain (Input → Physics → Logic → Economy → Feedback) helps diagnose these: find which step the failure occurs in, then check the corresponding script.


Open questions

  • How does this architecture scale to multiplayer, or to games with AI-controlled agents? The GameManager singleton becomes a bottleneck.
  • At what point does a GameManager become too large and need splitting into ScoreManager, HealthManager, etc.?
  • How do Unity’s newer features (e.g. the Input System package, Scriptable Objects for data) change this architecture?