A web developer walks into a game jam...
Here's a super hot take for ya: making video games is hard, especially when you're new to it. Even though we each have a decade of experience developing software and we picked the simplest possible idea, it still took us multiple months to finish our first little game!
As we started planning for our next game, we realized there was one big unknown floating around: how much had we actually learned from building Boba Simulator 2020? We certainly felt like we'd learned a lot, but we couldn't quantify it. We started Bee's Knees Games with the assumption that our years of development experience would allow us to pick up game development more quickly, but with only a single point of reference so far, we weren't sure if we'd need to reevaluate our various business timelines to account for a longer ramp-up time.
Right around this time, Portland Indie Game Squad announced an upcoming game jam: Summer Slow Jams 2020. We'd never done a game jam before, we both love turn-based games, and we were excited to use everything we'd learned on Boba Simulator 2020 to build another quick game and compare the development processes of the two games. We felt like finishing a second small game would give us a much more concrete idea of our ramp-up time, and allow us to estimate the development time of our next game with greater accuracy.
You can download OXO on itch.io, and if you stick around, you can read our thoughts on the development.
We got an idea for a gardening game
The initial game jam announcement said that all games must be turn-based, but they didn't announce the creative theme, so we started a brainstorm on what types of things we'd like to see in a turn-based game. As the Bee's Knees Games CPO (Chief Plant Officer), Jessica immediately gravitated towards a gardening game, where weeds spread every turn and you have to prune them before they overtaking your garden.
We got very excited coming up with different ideas for weed-spreading algorithms and the pruning tools that you could use. We also felt like we could pretty easily swap gardens and weeds for a lot of other possible themes (a virus spreading across a network, a fire spreading through a forest, etc.), so we felt comfortable thinking deeply about the idea even without knowing what the creative theme would be.
We got extremely lucky
A couple days before the official start of the game jam, Alex Benson reached out – he's a 3D animator and musician who had also never done a game jam and was looking for a team to join. We'd nervously agreed on doing the graphics and music ourselves, but when Alex reached out, we felt so lucky. I mean, just check out his work.
Not to spoil the rest of the blog post, but Alex was an amazing teammate. We'll go into greater detail later, but it's hard to imagine the game we all made together without Alex's artwork and music. Alex brought a style and a level of quality to the project that ultimately let us go far beyond what we thought we could accomplish in two weeks.
We got our creative theme
A few days later, PIGSquad announced the creative theme: "alternate timelines". The three of us met on Discord and discussed whether our initial weed-spreading idea was adaptable or not.
Ultimately, we decided our game would have a whole multiverse of different timelines, and the walls between the timelines would be breaking down, and the player's job would be to fix the cracks between the timelines before the whole universe collapses in on itself. Which, if you think about it, is pretty much just pruning weeds with some fancy shaders.
We organized ourselves
While we were still unsure on how well our web development experience was translating to game development, we knew how to organize ourselves when developing software, and we felt confident that this knowledge would work well for game development. We used:
- A GitHub repository for version control.
- A Trello board for tracking work and sharing assets.
- A Discord channel for synchronous communication between the three of us. We'd normally use Slack, but Discord is better when collaborating with someone outside our company.
These tools worked great for us, and we'd highly recommend them to other teams participating in a game jam.
We started building the game
With our team organized and our game idea laid out, we started work on the actual game. Our first task was planning a simple very simple version of the gameplay to get the game's foundations in place. In web development, we call this concept "minimum viable product" (MVP for short), and we felt like this idea would translate well to game development.
We started work on our MVP by brainstorming about how the timeline damage would spread across the board, and what options the player would have for fighting it. We did our earliest prototypes using some super high-tech tools:
This was super useful for quickly figuring out what options might make sense and ruling out non-starters. After a couple hours, we took what we'd learned and started coming up with algorithms that would translate well to a computer.
The damage spread algorithm
We wanted the timeline damage to start out feeling minor, but to get "out of control" as it spreads across the board. To enable this, we came up with an idea we called "damage heads".
On turn 1, there is a single damage head in a corner of the board. Every turn, this head moves to a random adjacent cell, leaving behind a trail of damage on all the cells it previously touched.
Alone, this simple algorithm never gives the feeling of the board getting out of control, since only one new cell is damaged each turn. However, we also included a second rule: every 3 turns, all damage heads split in two.
This gave us the feeling we were looking for. Now, if you dilly dally around fixing up damage without a plan, the damage heads will grow exponentially and you won't be able to fix things fast enough. This algorithm evolved to be a bit more complicated over time, but its roots remained the same.
The player's options
We decided to start the player out with just two simple options: "move" and "fix". The player gets three "action points" per turn, and can spend them moving to a different cell, fixing the damage on a cell, or some combination of the two. Moving and fixing cost the same amount: one action point per cell traveled. For example, fixing (or moving to) the cell directly on your left costs one action point, while fixing the cell that's two steps to your left costs two action points.
While these options are extremely simple, we felt like they were great for an MVP, and we'd be able to expand on them later on. Like the damage algorithm, these rules evolved over time, and the final game has slightly modified rules. You can see our final rules list on the game's itch.io page.
We built a solid foundation and iterated on it
With only two weeks to build the game, it was tempting to start hacking something onto the screen right away and throw any semblance of foundational planning out the window. However, we still decided to still spend some time building a solid foundation. We really wanted to build something that was at least somewhat fun, and we knew this would require a lot of tweaking of various aspects of the game (board dimensions, action point costs, etc.). Our experience with web development taught us that small tweaks like this are easy in a well-architected system, but in a hastily-thrown-together one, each tweak can take a very long time. We predicted that spending some up-front time on architecture would save us time in the long run, and we turned out to be right. Here are a couple examples of this foundational work.
The grid. A multi-coordinate-system frontier.
All game logic took place on a square grid, which meant the game would inherently contain two coordinate systems:
- The Unity coordinate system, which gives each object a 3D floating point coordinate specifying where that object lives in the scene. An object living in the absolute center of the scene has a Unity coordinate system position of
(0.0f, 0.0f, 0.0f), while an object that's supposed to be 2.5 meters above the center will be at
(0.0f, 2.5f, 0.0f)
- The grid's own coordinate system, where each cell has a 2D integer coordinate. On our 16x16 board, the bottom-left cell has a grid coordinate of
(0, 0), while the bottom-right cell is at
(15, 0), and the top-right cell is at
We knew we'd need to do a lot of translations between these two coordinate systems. For example, if we wanted to move the player from cell
(2, 2) to cell
(2, 3), we'd need to figure out the Unity coordinate system position for each of those cells, so that we could animate the movement between them correctly. Our experience building Boba Simulator 2020 taught us that we really want to limit how much Unity position math is spread throughout the system, so we decided to encapsulate all the coordinate system translation logic in our Grid class. Much of this work was done by the
For example, instead of manually calculating the player object's Unity position during a move, we can just call
Grid.PositionForCoords() in the player movement method, and then do a simple lerp between the positions. This lets us keep the translation math out of the Player code entirely.
The debug menu
Early in the development of Boba Simulator 2020, we found that we had certain parameters we wanted to tweak frequently during development. Once this became bothersome enough, we added a "debug mode" that would toggle between debug-friendly values and the values we intended for players. For example, the tapioca balls in the game should normally fall randomly across the screen, but this made it slow to test the ball-catching logic, so we made the tapioca balls fall down in a straight line in debug mode. This toggle proved useful in Boba Simulator 2020's development, but left some granularity to be desired.
With this lesson in mind, we added a debug menu to this game very early on.
With this debug menu, we were able to quickly tweak all sorts of parameters with lots of granularity. For example, we spent a lot of thought on whether or not the player should be allowed to move diagonally, and the size of the board had a strong influence on this decision. We put board size and diagonal movement in the debug menu, which allowed us to quickly (and independently) tweak these values. This greatly reduced the time it took to come to a decision on the correct "release" values for these parameters.
Our prior experience on Boba Simulator 2020 saved us time here in two ways:
- We already had experience building a debug mode, so we were able to implement the debug menu fast.
- We made the debug menu right away, so we didn't have to spend extra time refactoring to expose the parameters to the debug menu.
We added artwork
While we prototyped and iterated on the game's code, Alex was hard at work creating a lovable central character. Here's a glimpse of the evolution of the characters he came up with:
Working with Alex at this stage and seeing the questions he asked taught us a lot about developing a character. For example, Alex asked our opinions on all sorts of parts of the character's backstory. Was he supposed to be highly skilled or more of a clumsy worker who happened to get the job done? Was he supposed to be happy and optimistic or more focused and serious? Coming up with these answers together was a fun exercise, and seeing them reflected in the character's model and animations was extremely rewarding.
We also derived the name of the main character (and ultimately, the game) from Alex's artwork. We all loved the look of the main character's face, and Jessica even put it into an ASCII emoticon. The rest is history.
As OXO progressed, Alex began creating artwork for the environment. Here's some examples of his environmental artwork progression:
Later on in the project, Alex sent us the music he'd been working on for the game. We absolutely loved it on the first listen, and we came to love it even more as we added it into the game and saw how well it worked with the visual art style. To this day, we still find ourselves randomly humming the song while doing the dishes. If you want to hear for yourself, you can download the game on itch.io or you can listen to the track on Bandcamp.
The last few days of the game jam were "crunch time". We spent this time adding in the last few animations, squashing bugs, designing and implementing the UI (with only a few hours to go!), and creating builds for submissions. A few of these took longer than we expected, which contributed to the large amount of work we did in the last few days.
A couple of the remaining tasks required more programming than we would've expected.
Some of the attack animations needed to behave a bit differently depending on what was happening in OXO. For example, the "spin attack" drops a bandaid on every adjacent cell, which could drop anywhere between three and eight bandaids depending on where the player is standing on the board. These "dynamic" animations took us much longer to integrate than we expected.
A few intermittent bugs also ended up requiring some significant refactoring of the code. For example, the logic that smoothly lerps the player from one cell to another used to live in the player's
Update() method. This is a method that Unity calls once per frame, and a lot of game logic often lives in it, but it can become hard to follow if it's trying to do a single piece of work (like moving the player from one cell to another) over multiple calls. Having the player movement code in an
Update() method led to an intermittent bug where the player would sometimes end up facing the wrong direction after moving. We refactored this movement logic into a coroutine, which fixed the bug and left us with simpler code, but it was quite a time-consuming refactor to be doing at the 11th hour.
This crunch continued right up until the deadline, and unfortunately, a few hours past it too. With about an hour before submissions were due, we switched the project's scripting backend from Mono (which Unity uses when running games in the editor) to IL2CPP and started our final build. Developers with compiled language experience will immediately see where this is going: the IL2CPP build had some game-breaking bugs that we'd never seen in the Mono builds.
We frantically tried to track down the source of the bugs, until 11:55pm hit. At this point, we accepted our fate, and messaged one of the PIGSquad organizers to ask for an extension on the deadline. Luckily for us, PIGSquad was very understanding, so we had time to get the build working right.
We dug deep into these new bugs for a few hours, and at around 2AM we found the issue: the work being done in our Unity
Start() methods. If you have multiple classes with
Start() methods, there's no guarantee on what order those
Start() methods will be called in. However, we believe the Mono scripting backend will always end up calling them in the same order, and the IL2CPP scripting backend may call them in a different order than Mono does. We believe our bugs were due to that hidden change in order, and once we restructured the code to be order-independent, the bugs were gone.
We finished! But there's always more.
Finally, at around 3AM on June 22, we submitted our Mac and Windows builds of OXO! This felt great, but as the common wisdom goes, you never really finish a piece of creative work, you just run out of time. Here's a list of a few different improvements we wish we'd had time to make:
- We would've liked to integrate more of the story and lore. Alex was able to pack a lot of storytelling into the animations and environment, but with more time we could've dove even deeper into OXO's world.
- The game is a little too easy right now. We erred on the side of easy so new players wouldn't get frustrated, but once you've figured out how to beat it, it's very difficult to lose. We would've liked to add some difficulty without making it frustrating for new players.
- It's currently hard to tell when one turn ends and the next one begins. We would've liked to add some more obvious transitions to let the player know when a turn's passed.
- A few little bugs still made it in, like the pause menu's dark overlay not stretching to fill the screen at certain resolutions. All pretty minor stuff, but as Wayne Gretzky says when he's doing game jams, you always regret 100% of the bugs you don't have time to fix.
In addition to these improvements, here are some "stretch" features that we wanted to build but didn't have time:
- If the worker stuck in the hole on the grid is surrounded by damage, you've failed to protect the worker from a tear in the universe, and you should lose the game. Additionally, you should be able to "rescue" the scared worker from impending doom. This would've been an interesting tempo tradeoff: you can eliminate the risk of the worker being surrounded, but you have to spend some turns moving towards him and rescuing him, during which the damage could get out of control.
- It might have been cool for the player to have multiple "lives". Alex had a mockup for this where a new OXO robot would scamper out of the vehicle and onto the board after the after the previous OXO fell into an alternate timeline.
- We would have liked to make some of the damaged cells start showing "tears" into other timelines. We had a cool idea for an effect where you'd effectively see bits of another board through these tears, really hammering home the "alternate timeline" theme.
- We had an alternative set of logic for the "bomb" attack that might've been interesting. Instead of going off when the damage touches it (which is more like a landmine than a bomb), the bomb could explode a few turns after being placed, hurting the player if they're too close. This is probably a downgrade from the current bomb logic, so in exchange, this bomb could've had a bigger blast radius.
Despite this retrospective, we're extremely proud of what the three of us created. We found the final build of OXO to be legitimately enjoyable to play, look at, and listen to.
All in all, we feel relieved that the development of OXO was a crystal-clear indicator that experience in web development is indeed transferrable to game development. Even though we're using a new language with a totally different domain, we're not really "starting over from scratch"; our web development experience is allowing us to get up to speed quickly on game development. If you're a developer who's never worked on games but has always wanted to, we hope this blog post gives you some extra confidence to give it a shot!
Working with Alex was an absolute joy, and we're pumped to see what cool stuff he makes next. In fact, he's somehow already got another new game out for PIGSquad's most recent game jam, and he made it completely solo (did he even need us??)! Check out his game Open Mic Night, and while you're at it, we'd suggest following him on Twitter and Instagram.
We also really enjoyed the experience of participating in our first game jam, and we'd definitely like to do more in the future. We particularly enjoyed participating in the PIGSquad community. They're a really great group of people, and if you're considering doing your own first game jam, definitely consider entering one of their Summer Slow Jams – they're extremely fun, and everyone is welcome (even if you live on the other side of the world!).
Now that we're done with our first game jam, we're starting work on our first commercial game! If you're interested in hearing more from us as we build it, you can stay in touch via the following channels:
- Sign up for infrequent updates from our newsletter.
- Follow us on Twitter. Bee's Knees Games has an official account, and our personal accounts are @jessicard and @jakecard.
- Join our Discord! We'll be around to chat, and you can also pop in to leave a bug report or just say hi.
Jessica and Jake