GMTK Game Jam 2022 PostJam Analysis


Pre Jam

Prior to the start of the game jam, I had done a bit of work on my game engine so that I could add some more features and refinements to make my experience during the jam easier. Without knowing what the jam would be, I wanted to make sure that I added some features which could be useful.

Updating .NET

The first thing I wanted to do was update my game engine from .NET Core 3.1 to .NET 6. I thought it would be a pretty easy change but I might have realized it would cause more problems. Unbeknownst to me, Microsoft had deprecated the already limited and short-lived support for System.Drawing that was cross platform for Linux. This led me to do a partial re-write of my drawing and bitmap classes. This is almost certainly for the better because now I have more flexibility to directly use the underlying bitmap classes from whichever UI/Window library I decide to import. (Prior to this, I was converting System.Drawing bitmaps to Avalonia images which was a large performance drain).

With that out of the way I wanted to make sure that my sample games would run on my Steam Deck.  There were a few things I had put a hack in for like window transparency, but those were pretty niche and could likely be ignored. I noticed though that despite the sound library (NAudio) I was using being cross platform compile-able, it didn't actually support audio on Linux

Sound on Linux

(I'll start by prefacing that I learned more about sound and audio buffers than I cared too, and I don't think I even learned them all too well, just enough to shoot myself in the foot.) After deciding to tackle adding sound to Linux (because how hard could that be really?) I started searching for plugins to NAudio that supported Linux. I wasn't able to find anything that seemed to suit my needs, so I sat down and started researching.  After a bunch of research I settled on ALSA (using libasound), which I hope is enough to be be rather far-reaching to work on other distros, and started coding an interop class to make the appropriate library calls. The code was relatively easy, but understanding the code and what it did and why you needed certain calls wasn't very well documented. After some trial and error and referencing a few different sources, I was able to make my Steam Deck produce sound. It was NOT the kind of sound you want devices to be making. Now I just needed to figure out why it didn't sound right (I needed to convert to a different audio format). This took a lot of trial and error but eventually I was able to get the audio working for a very specific input format. I considered this good enough and wrote a conversion from other sample rates and number of channels to a set 44100hz, 2 channel, 16bit output. This works relatively well except for some minor bugs (like skipping a sample occasionally).

Controller Support

After having triumphed with sound after 2 weeks of battle, I decided that it would be relatively easy to add some system calls to xinput in order to get XBox controller support working at the very least. I had done this in Java for Windows in the past, so I vaguely remembered what I needed to do for that. After searching for more information on Linux though, I found that there wasn't such support shipped with the OS. Instead it seemed that the base way to get controller input was to read the device system files and see if any controllers were connected. I found that there were 2 different formats, one with events, and one without. I wasn't sure which to use at first and ended up writing a solution that combined both and did not work. I was able to set myself straight and separated the 2 implementations, and I believe I have both working on Linux.


The Jam

The Night Before

It had been a few days since I'd finished work on the final updates to my engine before the jam and so to do some final preparations, I booted up OBS and made sure that my streaming setup still worked. I made a few more tweaks to it and got the auto-scene switcher working better for my setup.

The Day Of

I could barely think about work. I already knew I would be taking a half-day. I made sure to eat lunch and have my afternoon coffee prepped. I opened GitHub, and got ready to make a new repository for my entry, and cloned the empty repo locally. I imported the local NuGet files for my game engine and awaited the announcement for the theme. "Roll of the Dice", I thought that sounded fun, I love rolling dice and games of chance. I hurried to start the connections for my engine, picking the frame rate, the window size, and view parameters. Meanwhile I was letting the idea brew in the back of my head while I set up my project and got ready to start developing. Once I was really ready to get started, my mind began to wander towards some other games I had played recently, like SNKRX and Stacklands. I also thought back to any fun boardgames which used dice rolling and the first that popped into my head was Yahtzee! I gave it some thought and decided to give it a shot, a roguelike Yahtzee! game. I had not yet thought how it would work, just that I thought I could make it work.

The End of Day 1

By the night of day 1, I had gotten the sprites set up for all the dice, and a basic pickup and rolling system for the dice. I had decided to use a picture of my desk for the background, and my bag of dice (These ended up in the final submission!). By this point I was still not sure how to go about getting the core concept of yahtzee and massaging it into something that might play like an rpg rougelike. I knew I wanted the dice to represent adventurers, and for the missions to have some sort of enemy/enemies but I wasn't sure how to score or treat the missions. In Yahtzee! it's simple, you just add the value of the dice faces and that's your score. I wasn't sure if I wanted there to be more to it, or how I might rate/score an adventuring group vs a monster or task. I went to bad that night knowing that in the morning I would be able to think better about it, and that I might just easily get a solution in the morning.

The Next Morning

I get a full nights sleep because I decided not to use an alarm. Feeling refreshed, I grab a cup of coffee and sit back down at my computer. Thinking through some more ideas, I can't quite figure out how to resolve a score in a single step like Yahtzee! does. Instead, I opt for the "simpler" approach: send the dice to battle! Battles are always pretty clear cut, you either win or you don't. I think that this should work decently well and be pretty easy to implement in the timeframe given. I start off to write some battle code. Nearing the end of the morning, I've come up with a name at this point: "Dicey Guildkeeper".

The Idea

The idea is that the player is a guildkeeper, and adventurers are asking for assignments. A bunch of ideas start whizzing around in my head, but I decide not to entertain. Adding too much to the scope at this point would spell the end of my jam entry. I need to focus on finalizing the game loop, adding some better feedback for the player, and then final testing and refining.

Lunch

I'm starting to make decent progress on my entry, but I hadn't eaten yet today (just a cup of coffee). I knew it was about time to grab some food, and I had a pending invite to grab a bit to eat and catch up with an old friend. I did this which cost a bit over an hour. It was enough time to get my mind off the jam for a bit and come back with a fresh perspective and renew my motivation. I had come up with the idea to record some sounds of dice and use them in the game. What are dice rolls without the intoxicating crackling of dice bounding around and the clacking of their collisions? The day is too noisy, and I make a note to make them at night and when the AC is off.

The First Major Bug

Disaster strikes! I'm getting "key already added to dictionary" I can't quite figure out why. I know it has something to do with transitioning locations and copying entities between them. I know I'm removing them from the old location before adding to the new, but the execution doesn't lie. After 30 minutes of debugging I figure out that after transitioning locations, entity removals are delayed until the next engine tick, but only after they're added. I quickly note in the code that I have a major engine bug, and start on a solution. The easiest thing I can think of is to just force another tick of the location before continuing on. This works decently well, I just need to make sure to remove any chance of infinite recursion (I didn't, at first, but I was able to fix the second occurrence of the bug).

Evening

Now's the time to start creating the sounds and think about any other final touches I might want to add. I play around with some dice on my desk and after getting a bunch of samples of dice rolling, I throw them in the game and have each dice choose a random sample to use for each roll, as well as for their collisions. This has a surprisingly nice sound, and I'm quite happy by it. I try to make a soundtrack I can play on repeat that sounds like groups of adventurers chatting in a guild, but the result is a bit creepy. I added it, but put it behind a toggle, just in case.

The Final Morning

I quickly assign the sounds to the dice and the ambience to the main menu. I create a quick jingle because joining to a silent game just seems so boring. I've had very negative feedback in past years about audio, and so I decided to create a mute toggle and insert it in all locations. A quick click of the toggle and all sound stop.

The Second Bug

This bug was more minor than the first bug discovery. This time I found that the audio resumes despite attempts to stop/clear it (I didn't have an explicit clear function and had hoped "Stop" would be enough). I had just been working in this code and never though to test stopping it, I also don't expose the sound player directly, so I try to do some hacks to clear the sound buffer, but nothing seems to work. I write a note in my game, this time without a workaround.

2 Hours Left

There are 2 hours left in the jam. In the past this is the stopping point. I had submitted 10 minutes prior and breath a sigh of relief. I think ok, this should be good. I'm pretty happy with this. I take a break from development, shower, and eat breakfast. I come back and decide that since the jam is still going, I'll use the last remaining time to try and iron out some bugs, and throw some text on the game screen (It hadn't occurred to me to write a tutorial earlier and I wasn't in the mindset for new features). I refine the missions a bit to make the difficulty slightly harder. Before this, it was a pushover to ramp up and win.

The Big Crunch

It's 10 minutes before the jam comes to an end. I think "Oh shoot, I never tested going from the last boss to the win screen, I wonder if that actually works." Surprise! It didn't. Classic off by 1 error. Instead of going to the victory screen, the game just crashes. PANIC. I revert my changes for debug, and make a build. I open the Itch page and get ready to upload. I load up the game and quick play through it, things are working find still. Nervously I upload the file with 5 minutes left. The site is grinding to a halt. It takes around 30 seconds before the site registers my upload as starting. I'm a bit relieved but I'm still nervous that something could be broken. Time is up.

The Final Bug

Since time is called, I start writing up a better description on my page, and play through my game. Since I've developed it I know it's on the easier side, and can pretty easily be cheesed. I think that's fine though for a jam entry. Don't want to make it too difficult. I get to the final boss with a half-downed party, unsure of my victory. I enter the final battle. My jaw drops. The final boss has 0 attack. The tension is gone, and disappointment sets in. The climax is ruined, but there's nothing to be done. I already knew what had gone wrong. The darn regular expression I was using couldn't handle double digit damage. If I hadn't rushed and hacked together the missions this would never have happened. In the end though, I think it's ok. The final battle was nothing extraordinary, just a final enemy that hits like a truck.


Post Jam

Marketing

Now starts the fun. Time to try and promote my game. I think I've got a pretty good idea here with a fairly decent implementation (I'll let the reader/player be the judge of this). I grab a screenshot of the game and slap that into the cover image, better to have an image than not. After a day and with little promotion, my CTR is around 0.48. It's low, but that's what I'm used to. I change my cover to just the title screen in the hopes that it will raise the CTR, and it does a bit, up to 0.54. I do one last thing: create a pixel art background with some dice and the title name. This increases CTR all the way to 0.65. I'm pretty happy with that. I know without some sort of streamer picking up my game that it won't reach a wider audience, especially since I don't have a web version. I resign to the fact that my best bet for ratings and exposure to is "trade" plays/comments/ratings. This isn't so bad though, I had previously gone through games in need of ratings to help boost those game's ratings. This did 2 things for me: 1. boost my karma, but more importantly 2. made me feel good. I know it sucks to not have a lot of ratings or people seeing my game, so I felt like I was really able to give back to the community by doing this. By the end of the rating period, I had rated about 70 games and received 33 ratings (Midway through I had noted a 66 reviews and 18 ratings which put be in the top 60 for most karma).

Updates

After the closing of the ratings, the uploads have been re-enabled on the jam entries. I've spent a couple hours to add a rough tutorial, a reset option for the game, and a few minutes to fix the final boss health bug. I published this on Itch, but I made sure to leave my old build to be inspected for later.

Results

Hopes

I'm rather hopeful of my ratings. It seemed like comments I had received were very positive. I know the score will suffer due to lack of tutorial or refined graphics. My hope for this year is to be in the top 40% of games overall, with a top 20% in creativity. I'm almost certain the presentation (poor graphics) and likely the enjoyment (lack of tutorial/confusion) will be holding the game back.

Final Score

Fantastic! My hopes were met. I did top 15% in creativity, and top 30% overall. As expected my presentation really dragged down my overall rating, but that's generally not what I care about in a game jam while doing it solo.

Prior Years

I went back to check out how I did in previous year and I'd like to share the results here.

In 2020, I made a game called Rule Scramble for the theme Out of Control. It did ok, but had a very high creativity which I was happy with. The presentation was abysmal which I accepted because I was using "primitive" calls, like drawRect and drawEllipse.

The following year, 2021, I made a game called Idle Together for the theme Joined Together. This game was a relative flop (likely not just because it was a clicker/idle game). It scored worse in general, but it also had a broken gameplay loop. My focus that year was presentation, which I was relatively happy with an even 3. Note: I did NOT create the assets for this game during the game jam, instead I re-used/altered assets for which I had already purchased.

Compare

  • This year I broke top 1000 in a category for the first time, and top 15%.
  • This year my ratings are more grouped to 3 stars with a slight inclination towards 4 stars whereas in previous years the ratings were inclined towards 2 stars and much more evenly distributed.
  • The 3 and 4 star ratings make up oh so nearly 2/3 of all the ratings (65.6%).
  • My creativity earned a 3.576 of 5 stars (which is 71.52% a C-, though I wonder what the standard deviation is like)

Next Steps

What's next for Dicey Guildkeeper?

What to do next? I think I have something pretty good here. Not the code, but the idea. I have a bunch of things in the back of my mind still that I tossed to the side in order to complete the jam. Right now the game is very abstract and it looks and feels like a tabletop game. I picture a game which shows you the guild, and has adventurers which you can actually see. I picture better fights; not just a single enemy, and different types of damage, like melee, ranged, and magic which are more than just damage. I see the potential for replayability, as a rougelite instead of a rougelike. Perhaps buying upgrades for your guild which could give buffs to adventurers or alter the dice you use to represent them.

Next Year

Next year, one of my goals is to make a game as a team. I'm sure there are more difficulties when designing in a group. I still hope to be using my game engine, so I'm sure a group with people I don't know wouldn't work out for me in that regard. I do hope to add web support for my game because I see how important that is for CTR and discoverability.


Thank you for taking the time to read. I've opened up for comments so feel free to start a discussion. I'm also available on the GMTK discord for discussion. Cheers!

Files

Post-Jam version 31 MB
Jul 24, 2022
GMTK Game Jam 2022 version 31 MB
Jul 17, 2022
Linux GMTK Game Jam 2022 version 25 MB
Jul 17, 2022

Get Dicey Guildkeeper

Leave a comment

Log in with itch.io to leave a comment.