Post

Dungeon Slayer: A Rogue-like Deck-Builder

Dungeon Slayer: A Rogue-like Deck-Builder

Project Overview

This Project’s GitHub Repo

Dungeon Slayer is a 3D first-person rogue-like deck-builder developed in Unreal Engine 5 as part of CS3247 Game Development course in the National University of Singapore. As part of a 6-person team, I took on the role of lead developer for the modular card crafting system and utility-based AI decision system.

The Concept

Players take on the role of a sorcerer trapped in a cursed dungeon, caught in an endless cycle of death and rebirth. Each death reshapes the dungeon, ensuring no two runs are identical. Armed with arcane knowledge, players must collect magical charms to forge powerful spell cards and ultimately escape the living labyrinth.

Key Features:

  • Modular Card Crafting System: Build spells from individual components rather than collecting pre-made cards
  • Utility-Based AI: Intelligent enemy decision-making that adapts to combat situations
  • Procedural Generation: Dynamic dungeon layouts with randomized encounters
  • Stylised Visuals: Moebius-inspired sketch art style with custom shaders
  • AI-Generated Content: Leveraged modern AI tools for music, sound effects, and sprites for enemy characters

Modular Card Crafting System

The card system was something that I have been thinking about extensively since the concept phase of the game. Traditional card games limit players to pre-designed cards, but I wanted to create something more flexible and creative. Eventually, I figured that as opposed to having each card with a set of static and pre-defined behaviours, why not leave the choice to the players as to what kind of cards they wish to create? Our modular system treats individual card effects as building blocks, allowing players to construct spells with complete creative freedom.

This system creates emergent gameplay where players discover powerful combinations through experimentation. Rather than memorizing optimal pre-built decks, players engage in creative problem-solving, making each play-through feel unique and personal.

Architecture Overview

The system is built around three core charm types:

Impact Charms

  • Serve as the foundation of every spell
  • Provide the primary effect (damage, healing, utility)
  • Must be present in every valid spell recipe

Enchantment Charms

  • Act as modifiers that enhance or alter Impact effects
  • Can be chained together for compound modifications
  • Applied recursively through the spell’s effect tree

Special Charms

  • Dual Casting: Execute two spell effects simultaneously
  • Power Fusion: Combine two Impact charms into new, unique effects

Technical Implementation

First, I created a data type for the cards:

Card Data Structure:
├── Mana Cost: int
├── Recipe: recipe object
├── Effects: array[card effect]
├── Root: charm node object
├── Craft Cost: map[resource, int]
└── Durability: int

Here, the “charm node” object is the key to the modular card effect system. Essentially, this root node stores a reference to a binary tree data structure where each node represents a charm. When applying a card, an iterator traverses the tree by depth-first search, during which every single root-leaf directed path is collected and built into a run-time card effect! This approach provides several key advantages:

Recursive Processing Algorithm

The system processes spells through tree traversal:

  1. Enchantment Charms: Recursively build effects on subtree, then apply modifier
  2. Dual Casting/Power Fusion: Process both subtrees and combine effects accordingly
  3. Impact Charms: Generate base effect and mark as leaf node

As such, this tree structure ensures that enchantments which could potentially be applied to multiple other nodes can be stored in a memory-efficient way without having to duplicate the nodes for every impact located at the leaves.

Chain of Responsibility Pattern

By our very design, a card can potentially have lots of effects, with each applicable to a different component on the target. For example, a card should first apply a mana deduction effect to the player, after which a damage effect is applied on the targeted enemy, where different types of damages should be considered against the enemy’s defence and resistance stats.

To prevent bugs and enhance code maintainability, I implemented a processor pipeline for spell execution during combat. The pipeline consists of a sequence of effect processors, where every processor only handles a very specific aspect of the card’s effect. If a card does not have the effect which a processor is expected to handle, the processor simply skips the work and pass the card to the next processor in the pipeline.

An example flow might be this:

Card |> Mana Cost Processor |> Defence Processor |> Damage Processor |> Healing Processor |> Special Effect Processor |> ...

This pattern ensures:

  • Scalability: Easy to add new effect types
  • Maintainability: Each processor handles one responsibility
  • Modularity: Effects can be processed independently

Utility AI System

Creating believable, challenging enemies required a responsive AI decision model. To simulate realism, this AI decision model should present some randomness or fuzziness when selecting an action, much like in real-world contexts where information is often vague or incomplete. However, the randomness should also be contained in a reasonable scale for games because we still wish the players to have a sense of control over the combat.

Towards this goal, I developed a utility-based AI system that makes contextual decisions, creating opponents that feel intelligent and adaptive.

Three-Phase Decision Making

Phase 1: Observation

The AI captures a “screenshot” of the current battle state:

Combat Context:
├── Self: the enemy's own stats and status
├── Enemies: array of all enemy characters
└── Player: current player state and attributes

This context feeds into all subsequent decision-making phases as a blackboard holding the data relevant to decision-making.

Phase 2: Thinking

The enemy can perform multiple skills in a turn. To simplify AI evaluation, I further divided each skill into a series of actions. For example, a single skill might damage the target and increase the enemy’s own defence at the same time, so this skill consists of two actions.

For every possible skill, the AI first iterate over the actions in the skill. For each action, the AI calculates a utility score using custom formulae. To ensure fair comparison, every formula should normalise the raw utility into a range between 0 and 1.

Damage Utility Example:

Raw Utility = Damage Value / Target Remaining Health

Healing Utility Example:

Raw Utility = Healing Amount / Health Before Healing

Another feature of the AI system is evaluation curves, which represent the importance or urgency of an action given a specific combat state. Each action type uses a custom evaluation curve that scale the base utility according to situational factors:

  • Low Health Scenarios: Healing and defensive actions receive higher priority scaling
  • Near-Death Enemies: Damage actions gain increased utility when they can finish targets
  • High Health or High Defence Scenarios: Healing is less important and the AI is braver in aggressive attack

For skills containing $N \geq 1$ actions, I developed a formula that balances the impact of the strongest effect with overall skill versatility:

Skill Utility = MaxActionScore + (1 - MaxActionScore) × (TotalActionScores / N)

This ensures the AI considers both powerful singular effects and well-rounded abilities.

Phase 3: Decision-Making

Before choosing a skill, the skill’s utility is modified with a “randomness coefficient” that prevents completely predictable behaviour. This coefficient is exposed to the editor so that the team can experiment for an optimal value.

Final Utility = Base Utility × Random(1 - R, 1 + R)

Other Core Game Mechanics & Design Philosophy

The Gameplay Loop

The game follows a tight, engaging loop designed to maintain tension and progression:

  1. Exploration Phase: Navigate procedurally generated dungeons, discovering resources and charms
  2. Combat Phase: Engage enemies using crafted spell cards with tactical decision-making
  3. Crafting Phase: Combine collected charms into powerful spells at enchanting altars
  4. Progression: Choose between exploring more areas or challenging the final boss

This structure ensures players always have meaningful choices while building toward the climactic boss encounter.

Portal System & Player Agency

The dual-portal system gives players control over their risk-reward balance:

  • Green Portals: Lead to new areas with more resources but increased danger
  • Red Portals: Direct path to the boss fight for players ready to conclude their run

This design respects player autonomy while maintaining the roguelike tradition of permanent consequences.

Advanced Visual Systems

Moebius-Style Rendering Pipeline

The team developed a custom post-processing shader that creates a distinctive comic book aesthetic:

  • Toon Shading: Quantized lighting levels create solid regions of light and shadow
  • Outline Detection: Filtering on depth and normal maps to generate clean edge lines
  • Cross-Hatching: Procedural texture application in shadow areas adds hand-drawn character
  • Dynamic Effects: Real-time particle systems and camera shake enhance combat feedback

Procedural Content Generation

Our team implemented a comprehensive procedural system to ensure replayability:

Room-First Level Generation

  • Pre-designed room templates with fixed entrances and 1-3 exits
  • Collision detection prevents overlapping rooms during generation
  • Configurable dungeon size parameters (MinDungeonSize, MaxDungeonSize)
  • Automatic wall closure for unused exits

Dynamic Encounter Placement

  • Configurable DangerLevel parameter controls combat density
  • Weighted random selection for enemy party composition
  • Interactive object placement at predefined spawn points

Modern AI Integration

Recognising our team’s limitations in art and audio, we embraced AI tools to obtain quality assets:

  • Music: Generated ambient tracks and main theme using Suno AI and Udio
  • Sound Effects: Created using ElevenLabs for consistent audio design
  • Visual Assets: Enemy sprites and UI icons generated with Stable Diffusion
  • Workflow: Deployed ComfyUI for streamlined asset generation pipeline

This approach allowed our small team to achieve visual and audio quality typically requiring specialized artists.

Robust Character Systems

Built on Unreal Engine’s Gameplay Abilities System:

  • Unified Attribute Management: Health, mana, defence, and damage resistances
  • Effect-Driven Changes: All attribute modifications go through Gameplay Effects
  • Automatic Clamping: Built-in value validation and range enforcement
  • Custom Damage Formulas: Flexible calculation system supporting complex interactions

Technical Challenges & Solutions

Challenge: Scalable Effect System

Problem: Need to support dozens of unique spell effects without creating unmaintainable code

Solution: Implemented Chain of Responsibility pattern with data-driven effect definitions

Challenge: Believable Enemy Behavior

Problem: Simple state machines created predictable, exploitable AI opponents

Solution: Developed utility-based system with fuzzy logic for human-like decision variance

Challenge: Complex Card Interactions

Problem: Nested effect modifications and parallel spell execution required flexible architecture

Solution: Binary tree structure with recursive processing enables unlimited effect combinations

Challenge: Procedural Quality Control

Problem: Random generation often created unplayable or boring layouts

Solution: Template-based rooms with intelligent connection algorithms and configurable parameters


Key Learnings & Takeaways

This project reinforced several important principles in game development:

  1. Systems Thinking: Complex games emerge from simple, well-designed systems working together
  2. Player Agency: The most engaging mechanics give players meaningful choices and creative freedom
  3. Technical Architecture: Investing time in solid foundations pays dividends when adding features
  4. AI as a Tool: Modern AI can augment small teams but requires thoughtful integration
  5. Iteration Importance: The utility AI and card systems improved dramatically through multiple iterations

The combination of technical depth and creative design made Dungeon Slayer both challenging to develop and rewarding to play. Leading the development of core systems while collaborating on the broader vision provided invaluable experience in both technical leadership and team coordination.


Dungeon Slayer was developed using Unreal Engine 5 as part of CS3247 Game Development. Team members: Gerard Jeremiah Matthew, Lai Yiwen, Li Chengzhen, Lin Yuxiang, Ma Yirui, Zhang Puyu.

Technologies Used: Unreal Engine 5, C++, Blueprint Visual Scripting, Stable Diffusion, Suno AI, Udio, ElevenLabs

My Primary Contributions: Modular Card Crafting System, Utility-Based AI System, Game Concept and Mechanic Design, System Integration

This post is licensed under CC BY 4.0 by the author.