Monday, April 4, 2022

Ludum Dare 50: Bomp

This past weekend was Ludum Dare 50, a milestone event for my favorite game-creation event and its 20th anniversary. The theme was "Delay the inevitable." I sketched out a few ideas on Friday night based on the theme. Many of these were tossed quickly due to their art requirements, and I did not feel like investing a lot of time in drawing or trying to remember anything I've learned about 3D modeling. 

The idea that I kept coming back to was to explore one of my favorite inspirations, Every Extend. I have never played any of the commercial releases, but I've been intrigued by the original since shortly after its 2004 release. I wish I could remember how I even came across it. The game was the subject of a case study that I ran in 2006 in my first graduate class at Ball State. That led to my first SIGCSE paper and my first journal article. I have come back to it regularly in my game programming classes. I use the core systems of Every Extend as a sort of kata when learning new game engines: I've rebuilt it in plain Java, Slick, PlayN, Unreal Engine, and Godot Engine at a minimum. Those were all just technical experiments, though. I had never actually built the core systems into a complete game, even a small one for jam.

Until now.

For Ludum Dare 50, I made Bomp, an homage to Omega's original Every Extend. Just like the original, the core tension is that you start with a small stock of bombs, and you blow them up to earn points. Earning more points means you earn more bombs, but the number of points you need increases for each extension. This is where "delay the inevitable" comes in. The game is so short that even though running out of bombs is inevitable, you always feel like you can try one more time to beat your high score. (This kind of game really screams out for a local high score table, but that was out of scope for the 48 hours of Ludum Dare.)

I was able to explore a few specific game development ideas in the building of Bomp, and I'll share a few word about them here.

I have one explosion sound, a simple retro sound created with the SFXR plugin to LMMS. In order to add some variation, I pitch-shifted each instance of it. I did a little research to figure out how to get a normal distribution rather than a "flat" random number generator. By using randfn, I was able to shift the pitch of each one within a 0.15 standard deviation. The result is that they sound almost the same, but just different enough to be aurally interesting.

Most of my jam projects are 2D games, for various reasons, and many of my old Every Extend experiments have been implemented in 2D. For Bomp, I decided to build it in 3D, using CSG primitives for all of the asset needs so that I would not have to drop into Blender or some other modeling tool. This was easy and quick, and the result matches the gameplay aesthetic I wanted. The player's bomb is simply two tori that rotate independently, the obstacles are squares that spin, and (spoiler!) the "shooter" that comes in at the 30-second point is a combination of a box and cylinders. I had imagined exploring 3D shaders to get some more interesting visual effects, but I ended up putting my limited energies elsewhere. One thing I did explore was Godot's WorldEnvironment and its distance blur effect. This got me a great return on investment, but unfortunately, it does not work in the Web build. 

Windows version: Cool blurry background

Web version: Blurless

Two things I noticed about this blur effect are worth noting for future reference. First, if the model's material has transparency enabled, then it will blur regardless of distance from the camera. My best guess is that the alpha data is overloaded: these same data must be used for distance blur as are used for transparency, and the former supersedes the latter. Second, I had to switch to the GLES2 renderer in order for the Web build to work at all. When using distance blur and GLES3, the Web build was unusable, rife with visual artifacting. When using GLES2, the blur didn't work, but at least it showed the game as expected without it.

Over in LMMS, I wrote my first sketches that use effects and the automation track. My first pass at a theme involved an overdriven guitar playing over a bass, and I used a tremolo effect together with automation. This sketch ended up being too dark for the gameplay, and I abandoned it, although the project file is in the repository. For the song that ended being the main theme of the game, I used the automation system to pan the channel of the pads over time. I never did try that with headphones on, and maybe it's too subtle to hear. Or maybe I did it wrong. In any case, I know at least have a sense of how the effects system and the automation tracks work together with the main mixer.

Related to the music, I have been working on trying to get diminished chords more into my playing. If you can live long enough in my game (or click the link above to just hear the soundtrack), you get to a part of the song that uses some simple inversions followed by a cool diminished chord, right before the end of the loop. Now if I could only find the guitar chord fingering for diminished chords as quickly as I can arrange them in LMMS...

Those were the novel areas for me this time around. I am pleased with the result: everybody seemed to enjoy it at my family's play party last night, and most of the folks who have checked it out have given good feedback. Once again, I owe a lot to Omega (Kanta Matsuhisa), whose gameplay ideas I explored here. The tension in the core system is all due to him, but still, I am proud of my work as a quality execution of one of my favorite ideas. I am pleased with the software design as well, for those who are interested in such things.

You can find all the links to the source code and various builds from the project's Ludum Dare page. While you are there, be sure to check out the games made by my two oldest sons as well, The Poisoner and Grim Reaper vs. You! Featuring the Narrator!

No comments:

Post a Comment