Inspiration

I prefer sorting complex systems and defining logical rules over manually arranging static scenes. I wanted to tackle procedural generation and turn-based mechanics by building a lightweight, highly structured roguelike engine from scratch.

What it does

Ninja Descent is a turn-based dungeon crawler. It drops the player into a procedurally generated floor where they must navigate grid-based combat, manage an inventory of consumables (like Health Potions and Calamari), and level up to earn skill points. Enemies dynamically pathfind toward the player if they cross into their sight range.

How I built it

The game is engineered entirely in Python using Pygame-CE.

  • Procedural Generation: I implemented a custom "Drunkard's Walk" algorithm to generate the floor layout. The system drops a "drunkard" that steps randomly across a grid, backtracks if it gets stuck, and carves out rooms along the path. The engine then dynamically assigns wall, floor, and door sprites based on the resulting grid.

  • Data-Oriented State: Entity and item positions are tracked using discrete 2D arrays (entities_map and items_map) rather than relying on heavy physical collision boxes.

  • Custom UI & Serialization: I built a scalable UI framework from scratch, including dynamic progress bars, checkboxes, and an interactive inventory display. Player progression (level, floor, kills, stats) is serialized and saved natively using Python's xml.etree.ElementTree.

Challenges I ran into

Balancing a strict turn-based logic loop with smooth visual feedback was tricky. I engineered a tween_movement system that instantly updates the backend grid state while applying ease-in distance multipliers and knockback decay to the rendering loop. This allows the game to calculate the next turn instantly while the visual sprites smoothly glide to their new grid positions.

Accomplishments that I'm proud of

I am proud of the modular buff and upgrade system. Players can allocate earned skill points to permanently increase base damage and health percentages, or consume items like Beef or Calamari to temporarily double their stats for a set number of turns. Implementing this required building a cumulative buff tracker that cleanly manages and removes expired effects during the main update loop.

What I learned

Getting the Drunkard's Walk to reliably generate playable maps without trapping the player forced me to implement clever backtracking fail-safes. Designing the custom XML save system and dynamic inventory UI reinforced my love for low-level systems programming and bypassing pre-built engine tools.

Built With

Share this project:

Updates