Sunday, October 4, 2020

Ludum Dare 47: Orbital Blast

Ludum Dare 47 ran from 6PM on Friday, October 2, to 6PM on Sunday, October 4. This is the latest instantiation of one of my favorite game-making events. The traditional Ludum Dare is a 48-hour game development competition in which participants are given a theme and then must make a game from scratch—code, art, music, sound, story—within the time constraints. "From scratch" is a bit ambiguous, since one is able to use programming libraries, game engines, and fonts, but the spirit of the event is clear. There's also a "Jam" category, which allows for teams, third-party assets, and an extra 24 hours, but to me that feels like a different, concurrent event. There's nothing wrong with it of course, but Ludum Dare to me means the traditional competition (or "compo").

The theme for LD47 was "Stuck in a Loop," and my eldest son and I both created entries for the compo. Because of family obligations, we only had a little more than 24 hours to work on them. The other boys worked on related projects in Kodu and Construct while we worked on ours. 

The rest of this post is about my LD47 project, Orbital Blast. Follow that link to the LD47 page, or you can also jump right to the HTML5 build (which was built, of course, through continuous integration).

The moment I read the theme announcement, I heard Devo's "Stuck in a Loop" playing in my mind. This put me in a retro mindset that got me thinking immediately about cyan and magenta. This combined with the "loop" idea of Gyruss. In fact, in 2012 for Ludum Dare 25, I made a quick entry called Reverse Gyruss, in which you play the aliens instead of the hero in a game of similar topology. I have fond memories of playing Gyruss on the C64, although it was one of many games I enjoyed; I suspect part of my reverence for the design comes from Raph Koster's including it as a notable evolution of shmup topology in Theory of Fun.

My family went on an after-dinner walk before I could sit down and start working, and we discussed some different interpretations of the theme. I think it was part of this conversation in which my wife asked me if there was something specific I wanted to learn from this jam. My first thought was that there wasn't, but on further reflection, I really did have two goals: one was to explore how object-oriented architecture manifests within Godot Engine, and the other was to implement examples of juice.

Controls

Developing the control of the games was challenging. I tested primarily with keyboard input, which I intend to be the primary input scheme. For most of the game's brief development life, I had a system where left moves the ship clockwise and right moves it counterclockwise. This works well for the ship's starting position at the bottom of the screen, but it gets awkward when maneuvering from the top. Upon further reflection, I could imagine holding a C64 joystick and pushing the stick in the direction where I wanted the ship to be, rather than the relative direction I wanted it to move. I redesigned my input handling logic to use this same approach with keyboard input. I could not puzzle out the geometric problem of determining which way around the circle to move the ship. For example, if the ship is at 9 o'clock, and you give input for 12 o'clock, how do you know which way around the circle to move? This was a case where I had to look up the formula and insert it into my solution.

Supporting touch input cost me quite a bit of attention. I started with keyboard input but, knowing how it easy it was to post an HTML5 build, I also knew that supporting touch would be convenient for players. My first approach—when the input system was based on left and right input—I tried just putting simple, handcrafted buttons on each side of the screen. Unfortunately, Godot does not make it easy to allow more than one button to be pressed at a time. Adding further complication is the problem that testing multitouch input requires me to deploy to the Web and load the game on my phone, so the cycle time is very long. After an hour or so, I decided this was not worth the effort and abandoned touch input... until later, when it had been scratching at the back of my mind and I decided to add it again. This time, I had the Gyruss-style input working for the keyboard, and it seemed natural to allow the player to touch the screen to move toward that point. Indeed, the math here was basically the same as what I already had in place, so it was just input processing. Unfortunately, this still raised the problem of not having an easy way to handle or test multitouch. A nice solution would be to look for a second finger down to fire, but I didn't have time for that, so I switched to an approach where touch (or mouse) input simply keeps the ship firing as quickly as it can.

A Bit of Juice

I was not able to add all of the juice that I wanted. In particular, I was hoping to add camera shakes; I found some great tutorials and it would just be a matter of putting it in, but there are only so many hours in a day. 

What I was able to add was particle effects, which I have never done in Godot Engine before. The built-in particle editor is nice, although it pales in comparison to those I've used in UE4—mostly Cascade and a bit of tinkering with Niagara. The background starfield is handled with particle effects, and of course the explosions are as well.

A related bit of juice is the smooth transitions between the menu screen and the in-game experience. I was so happy with the starfield that I decided I wanted to keep it running continuously through the game experience. Rather than have a separate scene for the main menu, then, I incorporated it, the gameplay, and the game end screens into the single Level scene. This led to a glut of logic within the Level's script, since I had to handle the states and transitions. In fact, now that I think about it, I probably could have saved myself some headaches if I had thought of the main menu at least as a separate scene that could be instantiated into the Level on top of the continuously-running starfield. This ties back to my other goal and the challenge of making a game in roughly 30 clock hours: I didn't take the time to refactor toward good OO architecture since everything is still relatively small, and there's no maintenance plan.

One of the earliest features I added to the game is actually one of the most clever ones—so clever that I kind of forgot about it until my son asked how I did it. I wanted to sell the illusion of depth in a strictly 2D game, and so to do this, I wanted the player's bullet to shrink as it moved toward the middle of the screen, and for the aliens to start out small and get larger as they move outward. Clearly, these two operations are basically the same: scale the actor based on its distance from the origin. I created a custom scene that, when instantiated into a node, would scale that node based on its distance from the center. It's not exactly the decorator pattern instantiation I was hoping for since it has to break encapsulation to manipulate its parent node, but it had the advantage that I could just drop it in to the Alien and PlayerBullet scenes and it worked like a charm.

Music

Perhaps my favorite part of making the game was composing the music. There are two tracks: the menu song and the game theme. Both were broadly inspired by a 1980s Devo sound. I wrote the shorter menu theme first, and originally it ran through the whole game. Saturday night, I was exhausted from working on the project all day, but after a quick game of Quacks of Quedlinburg with my family, I was invigorated to write what became the main game theme. 

I had tinkered with LMMS before, at least enough to know what things I was doing awkwardly. This time, I spent a little time looking at some of the demo projects to get a better handle on how to manage tracks, especially the different drum beats. I also knew that I wanted to keep the song mostly on one note in the bassline. In the main game theme, I did put in what I consider a fun and unexpected cadence It came from a discussion with my friend Andrew Crow, choral director at Ball State University, when I asked him what kinds of chord changes I should be trying to learn to level up my piano improvisation.

For a while, the main theme included a sound like the roar of an overdriven electric guitar, but I replaced that with the more sci-fi pad sound. The last thing I added to the song was the little wood block sounds. I hope that you didn't notice them the first time, but that as you listened you came to love them like I do.

Both of the songs in the game can be downloaded directly from GitHub in Ogg format if you want to give them a listen. Keep in mind that they are designed to loop, so if you just listen straight through they will end abruptly.

Closing Thoughts

Ludum Dare is always a good time. It's a good lesson in humility, to remember that scoping is difficult and expectations must be tempered. The format gives room to explore ideas in keeping with Alan Hazelden's advice that if you can't prototype it quickly, then you should probably work on something else anyway. I imagine the next Ludum Dare will be in the Spring semester, and I hope that my schedule works out so that I can join in again.

No comments:

Post a Comment