SleepSpace Post-Mortem

Image of SleepSpace title logo with a bed floating underneath

In August of 2022 we as Team Bouldy decided to get the band back together for a new project, so we registered for a slow jam with PigSquad. The jam itself provides both a technical and a creative theme, the technical for this jam being a Boss Fight, and the creative being Nightmares & Dreams. After some initial ideation we settled on the core theme of a plucky hero fighting an evil nightmare in a dream world to get to sleep and for the gameplay we decided we wanted to do something card-based on a hexagonal grid, with lots of inspiration from games we loved like Slay the Spire (Deck-Building) and Megaman Battle Network (Territory Control). We knew this would be a lot but we wanted to push ourselves after having done a lot of projects together to see what we could do (which we definitely did).

Gameplay Design:

With the themes and inspiration laid out, I began working on a rough concept for the gameplay. Because time was short, I decided that I didn’t want to implement traditional RPG mechanics like damage, stats, etc. and instead focus mainly on territory control as the primary mechanic for the game.

This meant that the primary goal of each round in the game would be to achieve a certain level of control, and any interaction with the boss, enemies, or cards would be through this lens. I wanted the territory mechanic to work similar to Go and Othello where there were 2 “colors” vying for control by flipping tiles to their side.

For the card system, I took a lot of inspiration from Slay The Spire and other deck builders by having the player draw a new hand each turn and limit them with energy costs for the cards.

I envisioned the enemies as smaller annoyances that would gum up the player’s plans if they weren’t dealt with.

The boss I envisioned as being an untouchable force of nature and your primary antagonist with semi-random impactful effects. It was important that since the effects were so impactful, they would be telegraphed to allow the player to plan around them in clever ways. The overall flow of the game would mimic a “final boss” encounter with 3 distinct phases, with power-ups between phases to allow the player to ramp up in power along with the enemies & boss.

After sketching out a rough concept, I walked the team through it to get feedback and identify any holes in the design. The feedback from the team was pretty positive so I moved on to ideation for card effects, enemies, boss moves etc. (while also doing the work of engineering the systems for them, more on that in the engineering section)

Concept

When creating the initial set of cards, I knew the key actions would be movement and tile flipping in various patterns. With this in mind, I developed a base set of 10 cards, most of which fall in line with those main categories but a few added a little necessary spice (drawing more cards, interrupting the next boss move). After designing the card set, I handed a build out to members of the team and some close friends to play-test and get feedback. The feedback was mostly positive, with a few cards that needed their cost/effects changed, but when talking with people who played they talked about different strategies that they employed. After the team getting into a heated debate about which cards/strategies were the best, I started to feel a lot more confident in the overall design.

The boss was tricky to get right and required the most iteration to get right. Initially, the boss would just pick a random move from a pool and do that every other turn with no more telegraphing than the name of a move. This resulted in 2 problems. First, the player wouldn’t understand the effects of the moves fully and felt cheated when they guessed wrong. The solution here was straightforward, I just needed to add more clear indicators of effects along with tooltips that helped clarify things further. The second problem I had was that it was difficult to balance the moves across all the phases of the game and make them feel challenging, but not overwhelming. My solution to this was to create separate pools of moves for each phase that could be balanced separately, while also creating variations of moves that were more or less powerful. This worked out really well because it allowed players to learn the move’s effects in the early stages before they became much more deadly later on and smoothed out the overall difficulty curve of the game.

Enemies came together at the last minute but ended up being one of the things people enjoyed most about the game. I initially started with a single enemy that moved around randomly, flipping tiles along the way and would drop a card pickup when defeated to incentivize the player to engage with them. This worked for most of development and introduced players to the concept of enemies in the first phase, but as we neared the end, it was clear this wouldn’t be enough. I utilized the path-finding system developed by the other engineer on the project and made an enemy type that tracked the player, this worked OK, but I wanted it to feel more threatening so I added a consequence for it catching up to the player by flipping all the tiles around them. The 3rd enemy I created utilized no movement at all and instead grew out like flower, flipping tiles along the way, which created a fun ramp up in danger over time if the player ignored them long enough. All of these enemies really come together nicely in the final phase, with a lot of decision-making and prioritization required by the player.

The Sleep Aids were the last big piece of the puzzle to come together for the gameplay. When creating the sleep aids, I looked at the primary knobs I could turn to make the player more effective, those being energy, number of cards drawn per turn, movement, and number of card choices from card pickups. Since I wanted play-testers to explore the whole space of the game and see what strategies emerged, I chose to make all 4 available between phases. I meant to change this and do something a bit more interesting, but I ran out of time while finishing up other parts of the game. If I went back to this system, I would want to make it a bit more random so that players are encouraged to explore other strategies and add some sleep aids that are more interesting than a simple power increase.

Engineering:

On the engineering side of things, I implemented the card, turn order, and player systems (in addition to the core of the mechanics described above). We wanted to be ambitious with the scope of this project, which led to some less than optimal solutions, but still, I’m really proud of how much we were able to get done in the short amount of time that we had for the jam.

The card system was a real treat to build and my favorite part of the project. I chose to optimize for flexibility in what a card could do so I made each card a prefab that had a list of delegates that it would invoke for playing a card (or previewing it’s effects). For those delegates, I built out a set of re-usable card effects that could be composed together like flipping tiles around a selected tile, generating a column of tile flips, drawing a number of cards, moving to a tile, etc. This made making and tuning cards very easy, allowing us to iterate quickly. For the look and feel of the hand, I employed SmoothLayoutGroup along with DoTween which made it easy to smoothly adjust card positions in the hand. In addition, I used some sorting tricks and other subtle animations (inspired by other digital card games I played) to allow the player to pick through their hand easily and grab the cards they want.

The turn order system was the next piece I built. It maintained a queue of turns and allowed the player, enemies, and the boss to register with it to get their turns. It would then update the turn order display and also generate future turns and add them to the turn list. The system worked well enough but got a bit fiddly when I needed to manipulate the turn list beyond adding and removing turns from the head and tail. Not sure how I would improve a system like this, but I will investigate a bit more.

Due to lack of upfront planning with the other engineer, the overall structure for the flow of the gameplay got out of hand quickly as we were making our own web of events that turned into a spaghetti mess that neither of us could fully unravel. This resulted in a lot of wrangling on my part to get things into a playable and (mostly) bug-free state. If I did it all over again, I would have centralized the flow of the game into a state machine so that we could more easily track the overall flow of events within and between turns & phases.

For this project I decided to try out Unity Atoms instead of using my homegrown scriptable object library since it seemed a lot more fully featured. It was nice at first but had some issues that would make me think twice about using it for future projects. By default, atoms will replay old events when loading a new scene, this makes reloading a scene an absolute nightmare since old events will replay from the previous instance of your scene and destroy any notion of a clean state. What’s worse is that the library provides no way to disable this or clear the replay buffer manually, so I had to use reflection to reach in and clear it myself so that we could get the game to restart properly. The other, lesser issue is that the library will bloat your project with a LOT of files if you want to make atoms specific to your project and use their code generation, which really clogs up your commits.

During this project I also found a great tool-tip library called ProTips, it was really easy to integrate and I can’t recommend it enough!