Randonaut is an arena survival game built with Unity. The player pilots a hero who automatically fights through waves of increasingly dangerous enemies, gathers experience orbs, and invests the earned skill points into a branching upgrade tree. Survive the five-minute countdown, defeat the boss that spawns when the timer expires, and set a new high score in the process.
- Spawn and survive:
GameManagerinstantiates the player, hooks up the UI, and continuously reduces the match timer. When the countdown reaches zero it triggers the boss spawn sequence and ends the run on victory or defeat. - Fight and maneuver:
PlayerImplreads input actions, moves the Rigidbody-driven character, and fires skills at the closest enemies. Each skill can be modified by global stat boosts earned throughout the run. - Progress and upgrade: Collecting experience through
ExperienceHolderlevels the player, awards skill points, and opens the skill tree UI for new perks.
| Folder | Purpose |
|---|---|
Core/ |
Low-level gameplay building blocks such as entities (Player, Enemy), combat components (Health, SkillHolder, AttractableMagnet), and shared resource loading utilities. |
Factories/ |
Runtime factories that generate procedurally varied skills and upgrade tree content used when creating players, enemies, and skill nodes. |
Runtime/ |
Scene-level managers that coordinate the match: spawning enemies, executing skills, and advancing the session clock. |
Shared/ |
ScriptableObject definitions, enums, and utilities that hold tunable data such as player stats, enemy stats, skill parameters, and elemental logic. |
Tree/ |
Data structures that represent the skill tree graph and its node content (skills, upgrades, stat boosts). |
UI/ |
Game interface scripts that display HUD elements, manage the pause menu, and build the interactive skill tree panels. |
Upgrades/ |
Modular stat and skill upgrades that can be slotted into the tree, ranging from global stat buffs to skill-specific modifiers. |
PlayerImpl extends the abstract Player entity with Unity Input System bindings, movement, skill firing logic, and magnet/experience handling. The associated PlayerStats ScriptableObject feeds base values such as move speed, attraction radius, and global damage multipliers that are cloned per run. Leveling is handled by ExperienceHolder, which tracks XP thresholds, grants additional skill points, and exposes change events consumed by the UI.
Skills are procedurally generated by SkillFactory, which selects a form (projectile, cone, aura, etc.), assigns elemental affinities, and rolls stats from configurable distributions. When used, SkillExecutor spawns the appropriate prefab, aims it based on target data, and applies on-hit effects defined by each Skill. Cooldowns, availability, and skill upgrades are tracked by the player’s SkillHolder.
EnemySpawner drives the escalating challenge curve by sampling animation curves to determine spawn rates, enemy compositions, and elemental modifiers. Enemies are instantiated around the player, optionally receive generated skills, and notify listeners when defeated so the score UI can update. Each Enemy clones its EnemyStats, applies contact damage or ranged behaviors, and leverages SkillExecutor for active abilities.
The skill tree UI scans configured node layouts, builds TreeNode graphs, and populates each node with generated content while respecting uniqueness rules. Nodes can represent skill unlocks (SkillContent), stat boosts (StatContent), or targeted skill upgrades (UpgradeContent), and clicking them applies their effects to the player before closing the tree if desired. Upgrade behaviors themselves live under Upgrades/, where ScriptableObjects derived from BaseSkillUpgrade implement bespoke modifiers and can react to events such as projectile spawns or on-hit effects.
PlayerUI ties together the HUD (timer, score, experience bar), pause menu, and skill tree overlays. It listens for level-up events to surface new choices, tracks the high score, and handles restart/pause flows, while auxiliary scripts such as SkillsUI, ExperienceBar, and NodeButton render individual UI elements.
Most tunable values are stored as ScriptableObjects under Shared/Data/. Examples include PlayerStats for base player attributes, EnemyStats for individual enemy archetypes (health, damage, sprites, elemental alignment), SkillStats for per-skill tuning, and ElementSounds for reusable audio references.