Cursor x AdTech Hackathon
Built Whitespace, an online tool aimed at collecting brand knowledge using Tavily, and then using that knowledge to generate ad copy.
Built Whitespace, an online tool aimed at collecting brand knowledge using Tavily, and then using that knowledge to generate ad copy.
Completed a procedurally generated dungeon crawler in Unity. Submitted as my Capstone Project for my final year of University, and released on Itch.io.
Client Project: 'Slackers'
Semester 1 - 2025| Student Name: | Stephen Purdue |
| Student ID: | 2301815 |
| Course: | BSc, Computer Games Design & Development |
| Module: | DM3108 - Negotiated Design Placement |
| Word Count: | 4796 |
| Date of Submission: | 16/01/2026 - Before 12:00pm |
GitHub Repository: https://github.com/stephendpurdue/Slackers
Images will open in a separate tab if clicked on!
The project 'Slackers' is a brief given by RaRa Games in response to DM3108 - Negotiated Design Placement. It explores a unique game concept involving disguised aliens within human workplaces. The objective is to create a prototype that uses a gameplay loop centred around chaos and sabotage, similar to Among Us (InnerSloth, 2018).
This prototype game will focus on a well-created mechanic, such as sabotage actions, enemy chasing, or the ability to change disguises. Players will navigate a small environment, such as an office, completing 'actions' and remaining anonymous to the AI.
The primary goal is to develop an MVP vertical slice, featuring core features that can be expanded upon in next semester's final project. This project will be created using Unity, and both a game design document and a Kanban board will be utilised to track the development cycle and manage time throughout the module. This development cycle strikes a balance between needs and wants, promoting sustainable choices that align with Sustainable Development Goal 12 (United Nations, 2024) by encouraging responsible production and development.
The brief provided was open to interpretation, and left workplace setting selection to developers, specifying the game should involve disguised 'aliens' within human workplaces, with chaos and sabotage mechanics. This presented me with an opportunity to express creative freedom, allowing me to select an environment which would best convey my design methods, making use of available assets. Initial ideas focused on the most obvious interpretation, an office environment with direct office culture and sabotage opportunities (coffee machines, printers, and computers).
However, two key factors caused a shift towards a more open environment.
Trello Board: https://trello.com/b/KgaZg9SP/slackers
Before beginning development, I conducted a comparative analysis of current titles in the chaos gameplay genre to identify design patterns that create engaging player experiences. This research went on to directly inform design choices and assets used in development.
The chaos gameplay genre relates to games in which player actions create disorder and escalating chaos, which have a direct impact on the world. Three games stood out for understanding how these mechanics function successfully: Among Us (InnerSloth, 2018), Overcooked (Ghost Town Games, 2016), and Untitled Goose Game (House House, 2019). Each of these games has a different approach to chaos systems, offering distinctly different gameplay and lessons that can be applicable to Slackers.
Among Us shows how sabotage can serve multiple purposes beyond immediate disruption. For example, when a player sabotages oxygen or lighting systems, both environmental and social chaos are created. The affected systems need to be fixed, and crew members must decide whether to call an emergency meeting or continue with tasks, weakening group coordination and potentially leading to further chaos. Critically, Among Us sabotage actions rely on cooldown timers to prevent overuse and encourage more strategic timing, which can have a direct impact on certain events. The game's success shows that sabotage gameplay remains engaging, despite there being only six sabotage actions, provided that each is used strategically. For Slackers, this informed my decision to create one or two well-polished mechanics, rather than numerous weak ones. This reinforces the idea of creating a polished vertical slice, rather than a weaker full title.
However, Among Us mostly relies on social deception between other players, translating this into a single-player game required a look at how chaos can function without social dynamics. Overcooked informed how cooperative chaos can function through environmental design rather than deception alone. Overcooked creates disorder through time pressure and spatial constraints; players must navigate through tight environments while managing multiple tasks on a strict schedule (Ghost Town Games, 2016). This game compounds simple mechanics into complex situations by layering them together with added pressure from a timer. I read into the (MDA) Mechanics, Dynamics, Aesthetics framework, where simple mechanics, such as chopping vegetables, produce dynamics such as team coordination, to generate the aesthetic experience fast paced cooperation (Hunicke et al. 2004)
This helped to inform Slackers, as it was clear that sabotage mechanics should have cascading effects and consequences, rather than isolated ones. For example, interacting with an item in-game shouldn't only create audio and visual effects, but also attract nearby enemies. This opens up room for secondary sabotage opportunities and experimenting with various mechanics to have intentional and unintentional gameplay effects.
Untitled Goose Game gave insight into how sabotage works in asymmetric power dynamics. The player runs within systems designed to constrain them, eg, gardens have fences, and shopkeepers will chase intruders, etc. This creates satisfying gameplay because the player operates from a position of weakness, allowing for satisfying and hilarious in-game actions, such as stealing a rake, prompting a response from an NPC, and turning a simple interaction into comedic sabotage.
This informed Slackers' AI system; the player isn't more powerful than enemies to the point where it isn't engaging. Tension is created by avoiding detection while completing objectives. Schell's Lens of Challenge states that difficulty should arise from making decisions under pressure and adapting to ongoing changes (Schell, 2008). Slackers utilise this by having NPC patrol routes, allowing players to time decisions and actions.
Implementing an effective AI detection required understanding how stealth games balance visibility, tension and player autonomy. Traditional stealth titles such as Metal Gear Solid employ cone-of-vision mechanics where players are detected when entering an enemy's sight range, which is typically visualised by an on-screen indicator. This provides clear feedback about hostile areas, allowing players to make informed decisions, rather than guessing what triggers detection.
These insights directly informed the detection system used in Slackers, as detailed in the development section's AI Detection System breakdown.
During this vertical slice, I played the role of both Game Developer & Producer, guiding both the development and production of the entire product. This allowed me to create assets and systems on a schedule that worked for me, and I was able to maintain a level of control over all aspects of development.
Throughout production, I aimed to link closely to the Sustainable Development Goals by following these key steps:
Development prioritised code reusability to minimise technical debt; this involved using inheritance so that core interaction logic didn't have to be rewritten for certain aspects of the slice. These steps helped ensure alignment with the ethical values and qualities of game development, as outlined throughout the SDGs.
Reusing assets in the Tiny Swords pack eliminated approximately 20-40 hours of custom sprite creation and learning; this also reduces computational resources used in asset creation and development. This decision aligns with SDG 12.2's principle of sustainable resource management, as well as SGD 4's principle of improving peoples lives through sustainable practices.
However, time constraints led to technical debt that will require future changes. Some values were hardcoded, such as damage numbers and flipping scales. This could create a future burden to development and maintenance should this slice be taken further. Code documentation in GitHub and Unity lacks sufficient information for external developers to understand how I worked, which could slow down future collaborative development.
Creating comedy about workplace environments and sabotage has ethical risks that require consideration; some harmful stereotypes could have been insinuated had I gone with a typical office environment. Therefore, I chose to go for an absurd medieval theme with no distinguishable stereotypes.
| Need/Want | Why? | Status |
|---|---|---|
| AI Chase Mechanics (Need) | Part of the core gameplay loop. | Completed |
| Health System (Need) | Visualises consequences of detection. | Completed |
| Disguise System (Need) | Core brief requirement. | Completed |
| Sabotage System (Need) | Core brief requirement. | On-Hold |
| Tutorial System (Want) | Critical to player accessibility, but not as important as core requirements. | On-Hold |
I had initially set the Tutorial as a need and was to be one of the first aspects of the game completed after the core gameplay loop. However, since the game was only a vertical slice with only one or two mechanics, I included on-screen queues to help with accessibility, removing the need for a tutorial.
Game development is a complex process, requiring meticulous detail and extreme flexibility. I chose to use a Kanban, which uses online planning tools such as Trello to manage tasks and track progress (Atlassian, 2024). I felt this was the best option for time management, as it uses a visual interface to track every aspect of the game development cycle. Kanban was chosen rather than Scrum because it gave a more visual structure for planning development, which is beneficial for a solo developer. Once the board was created, I added different categories, setting the primary focus on building a working product before addressing any bug fixes or further development. This ensured a prototype could be created much quicker, leaving more time for adding extras and fixing any bugs. This structure allowed for an organised and clear workflow that ensured smooth production and is similar to industry-standard planning.
The board was split into 7 columns:
The most important task was identifying current bugs and backlog of tasks, which required an immense amount of time testing the game, each mechanic and reviewing all scripts and assets to ensure they worked as intended.
Before starting the development process, I set out goals for the Minimum Viable Product. This was an important stage of production that involved analysing the client brief and highlighting essential mechanics that required high priority. This ensured there was a playable prototype. The purpose of creating the MVP was to capture the game's core mechanics in a clean and polished playable slice. This included systems such as 'Sabotage' or 'Destroy', as well as basic enemy AI detection, to add some challenge.
Throughout the development pipeline, I revisited the brief and constantly evaluated whether the slice I was creating met all the key criteria. If it didn't, I stopped to figure out why and made changes accordingly, ensuring that the client brief was met.
During development, I kept track using a comprehensive game design document, which contains all relevant information about the vertical slice, such as UI, enemy interactions, and audio; this was important so the project could stay on track, allowing time for bug fixing and extra details.
The game design document can be viewed here.
GitHub was also used as a backup for storage and version control. I felt this was more efficient than Unity Version Control, as I am more familiar with Git; this also acts as a 'portfolio' to showcase the project to other developers.
The GitHub repository can be viewed here.
Given the independent nature of the brief, formal client communication outside of development was limited. To help compensate for this constraint, I used self-evaluation at regular intervals to assess my progression and time management. This involved regular playtesting to identify and eliminate bugs, as well as ongoing review of the brief to ensure alignment with client needs and requirements.
Tutorial sessions over the semester enabled me to ask questions about the brief and receive suggestions as to what to implement and how this could be achieved; these focused on technical aspects rather than specific design questions or pointers.
The primary limitation of communication as an absence of engagement with the client (RaRa Games). Typical practice requires regular checkpoints and discussions in order to ensure the product meets client expectations, needs, and wants.
Accessibility was an important consideration throughout the design and development of Slackers. Although it wasn't a high priority, it was tackled through using clear visual communication practices, a readable user interface design, and simple interaction systems to ensure the game was easy to play and open to all players.
High contrast colours and a consistent art style were used to increase visual clarity and ensure complete visibility. I chose to keep the user interface as text to ensure it was visible against the bright background. The characters and NPCs are also clearly distinguishable from each other through different colours and sprites.
The disguise system also increases overall accessibility by providing players with a forgiving stealth mechanic, changing disguises resets enemy detection states, allowing players to recover from mistakes rather than facing repeated failure. This supports inclusive play by reducing difficulty, coinciding with Schell's lens of challenge, which says that meaningful decision-making is favourable over mechanical punishment.
However, several accessibility concerns remain due to time constraints and the overall scope of the brief. The game doesn't have any changeable colourblind, difficulty or audio settings, as well as lacking rebindable controls. Additionally, font size and UI scaling are fixed and cannot be changed; this could present barriers for some users.
Future development would benefit significantly from adding accessibility earlier in the development pipeline, rather than leaving it until last. Improvements would include an adjustable difficulty setting, remappable controls, and scalable UI components. This could involve accessibility beta testing with a diverse group to determine what features are a priority and should be added first.
When starting the project, one of the most important early decisions involved selecting the right visual assets. For this project, I chose to use the 'Tiny Swords' asset pack found on itch.io, a platform for indie developers to share assets. This pack stood out because of its beautiful art aesthetic, ideal for slackers. This pack was free and did not require any artist accreditation.
During Development, I used Unity Version Control to track and roll back changes. Should problems arise during the development cycle, more than 50 changes were logged, ranging from new systems to bug fixes. Documentation was kept within Unity, so detailed titles were used to outline changes.
When creating the environment, I chose to use a 2D tilemap. This was to keep the workflow manageable and remove the obstacle of having to create and reuse a large number of assets. This worked well for Slackers, as I was able to put more time into creating a polished mechanic, rather than a detailed environment.
I chose to use Unity's tilemap system due to its simplicity and accessibility. Layers were created for Ground, Elevation, Interactive Objects, and Decorations, in order for collision to work correctly. The elevation was extremely simple, using a Tilemap Collider in order to detect player collision.
The first iteration featured an extremely open environment, prioritising a working environment to test player movement and collision. This evolved into a more functional world, with distinct zones. Zone-based architecture was key in providing spatial rhythm, alternating between quiet and exposed areas, creating tension and altering player movement. Decorations were left for later in the development cycle, as priority was placed on getting base mechanics working, rather than small details.
Future development would benefit from earlier paper prototyping before implementing a complete tilemap, as the redesign showed substantial wasted effort. The final environment successfully balances visual fidelity with gameplay opportunities and a zone-based approach.
The environment's tilemap system required balancing visual depth and functional gameplay collision. This was implemented using Unity's tilemap layering system across eight distinct layers organised by rendering order.
I faced a technical challenge with elevated terrain boundaries. Unity's automatic tilemap collider creates collision along tile edges, but doesn't inherently prevent players from moving from high to low elevation areas in the 2D top-down perspective.
Rather than solving this through configuring proper 2D physics, I implemented a basic workaround: manually placing invisible GameObject boxes with BoxCollider components attached; they were then made invisible to stop players from moving into void areas. This did, however, require placing each object manually, surrounding each elevated area. I chose to stick with this solution, as 'if it works and doesn't break, ship it'.
Following the stealth system design principles identified during research, the implemented AI detection system focuses on balanced challenge and simplified mechanics, which are more appropriate for a polished vertical slice given the time constraints.
The AI detection system uses Unity's 2D trigger collision to create proximity-based chase behaviour. This favours simplicity over a more complex detection system. Each NPC possesses a CircleCollider2D trigger zone with a 4-meter radius outlining the detection range. When the player enters this area, OnTriggerEnter2D() executes, storing the player's transform reference and transitioning the NPC from Idle to Chasing via an enum-based state machine. During chase, FixedUpdate() calculates a direction vector from NPC to player and applies velocity to move towards the player. When starting, enemies were too fast and could outrun the player, causing an unfair scenario. Learning from this, I chose to set the default speed as 4 per second, so that the enemy is challenging, yet could be outrun. The NPC's sprite automatically flips based on the player's position to prevent it from facing the wrong direction. The initial attempts at creating this component were challenging and resulted in inverted flip logic, as each attempt at adding a new component to the script would cause it to start flipping to the wrong direction. This was fixed by hard-coding values so that it is facing either 1 or -1.
When the player exits the detection zone, OnTriggerExit2D() reduces the NPC's velocity to zero, clearing the player reference and returning to an Idle state. This is managed by Unity's animator component, with the ChangeState() method managing the animation boolean values: isIdle & isChasing. The isTrigger based approach provides clear detection for enemies, allowing them to remain idle or chase based on player proximity. When testing this system, the initial detection range was reduced from 7 to 4, as it was a bit too sensitive and would sometimes detect players before they were even on-screen.
My interpretation of the brief involved creating an outdoor goblin mine working environment, under siege by a band of crusaders. I felt this worked extremely well with the chosen art style and brief, as it allowed me to create a basic environment and focus more on mechanics, rather than creating a detailed indoor office.
The disguise change mechanic is the game's primary stealth tool and directly links to the brief's core requirement for alien operatives to maintain cover while executing workplace sabotage. This system allows players to reset enemy detection states by changing character sprites at the 'Goblin Hut', providing a method of remaining anonymous. Rather than focus on creating multiple points, I chose to provide one disguise station and ensured that it was working properly.
The disguise system runs through a static interaction point positioned close to the mine environment. When the character enters the huts four meter trigger radius, an on-screen prompt appears: 'Press [E] to Change Disguise'. Activating this triggers an instant sprite swap, cycling the player's sprite between one of three available outfits: the default Knight, a Goblin worker, and a Peasant Villager. Each is unique from the others, and provide choice when attempting to change disguise. Once the player activates the change, the player's SpriteRenderer is updated to the new sprite, and a reset command is sent to the Enemy_Movement script to reset their detection states.
Enemies that are currently chasing a player when a disguise change is activated are subject to an immediate state transition, their velocities are zeroed, and their state machines execute a forced return to the idle state. This creates a sense of awareness loss, allowing the player to resume as if they had never been spotted. I chose this way, rather than use gradual detection states, as it offers a consistent result that works every time.
In Conclusion, the disguise change mechanic is successful in providing a concrete system that addresses the brief's stealth requirements, because there is an on-screen prompt, players can use this to plan and change disguises as needed. For a vertical slice focused on polished mechanics done well rather than many mechanics done poorly, this is an excellent addition to the core gameplay loop.
The health system and user interface were another key mechanic to be worked on. The health mechanics were created from scratch using the Player_Health and Enemy_Combat scripts.
To start, a RigidBody2D was added to the Enemy_Torch so that damage could be added on contact. In Player_Health, two variables were used to decide maxHealth and currentHealth; these were then called in a public variable called ChangeHealth, which detected any damage and changed health accordingly. It also set the Player GameObject to false when health reached 0. Enemy_Combat was extremely simple, declaring a public integer for damage and setting it to 1, and changing the collided player's health by -1 upon impact.
The UI was created using an Image Canvas, anchored to the top left of the screen. The sprite used was a horizontal banner image from the same asset pack. This was relatively easy to implement, simply requiring a reference in the PlayerHealth script, as well as an animation to add the 'bounce' effect upon health loss.
Each entity was animated using Unity's built-in animator tool, splicing each sprite's PNGs together and spreading them across 30 - 60 frames in order to create a Zelda-like animation. Each had two base animations: Idle and Running.
During development, one bug I faced early on was the main player character falling through the map after applying a RigidBody2D component. This was particularly frustrating, as it prevented any meaningful testing or progress, due to the character falling out of bounds. The default gravity scale was causing the character to fall quicker than the collision detection system could register contact with the ground, as well as the character's rotation not being constrained, causing unwanted rotation and tilting. However, it was an easy fix; in the Unity Inspector, the gravity scale was reduced to zero, and I also froze the z-rotation to prevent any unwanted rotation resulting from in-game actions.
Another bug was found during the creation of character movement. When the movement button was released, the character continued to move for a short time. This was fixed by changing Input.GetAxis to Input.GetAxisRaw. This worked because of Input.GetAxis tries to slow the movement gradually when using a lower gravity setting; the latter doesn't do this, allowing for the character to cease movement immediately upon button release.
The most significant limitation of this project was the absence of external evaluation and playtesting, which fundamentally undermined the ability to check design effectiveness and highlighted a critical failure, unlike in professional practice. While the developed prototype represents competent core systems, the lack of structured feedback leaves questions about player experience, design balance and accessibility unanswered.
Typically, professional game development requires external iterative playtesting throughout the development cycle, even for a slice of gameplay. For Slackers, this would have been conducted in multiple testing phases with data collection that could be analysed and actioned.
Early-stage testing should have involved prototype testing with 3-4 external participants to help validate the core loop. Questions would have been asked, such as: Do players understand the objective? Is there a balance between detection and anonymity? This would have helped with idea iteration before committing development time to specific areas.
Mid-stage testing would have required 6-8 participants and an evaluation of the whole prototype. Players would have been observed on how they interacted with the environment, difficult areas, and any bugs that appeared. Data would have been collected and then acted upon before moving into the polish / bug-fixing phase of development.
Late-stage testing would have involved beta testing with 10-20 participants to identify accessibility issues and bugs. Following typical game development practices, this data would have been used post-release, implementing fixes after launch.
While this is a significant gap in development, the technical skills gained during this project are invaluable (Animation, Scripting, Environment Design) and will help create a well-polished final project. Overall, the skills used throughout the project help promote sustainable resource use outlined in SDG 12, as well as improving the lives of ordinary people by promoting sustainable values in relation to SDG 4.
The Slackers prototype successfully demonstrates the feasibility of chaos gameplay within the constraints of an MVP vertical slice. Through systematic iteration, the project delivers a working prototype that highlights mechanics required in the brief, combining 'sabotage' and 'stealth' systems in order to create engaging gameplay when properly balanced and designed. Working on this project in conjunction with RaRa Games this semester has been an invaluable experience, resulting in a full playable vertical slice. This opportunity allowed me to enhance my technical skills in environment creation, animation, and optimisation.
Primary strengths lie in project management and technical implementation. The Kanban methodology with Trello tracking allowed for organised development, prioritising MVP critical features while putting secondary elements on the backlog, to maintain effective time management. Zone-based environmental architecture creates strategic and tense gameplay, ensuring the player makes smart choices based on environmental hazards. Documentation practices, including a comprehensive Game Design Document and version control workflow, reflect industry standard practices and demonstrate professional development practices applicable to real projects.
While not all the mechanics were created, I am pleased that a polished chase and disguise mechanic could be created and implemented effectively, this does however link closely to the brief, by creating polished mechanics, rather than mediocre ones at an attempt to meet all the requirements. The experience gained from this project will feed directly into the final project for next semester, allowing me to create a full game rather than just a slice of gameplay.
Ghost Town Games (2016) Overcooked. Team17. (Video Game)
House House (2019) Untitled Goose Game. Panic. (Video Game)
Hunicke, R., Leblanc, M. and Zubek, R. (2004). (PDF) MDA: A formal approach to game design and game research. [online] ResearchGate. Available at: https://www.researchgate.net/publication/228884866_MDA_A_Formal_Approach_to_Game_Design_and_Game_Research.
InnerSloth (2018) Among Us. InnerSloth. (Video Game)
itch.io. (2026). Tiny Swords. [online] Available at: https://pixelfrog-assets.itch.io/tiny-swords?download
Konami (1998) Metal Gear Solid. Konami (Video Game)
Radigan, D. (2024). What is Kanban? [online] Atlassian. Available at: https://www.atlassian.com/agile/kanban.
Schell, J. (2008). The Art of Game Design. [online] Available at: https://www.inventoridigiochi.it/wp-content/uploads/2020/07/art-of-game-design.pdf.
United Nations (2025). Goal 12 | Ensure sustainable consumption and production patterns. [online] United Nations. Available at: https://sdgs.un.org/goals/goal12.
Haki (2023). Building a State Machine in Unity With C# - Haki - Medium. [online] Medium. Available at: https://medium.com/@jojackblack/building-a-state-machine-in-unity-with-c-b1c7c9c80a04.
itch.io. (n.d.). Pixel Frog. [online] Available at: https://pixelfrog-assets.itch.io/.
Unity Learn. (n.d.). Beginner Scripting. [online] Available at: https://learn.unity.com/course/beginner-scripting.
Unity Learn. (n.d.). Importing Assets. [online] Available at: https://learn.unity.com/tutorial/importing-assets.
Unity Learn. (2019). Unity Learn. [online] Available at: https://learn.unity.com/tutorial/animating-a-sprite-with-the-2d-animation-package
Unity Learn. (2019). Unity Learn. [online] Available at: https://learn.unity.com/tutorial/applying-2d-colliders-for-physics-interactions
Unity Learn. (2019). Unity Learn. [online] Available at: https://learn.unity.com/tutorial/controlling-unity-camera-behaviour-2019-3
Unity Learn. (2019). Unity Learn. [online] Available at: https://learn.unity.com/tutorial/introduction-to-tilemaps-2019-3
Unity Learn. (2019). Unity Learn. [online] Available at: https://learn.unity.com/tutorial/working-with-hexagonal-and-isometric-tile-shapes
Unity Technologies (2019). Unity - Manual: Unity User Manual (2019.2). [online] Unity3d.com. Available at: https://docs.unity3d.com/Manual/index.html.
Research Project: 'Synapse'
Semester 2 - 2026| Student Name: | Stephen Purdue |
| Student ID: | 2301815 |
| Course: | BSc, Computer Games Design & Development. |
| Module: | DM3107 - Major Research Project. |
| Word Count: | 2000 +10% |
| Date of Submission: | 15/05/2026 - Before 12:00pm |
Images will open in a separate tab if clicked on!
GitHub Repository: https://github.com/stephendpurdue/Synapse
This project represents the practical continuation of theoretical research conducted in Semester 1: Failure as Feedback: Investigating the Role of Experimentation and Failure in Player Learning and Engagement within Systemic Games, which investigated the role of failure as a learning tool within systemic games. That research established a theoretical framework for further study through comparative analysis of four titles: Dark Souls 3 (FromSoftware, 2016), Celeste (Maddy Makes Games, 2018), Outer Wilds (Mobius Digital, 2019), and Breath of the Wild (Nintendo, 2017). This research identified key design principles that are successful in transforming failure from a punitive measure into productive and useful learning opportunities, supported by Constructivist Learning Theory (Piaget, 1972; Vygotsky, 1978), Kolb’s Learning Cycle (Kolb, 1984), Flow Theory (Csikszentmihalyi, 1990), and Self-Determination Theory (Deci & Ryan, 1985).
This project delivers a polished vertical slice in Unity, featuring a third-person combat arena, a PPO-trained boss opponent with adaptive move sets, and real-time performance calibration to adjust attack patterns and overall aggression. This focuses on a single, well-crafted encounter to enable comprehensive training within the allotted time and to serve as a proof of concept that machine learning systems are efficient in systemic, failure-driven game development. Moving further, this project demonstrates the creation and implementation of inclusive and sustainable learning practices, allowing players to learn new skills and adapt to challenges, regardless of current skill level, linking with Sustainable Development Goal 4. The following section details how specific findings from the Semester 1 case study analysis directly informed the technical design decisions implemented in this vertical slice.
The case study analysis revealed three key design principles that directly informed technical decisions, but also a critical tension. The examination of Dark Souls 3 showed that pattern recognition and predictable boss attacks create a foundation for victory; the Pontiff Sulyvahn encounter exemplifies how predictable attacks help construct mental models through constant repetition, aligning with Kolb’s ‘abstract conceptualisation’ stage. This finding helped shape the core technical decision of developing a system that uses Proximal Policy Optimisation reinforcement learning within Unity’s ML-Agents toolkit. The agent observes the player's health percentage and attack frequency, calibrating the boss's behaviour accordingly.
The analysis of Celeste concluded that instant respawns that compress failure loops into 10-15 second intervals help sustain the player's flow state by reducing downtime between run attempts, encouraging rapid iteration without consequences. The analysis of Outer Wilds’ time-loop mechanic showed that knowledge persistence transforms punitive failure into cumulative progress, demonstrating that even deaths contribute to a player's understanding of the game.
However, the analysis exposed a critical tension: Celeste’s minimal punishment helps maintain flow but reduces the impact of failure, whereas Dark Souls 3’s lengthy runbacks intentionally disrupt flow, heightening the impact of failure, resulting in reflection. This raised the question of whether a machine learning algorithm can balance these two conflicting ideas, adapting to encounter difficulty and consequences.
After theoretical research, I concluded that optimal learning occurs at the intersection of Vygotsky’s Zone of Proximal Development and Csikszentmihalyi’s Flow State, where challenges are slightly beyond the player's current ability, yet still achievable through practice and achieving a flow state. This is another key principle that informed the use of an adaptive difficulty system. Where previous research aimed to discover the effectiveness of failure as a learning mechanism, this project is a technical demonstration, evaluating how machine learning can contribute to failure-based learning tools.
Following the Dark Souls 3 analysis of the Pontiff Sulyvahn encounter, which identified the importance of spatial awareness when recognising attack patterns, particularly in encounters with 1.5-second attack telegraphs. I implemented Unity’s Cinemachine third-person camera system with 360-degree orbital tracking, aligning with Kolb’s reflective observation stage by ensuring constant visual contact with the boss during attempts. This fixes the issue in Semester 1’s research, as the boss will be completely visible, reducing the chance of dying to attacks caused by irregular camera movement.
Player movement uses Unity’s event-driven input system, utilising Celeste’s rapid iteration principle of 10-15-second failure loops to minimise latency and maintain flow. The input action map system (Figure 1), also enables cross-platform accessibility, aligning with Self-Determination Theory’s autonomy principle by allowing more diverse input methods and reducing hardware constraints that could disrupt engagement. I also chose to implement unit tests (Figure 4), to ensure each component worked as expected on build.
These infrastructure components provide the stable foundation for failure-based learning. The camera ensures players have sufficient spatial awareness, while responsive input enables rapid iteration and experimentation, supporting flow consistency. Together, they form the basis on which the ML agent introduces calibrated difficulty variation. It is important to understand that an adaptive AI boss enemy could feel like cheating to players, if they aren't aware that the difficulty adjusts based on performance, which could undermine the perceived fairness of the game, and put people off.
Unity ML-Agents is an open-source tool developed by Unity that allows games to act as environments for agent training using reinforcement learning. This slice implements Proximal Policy Optimisation (PPO), an algorithm developed by OpenAI that is valued for its training stability (Schulman, 2017). PPO works by limiting how drastically the policy (the agent's decision-making) can change between training steps, preventing forgetting that was common in earlier algorithms. This allows the boss to develop adaptive behaviour rather than simple scripted responses, and creates a practical outcome of the Semester 1 finding that optimal learning occurs when challenges remain slightly beyond current ability, yet are achievable through iteration.
The ZombieAgent observes a 5-dimensional state vector at five key decision points: Player Health Percentage (0.0-1.0) tracked via the PlayerHealth components HealthSystem. Player Attack Frequency, (0.0-1.0) calculated through the PlayerAttackTracker monitoring for successful attacks over a rolling five-second window. Initially, a lower window of 3 seconds was used, but this proved overly aggressive against the boss. Distance to player (0.0-1.0) tracked against a 20-meter max range. Boss Health Percentage (0.0-1.0) tracked by the agent’s HealthSystem. Attack Cooldown (0.0-1.0) normalised against the 1.5-second cooldown period. This observation space was designed to operate within ZPD boundaries, with the player's health percentage directly affecting the challenge: high health signals to the agent that the difficulty is insufficient, while low health signals that it is intense. Attack frequency helps identify a player's offensive ability and engagement, allowing distance and cooldown decisions to be made accordingly. All observations are capped at the (0.0-1.0) range to ensure stable PPO updates during agent training.
While boss health is included in observations, it serves tactical rather than strategic purposes. The agent uses its own health to gauge engagement intensity and risk, but the reward function is calibrated more towards the player, ensuring the agent optimises for learning goals rather than self-preservation. This design decision prevents the agent from learning defensive behaviours that could create an unfair encounter or eliminate the player's flow-state. (Figure 5 - 5.3)
The ZombieAgent controls boss behaviour through a hybrid action space approach: two continuous action parameters controlling movement (moveX and moveZ, each with ranges of (-1.0, 1.0), and one discrete action with two branches (0 = no attack, 1 = attack). Continuous movement actions enable smooth navigation toward or away from the player, whereas discrete actions provide clear decision points for attacking. The ZombieController executes these actions, updating the animator based on movement, triggering an attack state when the discrete action fires within the attack range (1.5 metres) and outside the cooldown period (1.5 seconds).
Following the Dark Souls 3 principle that pattern recognition requires consistent consequence, attack damage remains fixed at 10 points per hit; the agent is unable to alter this. This helps to turn failure into an information source, ensuring players can learn rather than dying to random spikes in boss damage. The action space design resolves the Celeste minimal-punishment versus Dark Souls consistent-consequence tension identified in Semester 1 by enabling adaptive difficulty through behavioural parameters (attack frequency and movement aggression), while maintaining damage consistency.
The reward function is extremely important to the whole system, as it is how the agent learns good and bad behaviours. I designed this function to balance multiple objectives: maintaining engagement, creating challenges, and preserving the learning value of failure.
Outlined below is a table describing each behaviour, its reward, and the reason behind each.
| Behaviour: | Reward: | Reasoning: |
|---|---|---|
| Dealing damage to the player. | +0.1 | Encourages aggression. |
| Getting closer to the player. | +0.01 | Encourages engagement. |
| Staying too far from the player. | -0.01 | Punishment for being too passive. |
| Surviving each step. | +0.001 | Encourages survival. |
| Killing the player too fast. | -0.5 | Punishes overwhelming difficulty. |
| The player gets low health. | +0.2 | Rewards threatening the player. |
| The boss takes damage. | -0.05 | Encourages self-preservation / survival. |
Training completed after around 320,000 steps, with cumulative reward rising from zero to 25.68 and stabilising around 50,000 steps, (Figure 2). The value loss decreased over time from 0.15 to 0.035, indicating that the agent developed increasingly accurate predictions of potential future rewards. Policy loss varied between 0.066 and 0.074 throughout training, suggesting that the neural network identified a stable strategy rather than resorting to the common forgetful characteristics of earlier reinforcement learning algorithms, (Figure 3). While these metrics do confirm that training converged on a stable policy, they measure the consistency of the agent's internal training, not actual gameplay; this would require significantly more testing, including the data gathered from inference, and external players.
Following the training, I tested the agent in inference mode to determine if the learned behaviour aligned with the overall goal of the project. After testing across ten separate encounters, I identified a clear pattern: The agent consistently demonstrated balanced and adaptive behaviour, pursuit was started immediately, maintaining aggression without overwhelming difficulty, and each encounter lasted between 15 and 30 seconds on average. This duration supported Celeste’s rapid iteration principle, while avoiding the lengthy runbacks of Dark Souls.
However, due to computational and time constraints, I was unable to complete any formal validation of this training. Had time permitted, validation would have consisted of end-user testing to gather metrics on engagement, how many times a player dies, and overall boss aggression, this could have been used to tweak the configuration for the boss, should this have been conducted. Initial testing runs indicated true validation would require approximately 500-800 training episodes, which would require 15-20 hours of continuous agent training, which exceeded what I had available for idle training. Additionally, the training process would have benefited from a human player to test the trained neural network, providing feedback on how the algorithm performed, as well as what could be improved. The main takeaway from this project was a trained agent which provided technical feasibility of the core hypothesis. The trained agent helps players maintain flow and encourages learning and meaningful gameplay.
During agent training, there was one consistent bug that persisted through multiple attempted fixes: once training began, the boss would run laps around the player at normal speeds, and wouldn’t attack the player at all. The debugging process for this was time-consuming and showed a gap in my understanding of how NavMesh assets work. Eventually, the root-cause of the bug was found, the NavMesh Agent’s stopping distance was set to 1.4, which prevented the boss from entering the 1.5 attack range. Setting the stopping distance to zero and implementing manual logic in OnActionReceived resolved it, but the trial-and-error fixing process lasted several hours, eating into the time I had allocated for training.
After thorough testing of the learning algorithm, I believe this slice demonstrates that PPO reinforcement learning can be effectively used to promote failure-based learning principles, particularly those identified in Semester 1’s case study analysis. After training, an agent was produced which maintained encounter durations of 15-30 seconds and balanced challenge, linking to both Vygotsky’s Zone of Proximal Development and Csikszentmihalyi’s Flow State. While computational and time constraints prevented formal player testing, inference testing confirmed that the agent was successful in turning the key principles of failure-based learning into an implementable, adaptive algorithm.
This project has the potential for further adaptation and progression, such as accessibility features or personal difficulty calibration through a menu screen. Educational game development could implement automated systems in order to teach learners who struggle with typical difficulty selection systems, while commercial applications of this project could enhance player retention by implementing further skill-based systems and mechanics, such as quests or difficulty calibration. Future adaptations should use more comprehensive training cycles with larger episode counts and actual formal testing with other people.
Csikszentmihalyi, M. (1990). Flow: the psychology of optimal experience. 1st ed. [online] Colorado Mountain College. New York: Harper & Row. Available at: https://cmc.marmot.org/Record/.b10803749.
Csikszentmihalyi, M., Abuhamdeh, S. and Nakamura, J. (2014). Flow. Flow and the Foundations of Positive Psychology, [online] pp.227–238. doi:https://doi.org/10.1007/978-94-017-9088-8_15.
Deci, E. L., & Ryan, R. M. (1985). Intrinsic motivation and self-determination in human behaviour. New York: Plenum Press. [online]
FromSoftware. (2016). Dark Souls III [Video game]. Bandai Namco Entertainment.
Kolb, D. (1984). Experiential Learning: Experience As The Source Of Learning And Development Executive skills of Family Medicine Faculty View project How You Learn Is How You Live View project. [online] Available at: https://carleton-wp-production.s3.amazonaws.com/uploads/sites/313/2022/12/Experiential_Learning_Experience_As_The_Source_Of_-1.pdf.
Maddy Makes Games. (2018). Celeste [Video game]. Self-published.
McLeod, S. (2025). Constructivism Learning Theory & Philosophy of Education. [online] Simply Psychology. Available at: https://www.simplypsychology.org/constructivism.html.
McLeod, S. (2025). Piaget's cognitive stages of development. [online] Simply Psychology. Available at: https://www.simplypsychology.org/piaget.html.
Mobius Digital. (2019). Outer Wilds [Video game]. Annapurna Interactive.
Nintendo. (2017). The Legend of Zelda: Breath of the Wild [Video game]. Nintendo.
Piaget, J. (1972). The psychology of the child. [online] New York: Basic Books.
Schulman, J., Wolski, F., Dhariwal, P., Radford, A. and Klimov, O. (2017). Proximal Policy Optimization Algorithms. [online] arXiv.org. Available at: https://arxiv.org/abs/1707.06347.
Vygotsky, L. S. (1978). Mind in society: The development of higher psychological processes. Cambridge, MA: Harvard University Press. [online]
Hunicke, R. and Chapman, V. (2004) AI for dynamic difficulty adjustment in games. In: Challenges in Game Artificial Intelligence: Papers from the 2004 AAAI Workshop. Menlo Park, CA: AAAI Press, pp. 91–96. [online] Available at: https://www.semanticscholar.org/paper/AI-for-Dynamic-Difficulty-Adjustment-in-Games-Hunicke-Chapman/1e4d7627b2e343033a94f22f790e33727094ae05#paper-topics.
Unity. (2025). C# Code Style Guide (Unity 6 edition) | Unity. [online] Available at: https://unity.com/resources/c-sharp-style-guide-unity-6.
Unity. (2025). Unity ML-Agents Documentation (Unity 6 edition) | Unity. [online] Available at: https://docs.unity3d.com/6000.6/Documentation/Manual/com.unity.ml-agents.html
Openai.com. (2017). Proximal Policy Optimization. [online] Available at: https://openai.com/index/openai-baselines-ppo/.
Final Project: 'Exodus'
Semester 2 - 2026| Student Name: | Stephen Purdue |
| Student ID: | 2301815 |
| Course: | BSc, Computer Games Design & Development. |
| Module: | DM3103 - Final Project |
| Word Count: | 5000 +10% |
| Date of Submission: | 08/05/2026 - Before 12:00pm |
Images will open in a separate tab if clicked on!
This dissertation presents the design, implementation, and critical analysis process of a procedurally generated dungeon crawler developed with Unity, looking at the challenges of maintaining real-time performance while maximising replayability through algorithmic procedural generation. The project investigates Binary Space Partitioning (BSP) trees (Shaker, 2016) and the Random Walk algorithm as a method for generating unique environments, examining how a procedural algorithm can balance structure and gameplay variety. This research and practice demonstrate that while BSP & Random Walk excel at creating unique and coherent dungeons with consistent navigability, it requires extra randomisation techniques to prevent pattern recognition that emerges after repeated playthroughs.
The project architecture comprises three systems created in Unity: a BSP / Random Walk-based procedural generation algorithm that uses a queue to create interconnected environments, an objective system that adapts based on how many enemies are spawned, and a state-driven combat system including animations.
Comparative analysis evaluated the created system against current dungeon crawler titles, including The Binding of Isaac (McMillen, 2011), Enter the Gungeon (Dodge Roll, 2016), and Hades (Supergiant Games, 2020), examining environmental diversity and player engagement. This evaluation revealed that while BSP is computationally efficient, it produces less diverse environments than the hybrid generation methods used in the researched titles. Findings indicate that additional features, such as side-quests and win-conditions, are required to expand gameplay to the point where there is little to no repetition, and gameplay remains fun and engaging, highlighting the need to supplement algorithmic approaches with hand-crafted assets.
These findings have direct implications for independent game developers, where purely algorithmic generation can provide scalable content but must be balanced with hand-crafted systems to achieve high engagement and replayability, as is typical in roguelike titles.
GitHub repository: https://github.com/stephendpurdue/Exodus
Itch.io link: https://stephendpurdue.itch.io/exodus
Gameplay Video: https://youtu.be/fcwuSU7xZqE
Procedural content generation has become a defining trait in modern game development, enabling smaller indie studios to create expansive, replayable gameplay experiences without the resource-intensive demands of hand-crafted environments, used at more funded studios. Roguelike and dungeon crawler titles such as The Binding of Isaac, Enter the Gungeon, and Hades have become genre-defining examples that demonstrate the viability and success of using procedural generation algorithms, collectively generating millions in revenue, while maintaining engaged player bases years after launch. However, the technical implementation of procedural generation systems presents significant challenges; algorithmic generation must remain computationally efficient, balance environmental variety, and avoid predictable patterns to keep experiences unique and engaging.
This project investigates the design and implementation of a Binary Space Partitioning (BSP) tree algorithm for procedural dungeon generation in Unity. The following sections cover the comparative research conducted into existing titles, the technical implementation of the core gameplay loop, and a critical evaluation of the proposed research question: can a hybrid BSP and Random Walk algorithm produce dungeon environments with sufficient variety and coherence to sustain player engagement across multiple playthroughs, without relying solely on hand-crafted content pools, typically used by large studios?
BSP algorithms are used to recursively split a space into small segments and offer several advantages for real-time procedurally generated content (Michaels, 2020), especially computational and architectural efficiency, making them highly accessible for independent and indie developers. However, while there are benefits, there is still the question of long-term replayability and whether an algorithmic approach alone can generate sufficient variety to sustain player engagement across numerous playthroughs, or whether additional hand-crafted content is required to meet player expectations and produce equal opportunities for a smaller indie game that is typically successful in large AAA titles (United Nations, 2025).
To understand how successful titles approached procedural generation, three distinct titles were chosen for analysis. The Binding of Isaac (McMillen, 2011), Enter the Gungeon (Dodge Roll, 2016), and Hades (Supergiant Games, 2020). Each title uses a different approach to algorithmic generation and hand-crafted content; examining these differences helped to provide context for design decisions I made when creating Exodus.
The Binding of Isaac generates floor plans by expanding outward from a central starting room using a breadth-first random-walk algorithm. Each room can have a maximum of four neighbouring rooms, one for each side. This game uses a wide range of room placements, ensuring that each run is relatively unique and randomised compared to the last. Room interiors are pulled from a hand-crafted room pool, creating many combinations for each run. While this is fast and reliable, it can produce a limited variety for veteran players. From this, I decided to use solely generated rooms for Exodus, rather than a pool of hand-crafted ones, allowing unlimited variation in dungeon layout.
On the other hand, Enter the Gungeon uses a more structured approach. Rather than generating both the layout and room content at the same time, both are done separately. Each floor has a set of templates that define the main structure of the run, such as ensuring there is a shop before a boss fight or a secret room, etc. The procedural system used picks a template at random and then populates it with hand-crafted rooms. This ensures room quality is the same across runs, while the structure of each run is different. While this is an efficient method, it requires significant time investment, which is manageable for a larger, more funded studio but difficult for a smaller indie one.
Hades uses the least algorithmic approach of the three examples. Supergiant created a large pool of hand-crafted rooms for each biome, selecting from them during runtime using set rules rather than generating them procedurally. The procedural element of Hades is mainly in reward distribution, generating pots to destroy and other random rewards. Biome-specific rules decide what rooms spawn and when, for example, in Tartarus, smaller rooms are weighted to appear earlier, and larger rooms further into the run. This also provides consistent quality, but again requires significant studio investment.
Across all three titles, it is clear that each game supplements procedural generation with handcrafted content. The Binding of Isaac uses hand-crafted room pools, Enter the Gungeon uses hand-authored room templates, and Hades relies on hand-crafted chambers almost entirely.
When beginning development, the first task was to set up the initial project, including version control. Due to the size of the game, I chose to use both Unity Version Control and GitHub, ensuring that there are multiple backups of the game files in the event of user error requiring a rollback or data corruption. I created a .gitignore file, which excluded all auto-generated directories to avoid bloating the repo, and removed the risk of any merge conflicts. This system was set up before any development began, ensuring all prerequisites were met before starting (Unity, 2026 - Unity Version Control). On top of this, I added built-in macOS and Linux support to allow non-Windows users to play, removing the barrier set by having a particular operating system. I also chose to create a Trello board for time management (Appendix 1).
The first major technical system developed was the Procedural Generation algorithm. In the final version, the project uses a hybrid model of Binary Space Partitioning and Random Walk algorithms, with rooms deriving from the BSP, and corridors from Random Walk. This was an important design decision. I created it this way to produce more structurally coherent environments that are less random and more cohesive.
Before writing any algorithms, a base class, ‘ProceduralGenerationAlgorithms’ (Figure 13), was created to define the common structure shared between each generator in the project. This class exposes a single GenerateDungeon method, which clears the tilemap, runs a selected generation method through ‘RunProceduralGeneration’, and then broadcasts the new floor positions through an ‘OnGenerationComplete’ event. This allowed me to build and test multiple different generation strategies (RoomFirstDungeonGenerator, CorridorFirstDungeonGenerator, and SimpleRandomWalkDungeonGenerator), without duplicating logic such as tilemap clearing or generation callbacks, as they were included in the base class. Ensuring the codebase was clean and free of repeating logic, which could cause unnecessary performance issues.
The primary generator used is ‘RoomFirstDungeonGenerator’. This generator begins by passing dungeon bounds into a BSP function, which uses a queue to process the available space horizontally or vertically until the remaining sections fulfil the minimum width and height set in the inspector (Sian, 2025). I chose this approach because it ensures that each room has a size that is sufficient for each aspect of gameplay, which is important for top-down games where the player needs to be able to scan the environment, and because it provides the flexibility of being able to change room sizes at will through the inspector.
Corridor generation is handled by the Random Walk algorithm. A walk starts at a position, picks a random direction, moves one tile and repeats for a set number of steps. A HashSet is then used to store visited positions in a list, so that a seen space isn’t repeated. The generator runs this algorithm across multiple iterations, merging each into a single final set. The ‘startRandomlyEachIteration’ boolean then produces corridor shapes. When run, each new walk will begin from an already visited tile, causing paths to branch outward rather than overlap. The result produces corridors that differ across runs but remain structurally coherent.
Wall placement is handled by the WallTypesHelper script, which assigns each tile a binary code according to its neighbours, with an empty space being 0 and an occupied tile being 1. Each value is then checked at runtime to determine which wall prefab to place, ensuring the edges of the tilemap are filled correctly, regardless of the dungeon layout.
The BinarySpacePartitioning function processes spaces through a queue; each space is dequeued, and the algorithm decides whether to attempt a horizontal or vertical split. A horizontal split will occur only if the space is at least twice the minimum room height, and a vertical split will occur only if the space is at least twice the minimum room width. If neither split is possible, and the space meets minimum dimensions on all sides, the room is added to the final dungeon layout. Each room uses two generation modes that can be toggled through the inspector, one to fill room-bounds, and another to carve floor shapes and corridors outward from the room centre. These are then connected using the ConnectRooms function, which searches for the closest unconnected room and carves either a straight line or an L-shaped corridor to join them. This process is repeated until all rooms are interconnected and there are no empty spaces. Once this is finished, the ‘OnGenerationComplete’ is called, which passes the final floor positions to each spawner and the dungeon decorator.
The final post-processing pass is handled by ‘DungeonDecorator’, which categorises each floor tile by the number of neighbours it has. Tiles with four neighbours are classed as open room space, tiles with two or three neighbours are classed as edges, and tiles with zero or one neighbour are classed as dead ends. Each category has a set prefab pool (Unity, 2026, Prefabs) and changeable spawn probability in the inspector, ensuring that things like pillars and barrels spawn in corners, and coins spawn in open space.
The PlayerController script is the brain that controls all movement and attacks for the player. It is composed of one main class, with several subclasses assigned to various functions, the main of which is detecting input and controlling player movement accordingly. This also includes a method to flip the character sprite, so it is always facing the direction the player is moving; however, due to the sprite being 2D, it is unable to face away or toward the camera when moving up or down. This script also includes references to the character animator, ensuring certain animations play based on certain booleans or triggers. This included the animations for being idle, moving, attacking, taking damage, or dying.
The attack class for this script is relatively simple; it uses a Collider 2D and Physics2D (Unity, 2026, Scripting API) overlap circle to determine whether an enemy is in attack radius, and if the player presses ‘space’ when the enemy is within the appropriate distance, an attack is performed. I chose to include the visual indicator of the enemy flashing red to make it clear that damage had been received. This class also includes the logic necessary for destructible decorations, using a LayerMask to check which layer each component is on, and the same system used for attacking enemies. This was done to ensure the code was modular and computationally efficient.
When developing the attack system, the overlap circle took up nearly a whole day of testing to look at different attack ranges and damage increments. Should I progress this title further, I would skip this step entirely. This is because after considerable testing, there wasn’t too much of a noticeable difference, mainly because of the size of the sprites.
Decoration placement throughout each generated dungeon is handled by the DungeonDecorator script, which controls both which prefabs to use and their placement.
Firstly, a SerializedField (Unity, 2026, Serialisation rules) is used for each category of decoration and its spawn chance, so that they can be swapped out through the inspector. All spawned decorations are parented under a container so they can be bulk destroyed on regeneration without needing to scan the entire scene. This includes ‘openPrefabs, edgePrefabs, cornerPrefabs, keyPrefabs, hatchPrefabs, and wallPrefabs. These can all be swapped out at will, as well as new decoration categories added; all that is required is a new reference in the generator. Next, the Decorate method is used to clear decorations from the dungeon, and then a HashSet is looped through to determine if there are walls directly surrounding a tile, deciding which prefab type to place based on the result. The CountFloorNeighbours method is used to check the number of floor tiles and then spawn a prefab.
Exodus features two main objectives, and victory is achieved by completing either one. This involves eliminating all the enemies in the environment or collecting all the coins scattered throughout. These mechanics are handled by both the CoinCollector and EnemyTracker scripts.
Coins are scattered throughout the environment by the DungeonDecorator, using the openPrefabs inspector element. These are given BoxCollider2D’s with isTrigger set to enabled. Once the player collides with the coin, the gameObject’s sprite is destroyed. This is linked to a text counter, which indicates the number of coins collected. Once the player picks up a coin, the counter is incremented. While this is a simple objective, it allowed me to implement an easy-win victory condition, so I could focus on other areas of development.
The EnemyTracker first resets at the start of each run to ensure that increments are accurate, and then counts the number of enemy sprites spawned on start. These are then filtered to the on-screen tracker so the player can see how many there are. When all the enemies have been defeated, the timeScale is set to zero, and the victoryMenu is set to active.
The EnemyAI script controls the core behaviour of each enemy in Exodus, including movement and attack logic. It uses a finite state machine (FSM) architecture (Jagdale, 2021) and runs alongside Unity’s 2D Physics engine to enable typical enemy behaviours such as wandering, chasing, and dealing damage to the player.
The FSM defines three states: Idle, Chase, and Attack. These states are shifted based on detectionRange, loseAggroRange, and attackRange. The calculations for these variables are based on the distance between the enemy’s current position and the player, and are carried out inside Update(). While Idle, the enemy checks a timer, and if wandering is enabled in the inspector, it generates a random target point around its original spawnPosition and walks to it at 50% reduced speed. The system was designed this way so that wandering would feel more passive, and enemies wouldn’t move too fast unnecessarily.
Chasing is initiated once the player enters the enemy's detection range, and is carried out by calculating a 2D directional vector in MoveToward, which points directly at the player. This also applies to the sprite's Rigidbody2D, to push the enemy in a certain direction, as well as flipping the spriteRendered left or right so it is always facing the direction it is moving. Once the enemy reaches the player and passes its attackRange threshold, it switches to attack mode, stopping Idle and Chase so there is no animation overlap. While standing still, the enemy will attack the player if its attackTimer cooldown is ready; if so, the DealDamage sequence runs.
Looking back on this portion of development, had I had the idea, I’d have implemented context steering for the EnemyAI so they could walk around obstacles and walls more efficiently, without getting stuck. This is currently a significant drawback in the current build, as enemies tend to get stuck on objects that they can’t collide with, as the player can.
This script uses several practices to ensure code efficiency and sustainability. Components are cached in Awake() when not being used, avoiding expensive GetComponent calls during gameplay. It also uses a state machine with switch statements to restrict logic to what is currently being done. Further improvements could be made by using an event system rather than the currently large number of null checks; this would help reduce the risk of performance dips.
The main menu for Exodus was created using Unity’s canvas system, allowing the interface to be arranged clearly (Figure 7 & 8 - Main Menu). I chose a traditional three-button layout as it was simple, easily recognisable to players, and supported quick navigation. To strengthen the atmosphere of the menu, the background was given a slight move effect when hovered over by the mouse, providing subtle visual feedback, and I chose to use a particle system to generate small ‘embers’ emanating from the bottom of the screen and rising to the top like sparks from a fire. This added a subtle level of detail that brought the menu to life. This effect helped to reinforce the dungeon theme right from the start, aiming to give a good impression to new users.
The settings menu is comprised of four key components typical of most modern video games, including a ‘resolution dropdown, volume slider, quality dropdown, and a fullscreen toggle’. These are all implemented through the SettingsMenu script, with each component having its own class to keep the system easy to maintain. This structure is common to most game-setting menus and is designed to provide users with clear, user-friendly controls.
Hardware inequality is a considerable barrier in modern gaming; most titles release with minimum specifications that can unintentionally exclude players with older PCs or consoles. The settings menu in Exodus addresses this by including a quality dropdown, resolution dropdown, volume slider and fullscreen toggle. (Figure 9) This game can be configured to run on a wide range of hardware, rather than having fixed specifications. This helps address SDG 10’s call for reduced inequality and increased opportunity around the world. By including these settings, the game offers a basic, but important level of customisation that makes it more accessible for a wide range of users.
Procedural generation also contributes to this idea. The BSP, Random Walk hybrid approach removes the bottleneck that makes hand-created content development impractical for smaller, under-funded teams, meaning that solo or indie developers could use this approach to create a replayable game without the infrastructure that large titles like Hades require (Shaker, Togelius and Nelson, 2016). This helps to reduce the barrier to development for independent developers, which can act as a form of reduced inequality.
With additional development time, I’d expand on this further by including remappable controls to help those with motor impairment, as well as a colourblind mode to address the large portion of players affected with this affliction.
The main research question for this project was whether a hybrid BSP and Random Walk algorithm could produce dungeon environments with sufficient variety and coherence to sustain player engagement across multiple playthroughs, without relying on hand-crafted asset pools used by large studios. Based on the development, implementation and comparative research conducted, there is visible room for improvement.
Structurally, the hybrid system performed well, generating coherent dungeon layouts that never overlapped or were repeated. Each room was interconnected via ConnectRooms, and the minimum room dimensions set out ensured that each room had enough playable space. This was an efficient approach, as it removed the need to manually validate each layout. The RandomWalk algorithm added more variation that would’ve been missing had I used a pure BSP approach, mainly because the startRandomlyEachIteration function ensured that corridor geometry was noticeably different in each run. For a solo developer, this approach is both computationally and time-efficient, as it ensures that there is no need for hand-crafted room pools, which would have taken a large chunk of development time.
Where this system failed was the variety over time, this being especially clear after researching three titles. The Binding of Isaac supplements its generation algorithm with large pools of hand-crafted rooms, adding more variety on top of the algorithmic generation, even if the floor plan is somewhat similar. Even for a long-time Isaac player, they still experience some level of variety because the room interior is usually different. For Exodus, however, there is no equivalent; each generated layout is empty and then populated with decorations and interactable objects, meaning that once a player understands how each generation works, subsequent playthroughs will have an element of predictability despite the layout being different each time.
In comparison, Enter the Gungeon uses a flow graph system that introduces structural variety that BSP cannot replicate; it uses loops, forced routes through a shop, and multi-way forks in the environment to create unique layouts and routes for players to take. Whereas in Exodus, each room shares the same rectangular shape, joined by a corridor, creating a sense of regularity that doesn’t exist in Gungeon. Hades also has a high encounter quality compared to others, but this comes at a high development cost and would have been impractical for this project.
After playtesting, it’s clear that while the game does have a measure of replayability, it would require additional progression systems to last longer than a few sessions. This could be achieved by adding ‘meta-progression’, which is typical of games in this genre and entails additional characters, difficulty modifiers, cosmetics, and extra achievements. Hades, and its sequel Hades 2, are notable examples of this mechanic done well, as there is plenty more to do once the main game is completed. Additional runs can be completed to finish remaining side-stories, unlock new weapons, and get secret achievements. Without these extra systems, the game feels somewhat lacklustre and barebones when playing for extended sessions.
Finally, when comparing the practicality of this approach for both indie and AAA developers, it's clear that there are different aspects that algorithmic generation can and cannot provide. BSP with Random Walk corridors acts as an efficient foundation, removing the bottleneck that makes Hades or Gungeon scale development impractical for smaller studios, and produces consistent environments without hand-creating any assets. However, Shaker, Togelius and Nelson (2016) conclude that procedural generation systems work best when combined with human-authored content, supporting this conclusion. Learning from this, Exodus could be improved significantly with a smaller pool of hand-crafted room prefabs, providing much more variety without spending considerable time on asset creation alone.
Informal playtesting was conducted by end-users on itch.io, as well as through connections from LinkedIn. Users were asked to complete at least one full session and provide any feedback regarding visuals, difficulty, replayability, and overall enjoyment.
I was able to gather data and feedback from seven separate playtest sessions, while most of it was positive, several improvements were highlighted that have now been implemented. To start, there was a lack of background ambience or any sound; this has been rectified by adding an ambient background soundtrack, as well as an attack sound for the player. I felt this was appropriate for the scale of the project, and I aim to add more should the game get bigger.
One consistent trend with feedback identified a lack of ambient lighting or post-processing effects; in the uploaded build, these were all absent. I have since improved upon this by adding bloom, colour adjustments, and shadows to the entire game. These were all simple, quick changes that immediately improved the visual clarity and feel of the game by giving certain environmental assets, such as torches, more vibrance.
The consistent trend of feedback highlighting a lack of audio and lighting suggests that players have base expectations of this genre prefer brighter, more appealing visuals, as well as consistent atmospheric sound. All of these are consistent throughout the titles researched in the methodology, suggesting that these are important factors and should be prioritised alongside the main mechanics. Several players also noted that after two or three runs, the dungeon environments began to feel similar and somewhat predictable. While this was acknowledged, fixing this would have required a full redesign of the generation algorithm and was out of scope.
Given the small sample size, I feel that true validation and feedback are still missing. This would require a minimum of thirty individual responses, ranging from various demographics, backgrounds, and systems, to get a wide range of results.
Overall, the short, yet informal playtesting segment confirmed that there was a functional core gameplay loop and was engaging to begin with; there was significant room for improvement, which has been taken into account during further development.
This project aimed to answer whether a hybrid BSP and Random Walk could produce dungeon layouts that provide enough variety and coherence to sustain player engagement over numerous playthroughs, without relying on hand-crafted content pools used by larger studios.
The implementation of this demonstrated that this hybrid method is efficient and produces a solid foundation for further development. The produced dungeons were consistently both structurally coherent and had enough variety to sustain player engagement for the short-term. This is a successful development pipeline for a solo developer, as it acts as an appealing alternative to the considerable time investment of hand-crafted assets or room pools used in Hades, Isaac, and Gungeon.
However, both the comparative analysis and informal playtesting highlighted that algorithmic generation isn’t sufficient alone to create an engaging experience. Without hand-crafted room pools, meta-progression, or a flow-graph system, replayability and variety begin to noticeably degrade after a few runs. Each of the researched titles has a different feature used that differentiates them from each other, and highlights the improvement that could be made to Exodus.
Based on these findings, a more practical route for indie developers would be a hybrid model of using algorithmic generation for layout, with a small to medium-sized pool of hand-crafted content to add variety to the already generated environments. This could be paired with a small progression system or detailed objective system to create more engaging experiences, even for smaller studios. This method could act as a stepping stone for an indie developer or small studio to start working on their own dungeon crawler or similar title, with room to adapt and further add to this method.
If Exodus were taken further, future development would consist of implementing context steering for enemy AI, implementing a small progression system, and creating a small pool of pre-created rooms that could be added to the generation algorithm. This would help address the lack of variety and predictability.
To complete development on schedule, time management was important to ensure the creation of a complete game. I created a Trello board to visualise and manage the project workflow, ensuring time for research, development, bug fixing, and the dissertation write-up. Weeks 1-3 involved research on successful isometric titles to identify key trends. Weeks 4-7 involved creating the environment, character, and camera controllers. Weeks 8-11 involved the main portion of development, including the quest system and main menu development, as well as fixing any bugs from previous weeks. The final section in Week 12 included final dissertation additions, as well as the last bug fixes and polishing before submission.
To mitigate potential disruption, several contingencies were used to ensure a smooth development timeline. In the event of data loss, both Unity Version Control and GitHub were used to host all files. If time constraints became an issue, focus would shift to ensuring that a playable version was ready for the end-of-year show.
The Trello Board can be accessed here.
McMillen, E. (2011). The Binding of Isaac [Video game]. Nifalis Inc.
Dodge Roll. (2016). Enter the Gungeon [Video game]. Devolver Digital.
Jagdale, D. (2021). Finite State Machine in Game Development. International Journal of Advanced Research in Science, Communication and Technology, [online] 10(1), pp.384–390. doi:https://doi.org/10.48175/ijarsct-2062.
Michaels, J. (2020). Binary Spatial Partitioning for Dungeon Generation. [online] Medium. Available at: https://medium.com/datavt/binary-spatial-partitioning-for-dungeon-generation-a0716c642488
Shaker, N., Togelius, J. and Nelson, M.J. (2016). Procedural Content Generation in Games. Computational Synthesis and Creative Systems. Cham: Springer International Publishing. doi:https://doi.org/10.1007/978-3-319-42716-4.
Sian, T.B. (2025). From Algorithm to Playable Space: A Technical Note on BSP-Based Dungeon Design. International Journal of Creative Multimedia, [online] 6(2), pp.287–308. doi:https://doi.org/10.33093/ijcm.2025.6.2.16.
Supergiant Games. (2020). Hades. [Video game]. Supergiant Games.
Supergiant Games. (2025) Hades II. [Video game]. Supergiant Games.
United Nations (2025). Goal 10 | Reduce Inequality within and among Countries. [online] United Nations. Available at: https://sdgs.un.org/goals/goal10.
Unity Technologies (n.d.) Unity version control. Available at: https://docs.unity.com/en-us/unity-version-control/tutorials-landing (Accessed: April 2026).
Unity Technologies (n.d.) Scripting API: Physics2D. Available at: https://docs.unity3d.com/ScriptReference/Physics2D.html (Accessed: April 2026).
Unity Technologies (n.d.) Manual: Prefabs. Available at: https://docs.unity3d.com/Manual/Prefabs.html (Accessed: April 2026).
Unity Technologies (2024) Manual: Serialisation rules. Available at: https://docs.unity3d.com/Manual/script-serialization-rules.html (Accessed: April 2026)
Gamestudies.org. (2024). Game Studies - Genre, Prototype Theory and the Berlin Interpretation of Roguelikes. [online] Available at: https://gamestudies.org/2403/articles/cartlidge.
Khan, S. (2022). Implementing Wave Function Collapse & Binary Space Partitioning for Procedural Dungeon Generation. [online] Medium. Available at: https://medium.com/@ShaanCoding/implementing-wave-function-collapse-binary-space-partitioning-for-procedural-dungeon-generation-2f1a6cc376db
Sprinks, H.T. (2025). Best Indie Games With Hand-Crafted Environments. [online] GameRant. Available at: https://gamerant.com/best-indie-games-handcrafted-environments/