Unity

Random Dungeon Generation Using BSP Trees

In this project, I developed a simple method to generate a basic dungeon using a Binary Space Partition (BSP) tree. The goal was to create an algorithm that recursively divides a rectangular dungeon into smaller sub-dungeons until each one reaches the desired size of a room.

The source code for this Unity Project is on my GitHub

All the steps summarised

Presented here is a breakdown of the algorithm, outlined in two primary components:

1. Building the BSP Tree

The process begins with a rectangular dungeon:

Empty dungeon (called Container in code)

We employ a recursive splitting technique to divide this dungeon until each sub-dungeon reaches the desired room size. Below is the code responsible for the recursive splitting of a BSP tree.

/// <summary>
///     Recursively splits a tree into two parts and assigns the LeftNode and RightNode to the
///     respective split containers.
/// </summary>
/// <param name="iterations">How many iterations to split</param>
/// <param name="root_node">The container to do the split operations on</param>
/// <param name="parent">Parent node (null for root)</param>
internal static BinaryTree SplitRecursively(
	int iterations,
	RectInt root_node,
	BinaryTree parent = null)
{
	var node = new BinaryTree(root_node)
	{
		Parent = parent
	};

	if (iterations == 0)
	{
		return node;
	}

	node.Split();
	node.LeftNode = SplitRecursively(iterations - 1, node.LeftNode.RootNode, node);
	node.RightNode = SplitRecursively(iterations - 1, node.RightNode.RootNode, node);

	return node;
}

The dungeon splitting operation involves the following steps:

  1. Randomly select a splitting direction: horizontal or vertical. (or consider the container’s dimensions and select the direction that aligns with its largest dimension)
  2. Choose a random position along the chosen direction (x-coordinate for vertical splitting, y-coordinate for horizontal splitting).
  3. Divide the dungeon into two sub-dungeons.

At this stage, we obtain two sub-dungeons, namely A and B:

Dungeon after a single split iteration.

The same splitting operation is then applied to each of these sub-dungeons:

Dungeon after two split iterations.

When selecting the splitting position, it is crucial to ensure it is not too close to the dungeon’s borders. This precaution guarantees sufficient space for placing a room inside each generated sub-dungeon. In my code, the variables controlling the splitting variation are named splitMinRatio and splitMaxRatio. Depending on the rules applied to the splitting position, the resulting sub-dungeons can exhibit either homogeneity (position between 0.45 and 0.55) or heterogeneity (position between 0.1 and 0.9).

Setting both the “Split Min Ratio” and “Split Max Ratio” to 0.5 in the DungeonGenerator script always yields perfectly uniform containers.

We repeat these three steps until the smallest sub-dungeons reach the desired room size:

A dungeon after 3 split iterations yields 8 Containers.

2. Building the Dungeon

Next, we proceed to construct the actual dungeon by following these steps:

  1. For each leaf in the BSP tree (called a container in the code), we create a room with a randomly determined size (roomMinRatio and roomMaxRatio in the code). It is important to ensure that each room remains within the bounds of its corresponding sub-dungeon. Thanks to the BSP tree structure, we eliminate the possibility of having overlapping rooms.
Spawning rooms in each container (in red).
  1. To establish tunnels between the rooms, we iterate through all the leaf nodes in the tree and connect each leaf to another node or to another tunnel. We repeat this process iteratively until all the rooms are connected, ensuring a coherent and navigable layout for the dungeon. (Tunnel width can be controlled using the tunnelWidth variable. )
Connecting each room with tunnels (in yellow).
Instantiating room tiles and tunnel tiles as gameobjects.

And finally we have our dungeon once we remove the gizmo lines

A randomly generated dungon.

The DungeonGenerator script additionally includes a variable called padding value, which controls the spacing around tunnels. By setting it to 2, the algorithm guarantees that tunnels are placed at least 2 tiles away from the outer walls of each room.

This functionality is beneficial in two ways: Firstly, it prevents tunnels from starting directly at the corners of a room, creating a more aesthetically pleasing layout. Secondly, it ensures that tunnels have a few tiles of walls on each side, providing better visual separation between rooms and corridors.

The resulting dungeons offer a solid foundation for further embellishments, such as adding room decorations, enemy placements, and puzzle elements, to create captivating gameplay experiences

Games I’ve Made

Sonic Ninja

One of the challenging and fun puzzle projects I developed is a game where you navigate by drawing a path. I was the only developer who worked on this game.

An image gallery from the store page.

Early gameplay footage.

Draw A Hole

Again as a solo developer, I created another drawing project where players can draw “black holes” to devour a city and earn points. The objective is to spend these points to enhance the size, capacity, and other attributes of the black hole.

An image gallery from the store page.

Early gameplay footage.

Steam Projects

In addition to my full-time work, I have collaborated with several small teams since 2017 to develop games for the Steam platform. Here are a few of these projects below:

Hotel Anatolia

An adventure/horror game. Release date 2017.

More visuals and more information can be found on the Steam page.

Survival Journals

Survival Journals is a text based survival adventure that combines the classic “Choose Your Own Adventure” style gameplay with RPG and strategy elements.

More visuals and more information can be found on the Steam page.

Untitled Sci-Fi Survival Game

A space shooter/survival game that was put on hold.

Early gameplay footage and feature showcase can be viewed on my youtube:

An Arcade Idle Prototype (Hyper-Casual Genre)

This arcade idle prototype I’ve built includes the following features:

  • Mesh manipulation: The game allows for nodes to deplete, resulting in dynamic changes to the mesh.
  • Modular and expandable code: The game’s code is designed in a modular and flexible manner, making it easy to add new features and expand the game’s functionality.
  • VFX: Various vissual effects to enhance the overall gaming experience and to give feedback upon certain actions (looting, depleted nodes, cooldown indicators etc.).

Click & Drag To Control The Player

(Fullscreen button is on the bottom right corner)


I have developed a modular “Factory” system that efficiently processes input items such as Iron and Copper and produces a desired output, in this case a Sword.

This Factory system is designed to be easily interconnected, allowing multiple factories to be linked together in a chain-like fashion. This chaining enables the production of valuable items that require multiple processing steps to complete.

( For example: Iron ore -> Iron Ingot -> Iron Bar )

Here is an example of a Farmable Node script that has been configured to function as an “Iron Node”.

With this script, you can conveniently add different resources and items in just a matter of seconds. The flexibility of the script allows for quick customization and adaptation to specific needs.

Here is an example of an additional node that utilizes Prefab Variants, greatly simplifying the process of adding new farmable resources to be utilized in factories.

This feature makes it incredibly effortless to introduce new types of farmable resources into the system.


An idle game is a type of game in the Hyper-casual genre where players can progress with minimal or no interaction. Resources increase automatically, and players can interact to speed up their acquisition. The Idle genre gained popularity last year. These games combine elements of idle gameplay and metrics, resulting in hybrid games.

Arcade Idle is a subgenre that merges idle and adventure arcade features to create games with a Hyper-casual feel and appealing metrics. These games simplify the resource mining aspect while retaining engaging gameplay, leading to hybrid games with medium/low CPI but strong playtime metrics of over 30 minutes.

In Arcade Idle, players gather resources, sell them to accumulate wealth, expand their territory, and enjoy the game. Unlike traditional idle games, Arcade Idle includes a playable character that influences other game elements. It also offers an adventure-like experience, making it more enticing.


Arcade Idle success factors

In the Hyper-casual world, simplicity is crucial. Arcade Idle games should simplify the complexities of the Idle genre to appeal to a wide audience. From the economy to the controls and game design, simplicity should be prioritized.

To create an engaging Arcade Idle game, consider the following key ideas:

  1. Simple gameplay mechanics: Hyper-casualize the Idle genre and make it instantly enjoyable. Players should grasp the gameplay within seconds, avoiding the complexity often found in Idle games.
  2. Sense of depth: Within a few minutes of playing, players should recognize that the game offers hours of enjoyment. It should go beyond the typical Hyper-casual experience.
  3. Engaging progression: Provide a clear and satisfying sense of progression. Players should feel a constant sense of growth and accomplishment as they advance through the game. Introduce new features, upgrades, and challenges at regular intervals to keep the gameplay engaging.
  4. Strategic decision-making: Incorporate strategic elements that allow players to make meaningful decisions. Provide different paths or choices that impact their gameplay experience and outcomes. This adds depth and replayability to the game, enhancing long-term engagement.
  5. Attractive visuals and audio: Create visually appealing graphics and captivating audio to enhance the overall experience. Engaging visuals and immersive sound effects can greatly contribute to the game’s appeal and make it more enjoyable for players.
  6. Social and competitive elements: Include social and competitive features to foster a sense of community and encourage player interaction. Leaderboards, achievements, and social sharing options can motivate players to compete with friends or other players, driving engagement and retention.
  7. Regular updates and events: Keep the game fresh and exciting by regularly introducing new content, updates, and limited-time events. This encourages players to return frequently and maintain their interest in the game over an extended period.

By incorporating these key ideas, an Arcade Idle game can stand out in the Hyper-casual market and attract a dedicated player base.


Stencil Buffer Magic

Here’s how I used Stencil Buffers and URP’s Forward Renderer features in Unity to create a spawn animation for my space shooter game. An early version of this game is playable on my itch.io.

I use stencil buffers to spawn enemy packs out of thin air and here is how it looks in-game:

In order to achieve this effect, I created this shader;

Shader "Stencil"
{
	Properties
	{
		[IntRange] _StencilID("Stencil ID", Range(0, 255)) = 0
	}
		SubShader
	{
		Tags
		{
			"RenderType" = "Opaque"
			"Queue" = "Geometry"
			"RenderPipeline" = "UniversalPipeline"
		}

		Pass
		{
			Blend Zero One
			ZWrite Off

			Stencil
			{
				Ref[_StencilID]
				Comp Always
				Pass Replace
				Fail Keep
			}
		}
	}
}

I placed all the objects of type Enemy on a newly created Stencil1 layer.


I created two forward renderer features, one for opaque objects and one for transparent. Note that I used the Stencil1 layer as the layer mask.


I created a new material using the Stencil shader I wrote, paying attention to use the same Stencil ID I used when adding the renderer feature in the previous step.


I then assigned this material to a sphere and animated its scale, along with some other properties, to create the illusion of enemies appearing out of nowhere. Here is how it looks in the editor.

And here’s how it looks in game:

Custom Physics and VFX To Add Feeling To A Game


For this challenge, I received a 2D platformer scene and was given a few hours to complete these three tasks:

  1. Make the player character feel “heavy” in its movements.
  2. Enhance the spikes to convey danger to the player.
  3. Transform the pressure pad into a fun and positive experience for the player to interact with.

BEFORE

WASD To Control The Player

(Fullscreen button is on the bottom right corner)

AFTER

WASD To Control The Player

(Fullscreen button is on the bottom right corner)

Approach

To create the desired “heavy” feel for the player character, I implemented custom physics in the player mover script that increased the gravity and friction values, as realistic physics did not convey the intended effect. I also incorporated visual indicators to convey the impression of the player character struggling to move due to increased weight. In addition, I utilized various sprites that simulate damage to the environment when the player impacts it, thereby emphasizing the character’s heaviness. The use of particles helped to further communicate the impression of the player’s falls and movement affecting the environment.

I had the challenge of adjusting the gravity and friction so that the player felt heavy, but I also had to make sure the player could still jump between the same platforms.

For the spikes obstacle, I utilized visual cues such as a red color scheme and added effects to instantly communicate the danger to the player upon touching it.

To transform the pressure pad into a fun and positive experience, I turned it into a jump pad that launches the player into the air. I also incorporated particles and animations to provide visual feedback to the player, making it a satisfying and enjoyable experience.


Skills

During this project, I utilized my skills in game development, physics implementation, and visual design to improve the gameplay experience of the 2D platformer scene. Specifically, I demonstrated proficiency in coding custom physics in the player mover script, incorporating visual indicators to communicate the character’s weight, and utilizing particles and animations to enhance the player’s interactions with the game elements.


Results

The final product resulted in a significant improvement to the gameplay experience of the 2D platformer scene. The use of visual cues on the spikes effectively communicated the danger to the player. Additionally, the transformation of the pressure pad into a jump pad provided a fun and satisfying interaction for the player.


Reflection

Through this project, I learned the importance of balancing realism and fun in game development. While realistic physics may accurately simulate certain aspects of movement and interaction, it may not always create the desired player experience. Therefore, I had to use my creativity and problem-solving skills to implement custom physics and visual indicators that conveyed the intended effect. This project also taught me the value of user experience testing and feedback, as it allowed me to make adjustments and improvements based on player reactions and suggestions.

Scroll to Top