top of page

Bloodelic

A grid-based reverse-horror Hitman-like where you sneak around as a small monster attempting to feast on the town's inhabitants.

Engine

Unity, C#

Roles

Project Lead

Timeframe

Jun 2023 - May 2024

Contributions

I led a team of 12 people to complete Bloodelic. I'm extremely proud of the work that was accomplished and what we achieved, and it was an experience I have learned so much from. This project has made me a better lead, and a better programmer.

Grid creation tool

The project was conceptualized with 3D grid-based movement in mind, and manually placing and connecting grid cells was obviously out of the question. Unity's NavMesh tool couldn't be used, as well as any premade grid system as they only supported movement on the ground.

 

Therefore, a tool was necessary to dynamically generate the grid squares for the level. This proved a challenge, but a satisfying one. After many hours of ideation, research, and testing, I created a system that would raycast the scene in all directions (down, left, right, front, back) at the intervals the size of the grid cell, and create a new grid cell at the location(s) of collision. The size of the level would be determined by opposite corners of the level as defined by a designer.

The connection step was the hardest, but in the end, served doubly as the culling step. Each cell would find its neighbors using an OverlapSphere, and then proceed to check whether the connections were possible through logic and a large look-up table of valid connection types. The difficulty came with determining how cells could connect to each other in a 3D space.

​

For example, on the top edge of a cell on the floor, it can connect to another floor cell, or a wall cell. The wall cell must be facing forward if it is above the cell, or must be facing backwards if it is below the cell.

​

Due to these rules, the tool could also determine whether a cell was invalid and should be deleted. With this all happening before runtime, the game did not need to worry about grid generation slowing performance. While optimization can still be implemented with this tool, it served its purpose excellently for the rapid iteration of levels.

Development screenshot of level grid

Early development of tool with colored cells representing the direction it faced

Screenshot 2023-12-18 184313.png

Early generation testing not going well

Dynamic Selection System

With Bloodelic designed as a strategy game where the player could select different options from the player, NPC, and items in the level, I wanted the UX to be intuitive and practical. Therefore, I made the decision to have actors be selectable, where a UI prompt in the world would appear to choose different options. This dynamic selection system that could easily alternate between screen-space UI, world-space UI, and custom selectable entities ended up being one of the largest challenges of the project.

Final iteration of the selection system

While Unity has a built-in UI system, along with controls for it, this system could only partially interact with it. What made the system so difficult was the custom selecting game-objects and controlling what the player could select and interact with during specific game-states.

​

The first iteration focused on selecting game-objects, and while it worked, it was because it was hard-coded to select the player and then the grid after the player had been selected.

As this had been easy to implement, I was admittedly over-confident going into the rest of the project. However, this was short-lived as I tried to implement the beginnings of selectable NPCs and immediately saw the short-comings and difficulties that lay ahead.

​

A custom script "Selectable" was created to define what GameObjects could be selected and would interact with the CameraController and related selection scripts. This implementation required a lot of decoupling, and relied on events to propagate relevant information without needing to know what was propagating it. This made the selection much more generic and far easier to place on subsequent GameObjects.

​

State machines also needed to be implemented to control selection states. Whether an object is selected would determine whether its associated world UI could be interacted with or deselected.

The final massive overhaul came with the implementation of generic behaviors that player could perform. Movement, picking up an object, and killing an NPC all require use of the selection system after choosing the option in the World UI. Therefore, the selection system needed a generic way to interact with each behavior and furthermore, each step of selection for a specific behavior.

​

Therefore, another state was added to the overall selection state machine, and an abstract behavior state machine was created to be implemented in the different behaviors. The concept itself is easy to say, but coding it was anything but. Ensuring that the rework of the system didn't break preexisting gameplay elements taught me greatly about the value of writing generically, as well as following the single responsibility principle, from the beginning to avoid future tech debt and confusion.

More WRITE-uPs to Come!

  • LinkedIn
  • GitHub
  • monochrome_largedfg
  • Youtube

©2023 by Jade Spooner. Proudly created with Wix.com

bottom of page