Desktop & PC / Dungeon Crawler
2D Dungeon Crawler — Gameplay Systems
The foundational weapon, upgrade, and economy systems for a roguelike, built to scale to ~30 weapons without new code.
Gameplay architecture for a 2D roguelike dungeon crawler — a state-machine input controller, the full weapon system from aiming through reload timings, ricochet and boomerang projectiles, and a scriptable-object data layer that lets designers add weapons, bullets, and enemies without touching code.
Engineering highlights
Hover to preview · click to pin
Code
Demo
Code
Demo
Ricochet.cs
void OnHit(RaycastHit2D hit)
{
if (--bounces < 0)
{
Despawn();
return;
}
dir = Vector2.Reflect(
dir, hit.normal);
}Demo
Code
Demo
WeaponData.cs
[CreateAssetMenu(
menuName = "Data/Weapon")]
public class WeaponData
: ScriptableObject
{
public BulletData Bullet;
public float FireRate;
public int MagSize;
public float ReloadTime;
}Demo
Code
Demo
Systems, not features
This project was mostly an exercise in building the layer underneath the game. The interesting constraint was that the weapon roster needed to reach roughly thirty entries with ten-plus bullet types — which rules out implementing weapons individually.
So weapons are data. A WeaponData scriptable object composes a BulletData
with fire rate, magazine size, and reload timing; the weapon controller reads
that and knows how to run any of them. Adding a weapon is authoring an asset,
not writing a class.
Making bounces aimable
Ricochet projectiles are easy to make chaotic and hard to make useful. Reflecting the travel vector across the surface normal gives a bounce the player can predict, which turns wall-banking into a deliberate tactic instead of a random outcome. Bounce budgets are per-bullet data, so a boomerang round and a standard round share one code path.
Keeping input honest
The player state machine exists because combat verbs overlap badly. Reloading while dashing while starting a melee combo produces states no one designed. The machine restricts which inputs are live per state, so invalid combinations simply can’t be expressed.