Back
MECHANICS DESIGN
Explored 0%
Death screen red overlay Teal zone with corruption prompt Jump buffer mechanic Red player glow platforms Tutorial panel double jump
Unity 6 · Solo · University

Mechanics Design

A 2D platformer in Unity 6 and C# asking how a game can feel good to play — first through forgiving mechanics, then through game juice: DualSense rumble and lightbar, shatter deaths and a taunting death-corruption system.

Type
University Assignment
Module
GDEV50024
Engine
Unity 6 (2D)
Language
C#
Year
Sep 2025 – Jan 2026
Team
Solo
Version Control
Perforce P4V
Corruption States
4
Unity 6 C# 2D Platformer Forgiving Mechanics Game Feel DualSense DualShock4 Controller Rumble Lightbar UI Toolkit Cinemachine Perforce P4V ScriptableObjects Unity Recorder InputSystem
Final Grade 0%
0
Assessments
0
Forgiveness Mechs
0
Partial Classes
0
Source Files (C#)
Overview

What is Mechanics Design?

Mechanics Design is a Level 5 module at Staffordshire University (GDEV50024 — Introduction to Mechanics Design), split across two assessments that together form one complete project: a 2D platformer built in Unity 6 with C#.

The central question across both halves is the same — how do you make a game feel good to play? Assessment 1 answers it through forgiving mechanics: systems that catch human error without removing challenge. Assessment 2 answers it through game juice and game feel: responsiveness, viscerality, and the tactile feedback layer that elevates interaction above input.

Mechanics design gameplay // Early gameplay — forgiving mechanic showcase

The game has a deliberate personality. A death-driven corruption system floods the screen with brutal taunt text as the player dies more — "WHY ARE YOU STILL TRYING", "YOU KNOW THIS ENDS BADLY", "YOU'RE WORTHLESS" — implemented through a real event-driven architecture in Unity UI Toolkit. Version control used a self-hosted Perforce P4V depot on a personal PC running 24/7 via client VPN.

Assessment 1

Forgiving Mechanics

Sep – Oct 2025 · GDEV50024 · Unity 6 · C#

The brief: implement a suite of forgiving platformer mechanics — systems that compensate for human inaccuracy without removing difficulty. These are mechanics the player never consciously notices, but feels immediately if they are absent.

Jump buffer HUD // Jump buffer — HUD feedback display

Jump Buffering

Jump input queued for a short window before landing. If the player presses jump slightly too early, the buffer fires on the next grounded frame. Implemented via ForgivenessTimer and the ForgivenessSettings ScriptableObject.

Coyote Time

Player retains the ability to jump for a short window after walking off a ledge. The m_coyoteTimer resets on each grounded frame and counts down independently of the physics state.

Wall Jump

Full wall-slide and wall-jump system. Includes a regrab block window (m_wallRegrabBlockTime), smooth acceleration override during wall-jump arc, and velocity damping when re-colliding with a wall mid-jump.

Double Jump

Configurable air jumps via m_airJumps in JumpSettings. A separate multiplier (m_doubleJumpMultiplier) scales the second jump strength independently. Jump count resets cleanly on landing.

Charged Jump

Hold jump after landing to charge — horizontal velocity freezes to x *= 0.1f while charging. Release fires a jump scaled between MinJumpStrength and MaxJumpStrength by charge ratio. Includes a charge coyote window.

Variable Jump Height

Hold-to-extend jump via gravity reduction while rising and jump button held. Early release applies gravityScale * 2.5f blended by velocity ratio, cutting the arc short. Smooth apex hang time at peak.

Sticky Feet

Near ledge edges, downward velocity is zeroed and horizontal drift toward the edge is clamped while the player isn't pressing toward it. Grants a micro window to react before coyote time activates. Disengages instantly on directional input.

Bumped Head Correction

Predictive upward BoxCast each physics tick while rising. If a ceiling corner is detected ahead of the physics resolver, the player is nudged horizontally to clear it — preserving vertical momentum. Prefers movement direction, falls back to opposite.

Step Hop / Step Down

Auto step-up over small ledges (MaxStepHeight) and smooth step-down at platform edges (MaxStepDown). Step-hop uses a lerp coroutine for smooth camera-friendly traversal. Step-down prevents micro-air-time on descending stairs.

Speed Apex Boost

At the top of a jump arc (when vertical velocity falls below a threshold), horizontal air-speed cap is multiplied by m_speedApexMultiplier. Gives the player enhanced directional control at the moment it feels most useful.
Cut mechanic
Edge Detection — Removed
Initially implemented but conflicted with Coyote Time — both systems competed for control of the same ledge-exit window. Per the Design Plan document: "Edge Detection removed from forgiving mechanics." Sticky Feet was the replacement approach.
Assessment 1

Development Changelog

  1. 01

    Danger Blocks & Game Over System

    Collision detection for hazard tiles wired to a game over sequence. First pass of the death response system.

    Red glow platforms // Red glow platforms — hazard zone
  2. 02

    Cinemachine, Edge Detection, Hop Jump, Player Death VFX

    Switched from a basic camera script to Cinemachine for dynamic follow. Added edge detection (later removed). Implemented bump head correction (hop jump). Player explosion/death particle effect added.
  3. 03

    Wall Jump, Camera Lens, 2D Freeform Lights

    Full wall-slide and wall-jump implementation. Scroll-wheel camera zoom via ZoomCamera.cs. 2D freeform lights added to the level; global lighting toned down to let them read.
  4. 04

    Perforce Depot Migration

    Classic depot structure converted to Streamlined depot for better branching support. Self-hosted Perforce server running on personal PC accessed via VPN client.
  5. 05

    DebugLogger, CharacterMovement Refactor, Double & Charged Jump, Zoom

    DebugLogger.cs — rich coloured console output, severity levels (Info / Warning / Error / Success), tag filtering.
    DebugExtension.cs — gizmo drawing helpers (wire spheres, arrows) for runtime forgiveness visualisation.
    CharacterMovement.cs fully refactored into partial-class architecture with regions, tooltips, XML doc comments.
    Double Jump and Charged Jump implemented. ZoomCamera.cs scroll-wheel zoom finalised.
Assessment 2

Game Juice & Game Feel

Nov 2025 – Jan 2026 · GDEV50024 · Unity 6 · C#

Game Feel = Responsiveness + Intuitiveness + Viscerality. Assessment 2 builds the full feedback layer on top of the forgiving mechanics foundation — every action the player takes should produce a physical, audio, and visual response that makes the interaction feel like it has weight.

Controller Rumble

Per-event rumble presets via RumblePreset ScriptableObjects keyed by RumbleID: Jump, LandLight, LandHeavy, WallJump, StepHop, Death, ChargeStart, ChargeRelease, FallingLoop. Fall rumble scales continuously with velocity using a power curve (m_fallRumbleCurvePower = 2.8f). Charge rumble escalates via AnimationCurve tied to charge ratio.

DualSense Lightbar

Event-driven lightbar state machine for PlayStation controllers (DualShock4, DualSense). States: Idle (blue, gentle sine-wave pulse), Jumping (colour change), Sprinting, Charging Jump, Charged Jump Performed, Game Over. Smooth lerp transitions between all states. Implemented via GamepadHelper.cs using Unity's InputSystem DualShock API.

Death Corruption System

Four coordinated subsystems driven by death count via DeathCorruptionManager: CorruptionLighting (shifts global light colour), CorruptionClouds (tints background sprite renderers red), CorruptionVFX (scales particle intensity), CorruptionPrompts (spawns taunting text via UI Toolkit). Reaches full corruption at 10 deaths by default, shaped by an AnimationCurve.
Teal zone with corruption prompt

Taunting Prompt System

Known internally as the "bullying mechanic". Implemented in CorruptionPrompts.cs using Unity UI Toolkit. As corruption rises, random-position labels fade in and out across the screen: "WHY ARE YOU STILL TRYING" / "YOU KNOW THIS ENDS BADLY" / "YOU'RE WORTHLESS" / "YOU'RE NOT GOOD ENOUGH" / "WHAT'S THE POINT IN TRYING IF YOU'RE GOING TO FAIL". Spawn rate, max prompt count, and lifetime all scale with the corruption float.

Player Feedback System

Central event router (PlayerFeedbackSystem.cs) wired to CharacterMovement UnityEvents: OnJump, OnLand (severity-graded rumble), OnWallJump, OnChargeStart, OnChargeRelease, OnStepHop, OnDeath. Coordinates audio, VFX pool, trail controller, and gamepad helper from one component. Entire layer toggleable via GameFeelSettings ScriptableObject.
Double jump tutorial // Tutorial — double jump prompt UI

In-Game Tutorial Panels

Contextual tutorial cards displayed via TutorialManager and TutorialPanelUI. Cards contain embedded screenshots or video clips of the mechanic they describe (e.g. DoubleJump card with an in-game screenshot). UI Toolkit UXML/USS layout. TutorialUIAnim.cs handles expand/collapse animations. Triggered by proximity-based TutorialTrigger and TutorialArrow components.

Shatter Death Effect

ShatterPlayer.cs breaks the player into physics fragments on death via HealthComponent.OnDeath. Death also registers to DeathTracker (increments the global counter that feeds the corruption system), plays a death SFX, fires the gamepad Death rumble preset, and disables the jump trail.

Player Trail Controller

State-driven trail system (PlayerTrailController.cs) with distinct states: Jump, Land, Dash. Trail visual changes per movement event. Jump trail enabled on air, disabled on landing. Charge release activates dash trail state. Coordinated through the PlayerFeedbackSystem.

VFX Pool Manager

Object-pooled VFX system (VFXPoolManager.cs) keyed by string ID. Effects: JumpParticle, LandingDust, ChargeParticle, ChargeBurstParticle. GetVFX / ReturnVFX API with parent reassignment for world-space positioning. Prevents per-frame instantiation overhead.

Checkpoint System

Persistent CheckpointManager singleton (DontDestroyOnLoad). Activates the nearest checkpoint on touch, saves ID to PlayerPrefs, and restores on scene load. PlayerRespawnHandler subscribes to OnRespawnTriggered and re-enables the player at the checkpoint's RespawnPoint transform.

Audio System

AudioManager.cs with a central AudioLibrary ScriptableObject. Events played by ID string: Jump, Land, Death. CharacterVoiceover.cs handles character-specific audio triggers. Wired through PlayerFeedbackSystem — entirely decoupled from movement code.

Moving Platforms

MovingPlatform.cs exposes a DeltaPosition vector consumed each physics tick in CharacterMovement. When grounded on a platform, the player's Rigidbody2D position is offset by the platform's delta — no physics parenting required, no jitter.

Combat — Shooter & Enemies

Projectile system via BaseProjectile / ShooterBase / Shooter chain. Enemies: EnemyBase, EnemyRanged, EnemyFlying. Predictive aiming via PredictiveAim2D. Reinforcement spawner (EnemyReinforcementSpawner) for wave management. Health via IHealth interface + HealthComponent with DamageSource2D.

Highlight Recorder

Editor-only highlight capture system (HighlightRecorder.cs) wrapping the Unity Recorder API. Triggerable in-editor during Play Mode — captures a configurable clip length (default 4s) then stops automatically. Prevents recorder window from stealing focus during gameplay. The highlight recordings from Jan 2026 were captured this way.
Health stamina energy bars // Health, stamina, and energy bars — runtime display

Health, Stamina & Energy HUD

Three-bar HUD rendered via Unity UI Toolkit (PlayerHUD.uxml / PlayerHUD.uss). HealthUIController and StaminaUIController update bar fill in response to component events. Damage numbers spawn via UIDamageNumberManager with pooled popup elements. Stamina drains on sprint (coroutine-based), regenerates after a delay.
Death System

The Corruption Architecture

The corruption system is driven by a single float — the player's death count mapped to a [0,1] range via an AnimationCurve. DeathCorruptionManager routes this value to four independent subsystems simultaneously:

Death screen red overlay // Full death screen — red corruption overlay

CorruptionLighting

Shifts the scene's global light colour progressively toward a hot red as corruption rises.

CorruptionClouds

Lerps background cloud SpriteRenderer colours toward a deep red tint (Color(1f, 0.35f, 0.35f)) while darkening by up to 40%.

CorruptionVFX

Scales particle system emission intensity, size, and lifetime with the corruption value.

CorruptionPrompts

Spawns and fades taunting text labels at random screen positions. Spawn rate, lifetime, and maximum active count all grow linearly with corruption.
// Corruption prompt visualiser — live preview
WHY ARE YOU STILL TRYING YOU KNOW THIS ENDS BADLY YOU'RE WORTHLESS YOU'RE NOT GOOD ENOUGH YOU'RE NOT GOOD ENOUGH ANYMORE WHAT'S THE POINT IN TRYING IF YOU'RE GOING TO FAIL

The comment in the source code reads: "Known as the bullying mechanic".

DualSense Integration

Lightbar State Machine

The DualShock / DualSense lightbar is wired to a configurable event-to-colour mapping via Inspector-serialised EventLightbarMapping structs. All transitions lerp smoothly over m_lightbarTransitionDuration (default 0.35s). The idle state adds a gentle sine-wave pulse on top of the base colour.

Idle — blue, sine pulse Jumping — blue shift Sprinting — bright blue Charging Jump — white Charge Released — yellow flash Game Over — red Falling — wind-blue scale
Technical Architecture

CharacterMovement — Partial Class System

The player controller was refactored from a monolithic MonoBehaviour into a partial-class architecture across eight C# files. Each file owns a distinct responsibility. All handler instances are initialised through a chain-init pattern in Awake(): DetectorHandler → MovementHandler → StepHandler → JumpHandler.

The physics loop runs as a coroutine (C_PhysicsLoop) rather than FixedUpdate directly — this gives full control over execution order relative to other subsystems and simplifies coroutine lifecycle management.

CharacterMovement.cs

Core: fields, init, input handling, state machine, physics loop, sprint, helpers

DetectorHandler.cs

Ground / wall detection via raycasts and overlap checks

MovementHandler.cs

Horizontal movement, damping, air control

JumpHandler.cs

All jump types — ground, double, wall, charged, variable

StepHandler.cs

Step-hop and step-down traversal, lerp coroutine

Coroutines.cs

All coroutines: physics loop, variable jump, step cooldown, landing cooldown

Contacts.cs

Contact point callbacks, platform attachment, wall contact events

Debug.cs

Gizmo drawing via DebugExtension, DebugLogger integration, runtime state display

ScriptableObject data assets decouple all numeric parameters from code. Every value the designer might want to tune lives in one of five SOs:

ScriptableObjectTunable values
MovementSettingsMove speed, air speed cap, ground/air damping, sprint multiplier, stamina drain & regen
JumpSettingsJump strength, air jumps, double-jump multiplier, variable jump hold time, charged jump min/max, apex hang time & gravity scale
WallSettingsWall slide speed cap, wall check distance, wall-jump up/push forces, regrab block time, jump duration
StepSettingsMax step height, probe distance, forward offset, skin width, smooth step duration, max/min step-down
ForgivenessSettingsJump buffer time, coyote time, ground check radius, sticky feet probe/duration, speed apex threshold & multiplier, bumped head nudge steps & distance
State Machine

Player States

The player controller runs a six-state machine dispatched inside the coroutine-based physics loop. Each state owns its own movement logic, transition conditions, and feedback hooks:

Idle

Ground movement, step mechanics, buffered jump checks, sticky feet clamp. Transitions to Jumping or Falling.

Jumping

Air movement, apex hang smoothing, speed apex boost, double jump window. Transitions to Falling when velocity drops.

Falling

Wall slide, air control, coyote/buffer jump, double jump from fall. Landing resets all jump state and fires OnLand.

WallJumping

Timed wall-jump arc with smooth velocity lerp. Buffer cleared continuously. Wall collision dampens vertical momentum.

ChargingJump

Freezes horizontal velocity while charge accumulates. Charge coyote window allows charging at ledge edge. Exits to Idle/Falling on release.

VariableJump

Gravity reduction while jump held and rising. Early release spikes gravity for short arc. Smooth apex gravity restore when velocity near zero.
Challenges & Lessons

What Needed Solving

The biggest architectural challenge was the conflict between Edge Detection and Coyote Time. Both systems respond to the same moment — the player at a ledge edge — but with contradictory logic. Edge detection tries to keep the player on the platform; coyote time grants a jump window after leaving it. Running both together created situations where the player could neither walk off nor jump correctly. Edge Detection was removed; Sticky Feet was designed as a replacement that only acts as a passive drag, disengaging immediately when the player gives directional input.

Wall jump clippingThe initial wall-jump implementation let the player clip back into the wall they jumped off. Fixed by introducing m_wallRegrabBlockTime — a timer that blocks wall detection from firing again for a short window after a wall jump, giving the physics resolver time to separate the capsule.

The coroutine-based physics loop was a deliberate deviation from Unity convention. Using FixedUpdate directly caused ordering issues when subsystems needed to communicate in a defined sequence each tick. Running the loop as a WaitForFixedUpdate coroutine made the execution order explicit and allowed all coroutine lifetimes to be controlled from one place.

Lightbar spam preventionInitial lightbar implementation triggered a lerp transition every frame the movement state was evaluated, causing rapid flicker as states changed multiple times per second. Fixed by caching m_currentEvent and early-returning when the incoming event matches the cached one — preventing redundant lerp starts.
Milestones

Trophies Earned

First ClassAwarded 89% — First Class for the module
Divide & ConquerCustom partial-class CharacterMovement architecture across 8 C# files — Handlers, Coroutines, Contacts, Debug
ForgivingSeven distinct forgiving mechanics implemented and tuned via ScriptableObject data assets
Light ShowFull DualSense / DualShock lightbar colour system — event-driven state machine with idle pulse animation
Good VibrationsVelocity-scaled controller rumble — continuous fall rumble, charged jump escalation, per-event presets
CorruptedDeath Corruption System — 4 subsystems (lighting, VFX, clouds, taunting prompts) driven by death count
Show, Don't TellIn-game Tutorial Panels built in Unity UI Toolkit with embedded screenshots/video
LoggedCustom DebugLogger.cs with rich colour output, severity levels, and tag filtering
Highlight ReelHighlight recording system wired through Unity Recorder — triggered in-editor via gameplay event