Brackeys Game Jam 2021.1
My 11 year old son, his friend and I made a game for the Brackeys Game Jam in February 2021, during the pandemic. If you want to skip right to the game, here you go:
Click here to play Bowling for Monsters in your browser on Itch.io
Or... How to make a game with two 11 year olds
I've done a number of game jams, both solo and with teams of adults, but I've never done one with two 6th graders. This was different because the most important thing to me was that they had a positive experience. However I also know that most jams, especially for first timers, are disasters! So managing expectations was key.
The first thing I did was ask them what they wanted to get out of it. My son, Elliot, said his priority was to finish and to make something that did well in the jam rankings. His friend Kaung just wanted to have fun. So I took that as my challenge, to execute on their goals and make this feel like their game.
Next we figured out roles and responsibilities. Kaung has a way with words and is always making us laugh on Discord, so we wanted the game to have writing to support his skill. Luckily he is also quite technical and has run his own modded Minecraft server, coded in Visual Studio, and installed a number of ridiculous Discord Bots.
Elliot can do quite a bit in game development already including programming, art, sound, music, and design. He'd published two Itch games on his own before this, Acorn Hunt and Seat Labor. He's an aspiring game maker just like his dad. Yes I am still aspiring too.
So Elliot opted to focus on the art and music. That left me to do the programming and the organization. We made a little chart in Miro.com, which we used for our brainstorming.
Time is precious
The first thing we did was figure out how much time we had to work with. We used a unit of 1 day and walked through the week for each worker. It turned out that between school, work, and life, we each had about 3 full workdays for the 7 day jam. This set expectations on scope early. This also set up some accountability and expectations which were important to a new team.
Choosing the design
We all pitched ideas that we wanted to do in the time we had. Some of the ideas were a bit big at first, but Elliot's experience with shipping his own games helped him to reign it in. Ultimately we had two designs to choose from that captured all of our skills and seemed doable.
Both of these ideas seemed to work for our team. We sat on it for a few days, but then the theme was announced for the jam. It was "Stronger Together". The boys immediately saw how Bowling For Monsters was a better fit for the theme, so we went that way. Someday I'd like to come back to Skydiving Poet.
Tools and Pipelines
I felt like my biggest challenge, after picking a design that the boys felt invested in, was to figure out how they could work effectively without me. Art wasn't a big concern, becuase Elliot has his preferred tools already (Pixilart.com is his favorite). The writing was the thing. At first I thought we'd just set up a Google Sheet for Kaung, but after talking to Eka I learned about Yarn Spinner.
Yarn Spinner handles branching dialogue, setting variables, localization, and way more. After doing this project I'd use it again. The Unity integration is particularly neat, as they made a custom importer for .yarn files.
It also comes with a Unity UI setup for displaying the dialogue in game, which I pretty much just used as is with a few tweaks.
So Kaung was able to just hammer on stuff in the Yarn Editor and test in Unity without needing the game to work. He wrote some ridiculous stuff too. It was really fun to see what he did once his tools were working. We got tripped up a bit by the restriction that all Yarn nodes must be uniquely named. They all get loaded into a giant pile at game start. Once we figured that out and made each node <Character>.<Thing> that worked.
The Bowling Problem
Most of this project was pretty easy from the programming perspective. I just set up a loop between the bowling and dialogue segments using a simple state machine that used coroutines to sequence their transitions. The bowling segment though, presented a few challenges.
The first issue was that the art style Elliot was doing was pretty low resolution pixel art. I had to figure out how to match this while still using 3D physics. He ended up drawing the alley art in perspective and so I just decided I would overlay some 3D objects and use a rendertexture to downres them. It worked nicely.
So, getting bowling going artistically and mechanically was about a day for me. However I still didn't understand how scoring worked in bowling. Even worse, once I DID think I understood it, I still didn't understand it!
Bowling Scoring is a Sick Joke
OK ok I know that sounds extreme, but there is a reason that bowling scoring is used as a programming test on job interviews. It's an interesting problem that seems simple but is not. This has really cluttered the internet with bad takes. Just try Googling it. You'll find every manner of overengineered Java solutions with a class for every aspect of the frame. All I wanted was a simple function that would take in an array of frames and calculate the score! Eventually I found something on StackOverflow that looked good.
Thankfully after a lot of searching, the user Ranier P posted at the bottom of this Stack Overflow thread and included a simple C# extension method that is the essence of scoring bowling:
//C# List extensions method to calculate score
public static IEnumerable<int> Scores(this IList<int> pins)
{
// Walk the list in steps of two rolls (= one frame)
for (int i = 0; i + 1 < pins.Count; i += 2)
{
// Neither strike nor spare
if (pins[i] + pins[i + 1] < 10)
{
yield return pins[i] + pins[i + 1];
continue;
}
// Score can only be determined if third roll is available
if (i + 2 >= pins.Count)
yield break;
yield return pins[i] + pins[i + 1] + pins[i + 2];
// In case of strike, advance only by one
if (pins[i] == 10)
i--;
}
}
//economical storage and methods for each roll
public class BowlingScoring
{
private List<int> pins = new List<int>();
public void Roll(int n) => pins.Add(n);
public void SetRoll(int idx, int score) => pins[idx] = score;
public void Clear() => pins.Clear();
public int Score(int frame) => pins.Scores().Take(frame).Sum();
}
Now, you'd think that would do it, and I'd be done. But NO, a fundamental misunderstanding held me up. See, I didn't realize that in bowling (10 pin bowling that is), the scoring is based on ROLLS not FRAMES. The difference is that every frame does NOT have two rolls. I mistakenly thought that a strike was a roll of 10 and then an automatic roll of 0 after to fill the frame. This is wrong. A strike makes a frame have one roll. Once you understand this, it becomes apparent how a 300 game is possible. Each strike looks ahead two rolls, so in the case of three strikes in a row, the first frame resolves as 30. Thus, 10 frames that look ahead two frames to strikes yields 10 x 30 or 300.
I did not understand this and it cost me a lot of time.
Now, this just gets you the calculated score for each frame. It does not tell your UI how to present the frames. This was a whole other problem. You've got to draw an X if it's a strike, a / if it's a spare, and hold a blank frame if the strike or spare isn't resolved yet. Unfortunately I didn't figure out some simple way to do this and just beat it into submission by building a UI that updated on OnValidate and then I just entered values into the rolls list in the inspector until I couldn't break it.
In its entirety, the bowling scoring system took me well over a day and I didn't even finish it on time for the jam. So after all that prep I was the one that ended up missing the mark! Nice lesson for the boys there.
Jam Submission
So we worked pretty casually during the week, which meant our final day, Saturday, was a rush. Of course, this meant that there were integration issues as we stuffed content into the game at the last minute... but the game was fun and funny! The characters had a lot of personality and the writing was full of surprises. Elliot even wrote a custom music loop for each character. His music for the bowling roll was also timed perfectly on the first try.
Pretty close to the end we started implementing the ability system, which was where monsters would give you special bowling abilities after a conversation. We ended up finishing BIG BALL, QUICKSHOT, and PERFECT TIMING, each of which were quite fun to see.
The boys worked really hard the last day and we managed to get the game submitted with a few minutes to spare. The feedback was great! Here's the jam submission link:
https://itch.io/jam/brackeys-5/rate/928181
This was pretty good for a first time submission from a group with two sixth graders! There were 1,885 entries in the jam, so this put team Cheesebucket in the top third. I'll take it.
Lessons
I think our team learned that you have to get done with your game at least a day early in a weeklong jam, so you can test test test and polish. While I put in a few solid days during the week (mainly because I was stressed that I would be the one that held the team up), the boys didn't do much during the school week. That rush on Friday and Saturday left us tired and sloppy (even me). So aiming to finish the game on Thursday or Friday would have been ideal, with a sense of urgency throughout the week. Granted, that is tough when you have jobs and school, but "sleep when you're dead" is what my Dad says.
Most importantly, we hit on the boys goals of A) Finishing and B) Having Fun.
Click here to play Bowling for Monsters in your browser on Itch.io
Hi, I'm Ben Throop
This is my personal site about game development and emergent behavior. You can learn more about me here.
All Posts
- Elegant GPU Animation in Unity
November 6, 2022 - Compute Shaders and Emergent Algorithms
June 4, 2021 - Brackeys Game Jam 2021.1
March 20, 2021 - MIGS 2017 Talk - Blowing Things up in Unity
November 5, 2020 - Headmaster Development Tools Talk
November 21, 2019 - Headmaster @ 2017 Champions League Final
June 6, 2017 - Headmaster @ 2016 Champions League Final
May 31, 2017 - Why root for VR to fail?
July 21, 2015