Core gameplay code for a fast, top-down roguelite / survival arena game built in Unity.
Focus: modular weapons, enemy AI + difficulty scaling, achievements, and meta progression.
- Modular weapon framework (SO-based definitions + runtime instances)
- Targeting strategies & spawn patterns (single, shotgun, forward aim, nearest enemy)
- Status effect modifiers (bleed, slow, lifesteal)
- Weighted enemy spawner with unlock levels + elite variants
- Dynamic difficulty scaling based on player level and weapon strength
- Achievement system with persistence + UI browser
- In-run shop & inventory with non-repeatable per-run purchases
- Persistent leaderboard saved to
leaderboard.json - Polish layer (fade transitions, screen shake, damage popups, sorting bands)
- Features
- Gameplay & Systems Overview
- Project Structure Overview
- Getting Started
- Notes & Troubleshooting
- ScriptableObject weapon definitions (
WeaponDefinition) - Multiple targeting strategies and spawn patterns
- Reusable projectile modifiers (bleed, slow, lifesteal, etc.)
- Weighted spawns with unlock levels + elite variants
- Difficulty scales with player level + weapon strength
- AI movement modes:
- straight, circle, zigzag, strafe, ambush, retreat
- XP + leveling, level-up upgrades
- Per-run stats:
- timers, kills, AFK time, no-hit detection
- Central
AchievementManagerwith persistence (PlayerPrefsJSON) - UI list with progress tracking and wipe button
- Unlocks triggered by many gameplay events
- In-run shop with non-repeatable purchases per run
- Inventory + stat-modifying items
- Persistent leaderboard saved to
leaderboard.json
- Global fade manager for clean scene transitions
- Damage popups, UI lerps, screen shake, VFX
- Intro/cutscenes with skip support
- Sorting-band based 2D rendering order
- Fixed framerate initialization
- Global game state (pause, run flags, etc.)
- Controls
Time.timeScalefor pause/resume
- Runtime black overlay canvas (singleton)
- Scene loads via
LoadSceneWithFade(fade in/out)
GameLoader, RestartGame, BackToMainMenu, HowToPlayLoader
- Minimal wrappers calling
FadeManagerfor specific scenes
- Sets v-sync and target FPS once per app lifetime
- HP/XP/level + base multipliers + run statistics
- Drives HP/XP UI (lerps, indicators, shake)
- Level-up logic + achievement triggers
- Death flow: animation β blood β disable shop/pause β camera zoom β fade to Game Over
- Per-run timer (TMP display)
- Survival achievements at 5 / 10 / 15 / 30 minutes
- Spawns 2 random upgrade options on level-up
- Applies upgrade on click, then closes UI
- Drag-based virtual joystick (touch + mouse)
- Dead zone, max drag distance, max speed
- Updates
Rigidbody2D.linearVelocity, animator params, and shadow stretch - Aim uses
AimDirection2D
- Stores last non-zero move direction
- Used by forward-aiming weapons for shot direction
- Weapon = data (
WeaponDefinition) + runtime state (WeaponInstance) WeaponControllerowns equipped weapons and runs the firing loop
- damage, cooldown, projectile count, range, speed, icon, name
- composed from:
TargetingStrategySpawnPatternProjectileFactory/OrbitingWeaponFactoryWeaponModifier[]
- runtime values:
- level, cooldown timer, bonus stats, multipliers
- final stats = base weapon stats Γ player multipliers + instance bonuses
- Up to 3 active weapons + extra inventory
- Handles:
- cooldown loop β targeting β pattern spawn β projectile creation
- orbiting weapons
- weapon switching UI
- Unlocks weapon achievements (e.g. arsenal, orbit_master)
Types: Damage / ProjectileCount / Cooldown / Range / OrbitalSpeed
- Applies to a specific
WeaponInstance - Refreshes orbitals if needed
- Unlocks upgrade achievements (first upgrade, cooldown_50, range_150, etc.)
- UI slots: icon + cooldown fill
- slot buttons open the weapon switch panel
Targeting (TargetingStrategy):
NearestEnemyTargetingβPhysics2D.OverlapCircleAllthen closestAimForwardTargetingβfirePoint.rightorAimDirection2D.Direction
Spawn (SpawnPattern):
SinglePatternShotgunPattern(spread scales with projectile count)
Modifiers (WeaponModifier):
BleedOnHitβEnemyHealth.ApplyBleedSlowOnHitβEnemyHealth.ApplySlowLifeStealOnHitβ heal % of dealt damageProjectileEffectsbridges hits/kills β modifiers
Shared structs: WeaponContext, TargetInfo, Shot
- Weighted enemy list (
EnemySpawnData) - Scaling:
- enemy HP/damage scales relative to player stats
- difficulty ramps over time (interval, stats, spawn count)
- Spawns outside camera view on valid tiles
- Optional elite spawns (multipliers + visuals)
- prefab, unlock level, spawn weight, always spawn flag
- scaling ratios relative to player stats
- 2D
NavMeshAgent - Modes: Straight / Circle / Zigzag / Strafe / Ambush / Retreat
- On player trigger: deal damage then self-destruct
- health, speed, damage, XP/coin rewards
- damage text optional via
DamageTextSpawner - death: rewards player + blood VFX
- status effects:
ApplySlow,ApplyBleed
- Serializable achievement definitions + save data
- Singleton registry
- Unlock/check/list helpers
- Saves unlocked IDs to
PlayerPrefs(JSON) - Meta-achievements for unlocking N/all achievements
- Scroll list with styling + locked/unlocked states
- Shows global progress counter
- Button to wipe saved achievements
- Singleton attached to player
InventorySlotlist: (ShopItem, quantity)- Add/remove applies stat effects via
ShopItem
ShopItemis expected to exposeApplyToPlayerandRemoveFromPlayer, and may referenceWeaponDefinitionfor weapon items.
- In-run shop UI controller
- Ensures items are not offered/purchased more than once per run
- Filters weapon offers to avoid duplicates
- Purchase: coins check β inventory add β refresh
- Tracks purchases + lifetime spend, unlocks shop achievements
- player name, level, total time, minutes, seconds
- Reads TMP input + level +
RunTimer - Saves top runs into
leaderboard.json - Shows βsavedβ text animation
- Loads
leaderboard.json, sorts by level desc - Populates UI rows + pop-in animation
DamageTextSpawner: world β UI anchored, spawnsDamageTextUIDamageTextUI: curved float + fade + destroy
SortingBandManager: sorting order from world YCharacterSortingByBand: uses βfeetβ transformPropSortingRegister: static props sorted by bottom point
TilemapSetup: overlays + prop spawning with spacing rules
- Menu: loop track
- Gameplay: shuffle without repeating last track
- Unlocks
music_loveron first gameplay music start
VideoPlayerclips with skip support- Intro preloads menu scene and activates via
FadeManager - Unlocks
movie_buffif watched fully
- Pause menu fade/scale animation
- Toggles
Time.timeScale - Tracks
PausedThisRunfor no-pause achievements
- Opens/closes shop and pauses/resumes via
GameManagerScript - Avoids conflicts with pause state
- Core Game Flow:
GameManagerScript,FadeManager, loaders,SetFPS - Player:
PlayerStats,RunTimer,LevelUpScript,UpgradeOptionUI,PlayerMovement,AimDirection2D - Weapons:
WeaponDefinition,WeaponInstance,WeaponController,WeaponUpgrade,WeaponDisplayManager - Enemies:
EnemySpawner,EnemySpawnData,EnemyAI,EnemyHealth - Achievements:
Achievement,AchievementSaveData,AchievementManager,AchievementUIManager - Meta:
ShopManager,PlayerInventory,SaveData,SaveScript,LeaderboardManager - Polish: damage text, sorting, tilemap setup, audio/video, pause flow
- Unity 2021 LTS+ (recommended)
- TextMeshPro package installed
- 2D Renderer setup
- NavMesh configured for 2D (required for
EnemyAI)
- Clone the repository and open it in Unity.
- Ensure scene names match code references:
MenuScene,MainScene,HowToPlayScene,LeaderboardScene,AchievementScene,GameOverScene,CutsceneScene
- Create Weapon Definitions:
Create > Weapons > Weapon Definitions
- Configure enemies:
- assign prefabs + spawn data in
EnemySpawner - verify NavMesh for your map
- assign prefabs + spawn data in
- Hook UI references in the Inspector:
PlayerStats,RunTimer,ShopManager,AchievementUIManager,LeaderboardManager, etc.
- Run and verify:
- weapons fire
- enemies spawn + scale correctly
- achievements unlock
- shop/pause pauses time correctly