The Concept

It all started when I wanted to do something with procedural generation. I remembered an algorithm that I used a long time ago to procedurally generate houses in Minecraft. I thought it would be nice to use that algorithm to create houses for a stealth game. I wanted to combine the stealth and stealing mechanics of the Thief series, with the inventory management of the Fallout series. I’ve created several of my own game engines in the past, but I didn’t want to handle all the physics myself this time - so I decided to use the Godot engine.

The first idea was to make it isometric 2D. To learn the engine, I created a sample level from a tutorial. It was 3D isometric. I added camera rotation and the ability to see the player through the wall when our view is blocked. I loaded some sample 3D character meshes and added walking animations and collision. I started thinking about all the assets and textures that I would have to make for this and realized that I hadn’t even started on the procedural house generation that’s supposed to be the heart of this game. I decided that I didn’t want graphics to be the main selling point of this game, and I started over with a 2D top down view. Now that I had a nice grid to work with, I was confident to continue on to the planning phase.

I started a spreadsheet to plan rooms, objects, and items. This includes which objects were in which rooms (like a sink in the kitchen), and which items could be found in which objects (like a sponge in the sink). I also planned item weights, value ranges, and chances. Items would have both weight and volume, so you have to manage your inventory and decide what things to carry.

For a proof of concept, I downloaded an asset pack and learned:

  • TileMaps and TileSets

  • placing tiles

  • rendering the scene

  • getting user input

  • collision detection

Now it was time to draw.

I drew some simple assets for walls and doors. Then I realized - to appear less blocky, I would need to have directional tiles that blend into each other. Like a vertical wall, a horizontal wall, L shaped walls, T shaped walls, and + shaped walls.

Finally, it was time to apply the first procedural generation algorithm: BSP (Binary Space Partitioning). There will be more types of procedural generation used in this game soon, but I didn’t know that yet.

There are some really cool things about BSP. Splitting into tree nodes means that all leaf nodes are final rooms, and any connection to a parent node means the rooms share a wall. You can put a door there to connect them. In fact, this means that you are guaranteed to always have a path from any room to any other room.

The Results of Binary Space Partitioning

The walls connect in I, L, T, or + shapes. All rooms are connected to each other. Also added doors and a variety of themes like wood and brick.

Swapped the “P” placeholder with a player sprite

I wanted to be able to enter multiple houses, so I needed a city. I realized that I could use the same binary space partition algorithm that I used for houses to create cities. There are different ways to use BSP. For houses, I decided not to trim down the spaces. That works for a dungeon style with a hallway between rooms, but this isn’t that kind of game. For cities, however, we don’t want the houses right next to each other. We want yards and roads and dirt paths and such. So a partitioned space has a smaller space somewhere in it where the house will be placed. This leads to the next type of procedural generation: Rectangle Overlapping.

The first houses generated this way were kind of silly, but after some tweaking of the parameters, I started to get some nicer looking city houses.

Added sidewalks

…and dirt paths

Also added:

  • scene transitions (fade out and in)

  • ability to open doors in houses

  • room labels

  • special floors for gardens and garages

…and scattered patches of dirt

Now it was time to place some objects in the houses.

First I wanted to find the corners of each room

Then make sure the boundaries fill the rooms properly

And get the edges that outline the room

Then randomize and make sure the object orientations are correct

And finally, randomize the objects based on the room

Double sized items (like shelves and couches) were clipping through the wall and far items (like paintings) need to be moved back.

Those issues were soon fixed.

Here’s what it looks like with max object density

The next step was adding items to the objects. We can’t see them yet, though.

I think we’re done with houses for now. Let’s add some menus and screens!

I wanted menu to feel eerie, like you’re being watch by a thief. I made a proof on concept where the eyes randomly look at you. I like it!

The proof of concept worked, so I jumped in to VR to paint a guy in a ski mask reaching for something. The thing he’s reaching for will change each time the menu is loaded. I like the idea of a dynamic menu.

The very beginning of a backpack

Back at the house scene, I added foggy rooms and camera zooming.

Settings screen

Splash screen

Planning story and missions

gamepad controls

keyboard/gamepad controls for UI

UI navigation and confirmations

Inventory transfer

Then a barrage of updates…

Player

Animation

Updated Backpack GUI

Added saving and loading

Added suspicion meter and stats HUD

Improved saving/loading (custom JSON objects)

Some tricky menu improvements and edge cases

Added more characters

add tutorial and guild
location traversal
action bar (for lockpicking, etc.)
special stashes (vehicle, desk, safe)
tasks & task list
Signs and text boxes, with animation
partial tutorial
bugfix: load save wasn't clearing previous vars
bugfix: moving backpack rows was acting weird
bugfix: spacebar on item_row was emitting "pressed" twice
lockpicking animations
migrated from Godot 4.1.1 to 4.1.2

NPCs are generated from a random head, a random mid section, and a random bottom.

Some mid sections (like tank tops) will show skin, so some logic was added to make sure open skin middles are limited to the right head color.

I considered using a shader to color the skin. Then any top works with any mid. But some color combinations might not look good. I wanted a more curated feel.

Time for some NPCs!

Testing NPC Generation with 400 NPCs

48 heads * 24 middles * 24 bottoms * 3 skin tones = 82,944 possible NPC combinations.
After some curating and filtering, the total became 59,648 possible NPC combinations.

Added random NPC generation

NPC roaming with boundaries

NPC walking animations

Wait… Where are they going?

Lesson: This is what happens when you mix local position and global position.

update the suspicion label

added notoriety mechanics

added mask mechanics

added safe cracking

bugfix: searching through walls

design cop assets

add cops to cities

add NPCs to houses

make fog on top of NPCs in the house

make being in the house a suspicious activity

added objects to tutorial

backpack bug fix

place X on a city houses to indicate no re-entry

Cops chase the player at high suspicion (no pathfinding yet, just a straight line to the player)

dynamically color the suspicion & notoriety bars

popup notice on entered houses & busted locks

revamp suspicion/notoriety/mask mechanics

update the tutorial signposts

slide in and out of the city on the vehicle.
This started as a “What if?" idea, but it turned out to be so fun that I kept it.

Added: Getting busted!

Added camera smoothing.
Wow, the camera is so much better now!

fixed: trying to move while lock picking

NPC vision is done by ray-tracing. Every NPC has a line (ray) cast from the NPC to the player. If the line collides with the player and the length of the line is within the NPC max vision distance, then the NPC can see the player.

Let’s talk about NPC Vision!

Performing an illegal action while you are seen by the NPC makes your suspicion raise (or notoriety if you’re not wearing a mask). This is multiplied by the number of NPCs that are watching you. Cops work the same way (but you become wanted if they see you do something illegal).

An NPC is trying to track the player

All NPCs are trying to see the player

Cops work the same way as NPCs

Whatcha gonna do when they come for you?

added Special NPCs

character dialogue

add museum

update settings

implemented buy & sell

fixed some bugs

Museum Donations and Rewards

Auto-scroll for gamepads.
Godot 4 cannot repeat gamepad directional button presses, so I had to write my own logic to simulate this functionality in the backpack and other menus.

change backpack drop behavior

add task list (with auto-scroll)

At first the museum used the regular shelves asset, but I decided to make some lighter shelves specifically for the museum.

Sometimes something that seems simple is harder than you think. Scrolling with the gamepad is a great example. When you hold an arrow key on the keyboard, the event is repeated and you can scroll through menu options. When you press a directional on a gamepad or controller, the event is not repeated (mostly due to OS limitations). But we want to be able to scroll through menu items without pressing multiple times. So how did I fix this?

When a direction is pressed on a gamepad, I catch the button down event and start a timer. Whenever the timer reaches zero, the event is replicated in code and the timer starts over. This repeats until a button up event is caught, and we stop the timer. The scrolling speed can be modified by changing the timeout of the timer (a 0.1 second timer will scroll faster than a 0.5 second timer).

It’s little things like this that many gamers don’t even think about. But it doesn’t come for free, it takes work.

I’ve been drawing a few items a night. With over 1,000 assets to draw for this game, progress can feel slow at times. It’s nice to step back every now and then to see all that’s been accomplished.

vehicle yard

vehicle carry warning

update player stats and saving

updated assets and decorations

improve gamepad menu scrolling

expanded the yard and vehicles

implement experience gain and level up

get a popup message on level up

delay level up message while in conversation

implement training menu

fix window auto-closing on movement

enable new game defaults in config file

Let’s talk about Maze Generation

There are many ways to generate a maze (see Wikipedia: Maze Generation Algorithms) for some examples. Each way has their pros and cons. I chose a recursive backtracking algorithm because it fills all grid positions, guarantees a solution from any point, has no loops, and no islands.

The algorithm is not hard. You run a DFS (depth-first search) from any point in the grid, choosing a random open direction at each step. If you get to a point where you have no open positions, you backtrack up the stack until you have an open position and continue. You do this until you’ve backtracked all the way to the beginning. Now you can set your start and end point anywhere you like (this algorithm guarantees a solution from any spot). You now have a maze!

Now we have multiple type of procedural generation: BSP for the houses, modified BSP for the cities, rectangle overlapping for the city buildings, part matching for the NPCs, and backtracking DFS for maze generation. Nice!

A bunch of updates:

  • add main street to city (split at initial bisection)

  • extend vehicle collision & interaction range

  • updated vehicle assets

  • fix trespassing while exiting special houses

  • update vehicle collision on the yard

  • implemented vehicles purchasing

  • extract dialogue to separate file

  • fix skill training buttons

  • Gain abilities when requirements are met

  • Apply skill and ability effects

  • improve initial continue logic

  • using strength abilities

  • maze access board

  • start position camera fix

  • add maze reward area

  • task board asset changes on use

  • maze tasks

add city edges (beach and forest)

refactor border code

Location based triggers

Leaving city by main road

Add random foliage to city

statistics board

implement task board

split tasks by type

fix two new game save bugs

randomize character poses in settings

categorize items

display categories in backpack

backpack categories toggle

add task board collection chest

board task generation (category, item)

task board initialization

improve task board structure

update curator asset

improve sub-menu transitions

board completion condition check

suspicious person in guild

In order to accommodate some of the new task type from the task board, I had to categorize all (over 150 so far) items and show the categories in the backpack GUI (with a toggle for when you don’t want to see them).

Also had to widen the taskboard several times to make sure all tasks would fit

refactor board tasks

add more board task types (multi, single)

add more board tasks

clean up some tasks

improved level up notification

particle effects for level up

particle effects for gold up/down

bugfix: new game after deleting a profile

more board task types (distinct, room, object)

testing new board task types

particle effects for player busted

migrated from Godot 4.1.2 to 4.2

add code regions

cleanup particle effects

improve level up delays

update NPC mid assets

bugfix: min city lot size

small tutorial & guild updates

update statistics board

gameplay demo with audience

NPC and Cop visibility cones

toggle visibility settings menu

At first I wasn’t going to show which NPCs can see you. In real life you don’t have a vision cone to hide from. I didn’t want this to feel like a Metal Gear game.

But it was hard to know when to pick a lock if you don’t know who can see you. So I decided to only have vision cones when you’re doing something illegal. That way you can hide better without staring at immersion-breaking vision cones all the time.

And I added an option to turn these off in the settings. I split NPC and cop vision cones because you might want to keep the cop vision as you will become wanted when a cop spots you doing something illegal.

design, draw, import ability icon assets

update some GUI themes

add player icon to save profile menu

added clout & VIP item label colors

more type safety and GUI theme edits

started work on the Burgleville website

particle effects for bashing and smashing

screen shake on bashing and smashing

screen shake toggle in settings

refactor notoriety logic when busted

add pathfinding for NPC chase mode

can be caught by NPC when trespassing

fix some spelling mistakes

theme donated item text to avoid donating again

particle effects for abilities and vehicle purchase

update main menu background

improve menu performance

more work on Burgleville website

Update app icon and window icon

test windows export exe

Cops were chasing the player in a straight line. It was easy to get them stuck on a tree or building. So I added real pathfinding so they can walk around objects. I didn’t make it perfect, though. I want the player to have fun running form the cops and trying to trick them. I didn’t want the game to feel too stressful with perfect cops.

The Menu Objects

I like a dynamic menu, so apart from the characters eyes moving around, the object that the character is stealing also changes.

I’ve been drawing 32 x 32 pixel graphics for everything this whole time, and I’m definitely not experienced enough to draw something bigger with shading and lighting and gradient colors. So I looked at a bunch of references and started combining sketching. Then I imported to paint shop pro and pixelated the drawings to make them fit in better with the aesthetic of the game.

Now most of the main mechanics are done.

Next step was adding a ton of dialogue. Each character has their own way of speaking.

Then I worked on recording music and sounds. That’s a whole project on its own.

Then I continued adding new locations and populating them with items.

A huge part of the remaining work is now adding more story missions. It’s not the hardest, but it’s the most tedious and time consuming.

Then it’s time to work on some dev-ops. Exporting and testing, integrating with Steamworks, configuring depots, pushing builds, etc.

Then it’s time to update the business side of things. Registering, licenses, business accounts, websites, Steam store assets, etc.

It’s time for PR! Making videos, trailers, dev blogs, and interacting with communities.

Finally - as I write this, the release date is nearing. After the release, I expect the usual bugfixes and maintenance.

This project was huge for a single person.

Hopefully you like it!