Switch Hitter Development Log

Behold as I pretend that I am a game developer.

Sprint #18: "How does this sound?"

December 16th, 2018

Throughout the last six months, I've gotten to indulge my creative side in two realms that I rarely otherwise explore: sound and artwork. Although I do have a bit of a musical background--having grown up playing saxophone and moonlighting as somebody who knows how to play bass guitar--and I'm ever-so-slightly (emphasis on "slightly") familiar with pixel art, sound effects are something that I've never once even attempted to mess around with. When I began this sprint, my only goal was to complete it with a set of passable sound effects to include in a release. I ended up getting a lot more from it.

The [adequate] tool for the [approximate] job

The first thing you have to figure out when you want to create something is the tool(s) you'll be using. For sound effects, I've got to admit that I didn't do a ton of browsing to see what people "usually" use. See, during this development cycle, I've gotten to be pretty familiar with MilkyTracker. Even though it's used and intended primarily for music production, it provides a perfectly decent platform for creating sound effects as well. As long as you can create waveforms and give them envelopes, well, it works pretty much just fine. Essentially, for a given sound effect, I was just creating a one-second-long (or less) song that only played one note of a sample that I created. Generally speaking, these samples were pretty analogous to samples that I've used for instruments in my music. Once I got into a rhythm and had the workflow figured out, it actually felt pretty natural (multiple music puns in that sentence; intended).

I'm going to sort of jump over the sound effect design process because, honestly, it was just a lot of trial, error, and very quick acceptance that, "Yeah, that's fine, whatever, it doesn't have to be perfect." I don't really know what I'm doing--even more than when I usually say that--so I don't know that I can offer much insight. I will, however, make sure to call out this piece by Tomas Pettersson, as well as this one by Oskar Hanberg. Both of them have been extremely helpful as I've been learning more and more about chiptune and, really, sound design in general.

Old techniques for new problems

I was expecting sound effect integration to be somewhat of a pain to implement. I'm not sure why but I guess I was expecting it to be pretty hairy to have certain events trigger certain sound effects at certain times. It ended up being not really much of a problem at all, largely owing to how I've got so much of my game logic implemented around state machines. The JavaScript HTMLAudioElement class makes it about as easy as it possibly could be to load and play a sound effect. The only real subtlety I encountered is that a JS sound effect--at least as far as I can tell--can't have its playback position reset until it's done playing. So, if you're in the middle of playing a sound effect, you can't tell it to go back to the beginning and play itself again until it's gone the whole way through. In most cases, this isn't much of an issue because sound effects are often pretty quick. In Switch Hitter, though, there are times when I make the player do a bunch of pretty rapid-fire wall jumps and I was noticing that a wall jump sound effect would occasionally not get played on account of one having been played too recently. I certainly didn't want to be creating a new sound effect object every time I needed one (in addition to that being a memory hog, don't forget that, on the web, these effects are loaded remotely via HTTP request), so I needed to think of a better solution.

I used object pooling to solve this problem, which is the exact same technique that I used for the smoke trails I (quickly) mentioned in my post for Sprint #16 (I hope to have a much more in-depth write-up about basic visual effect implementation at a later date). The basic idea is that every sound effect I need will be represented by an instance of a class that maintains an array of HTMLAudioElement objects. Whenever I need to play that sound effect, the class checks to see if any of those objects are available to be played. If so, it plays the first one it finds; if not, it creates a new one, adds it to the array, and plays it. This way, I only ever have as many instances of a sound effect as I actually need to play concurrently. Realistically, I could probably just hard-code the lengths of these arrays to be, for instance, three and I'd be just fine. Object pooling is much cooler and hipper and less performant, though.

Knowing is half the battle

Even though I very much romanticize the idea that I'm personally creating just about every single thing in Switch Hitter, I do kind of wish I'd known about this one extremely cool tool before I'd already gotten pretty deep into my own sound effects. sfxr is a small program that, starting from very sane defaults, sort of randomly generates basic sound effects for you. It was created by the aforementioned Tomas Pettersson and is really nifty. You just pick which type of sound effect you're interested in (e.g. "Pickup/Coin", "Laser/Shoot", and more) and sfxr will give you a sound that works totally fine. You can also adjust a bunch of dials to refine the way it sounds or just click a button to generate another. It's so useful that Stephen Lavelle (the creator of PuzzleScript) decided to make an extension of it called bfxr. If you're ever in need of some basic video game sound effects that take mere seconds to create, I highly recommend having a look at both of these incredible tools.

Framing the problem

With sound effects implemented and a music track (discussed last sprint) that, to my astonishment, really hasn't gotten old to my ears yet, it's starting to feel like I have a real game to release. When all of the sound effect creation and implemention only took about a week, I suddenly had plenty of time to really focus on polishing Switch Hitter up. The main thing I tackled was the camera. Anybody who's played this game a bit has probably noticed that the camera has a way of jittering when you jump just a little too high. Sometimes it's fine but, usually, the camera needs to just stop moving altogether. I went ahead and implemented that feature: in every level's data, it can specify whether it just wants to the camera to stay still. I also implemented a way for the level data to start the camera out in a specific position. It took several hours of going back through all 108 levels but the camera should feel significantly better, to the point where I hope you pretty much just don't notice it. Just as a general takeaway for a game developer who's reading this: if you ever get to the point where you're implementing a side-scrolling camera into your game, I highly recommend giving yourself a way to set its initial position whenever you change levels or rooms or whatever. I regret not having done that a long time ago.

Hither and dither

In addition to polishing the camera, I decided that I wanted to add a bit more visual flavor to the background art. During Sprint #15, I created what I think is a pretty decent horizontally repeatable background that evokes a baseball field's outfield fence and a set of light stacks. The artwork was more intended for levels that were quite long and, you know, actually needed to tile the background. When I moved to the very-short-level format I'm using as we speak, it seemed like the light stacks were getting in the way, visually speaking, more than they were adding to anything. Although I had a few different colors for the sky, removing the stacks made the resulting art look very plain.

If I wasn't going to have the stacks in there, I wanted there to be more color. I reminded myself how dithering works and opened up the GIMP. After playing around with the gradient tool quite a bit and, frankly, learning ever more ins and outs of GIMP, I eventually came up with some background art that looked much better to me.

At low resolution, it's tough to see the dithering technique so here's a zoomed-in look at how the sky transitions from color to color.

Visual flavor begets more visual flavor, though. Once you feel like you have something, you just want more. I started really noticing all these blank spaces in my levels where I could totally put some light stacks to just fill in the gaps and they wouldn't get in the way. I decided to add a "background offset" feature to the level data so I could arbitrarily place the light stacks wherever I wanted so they wouldn't interfere with play. I think it works to excellent effect. Compare the following before, middle, and after screenshots.

I'm not saying it's perfect but it sure does look better to my eyes. Maybe I'm just weary from having spent so much time looking at this game.

Closing thoughts

So, yeah, this sprint culminated in me deploying what I'm going to call a legitimate release candidate, complete with music, sound effects, better background art, and a lot more overall polish. This sprint's release feels much bigger than last sprint's, even though most of the levels are identical. I know I've said this many times in these posts but I really am feeling like that Switch Hitter is a real game that will be released soon.

Next sprint

I'm going to be pretty actively seeking feedback for the next week so next sprint will be dedicated to actually acting on that feedback, whatever it is. Independent of that, though, I'd like to take a look at adding a real menu system to the game so I don't have to have those dumb, ugly HTML buttons at the top of the page. I'd also like to try adding more of a lead part to the music loop in the game, making it more fully fleshed-out. Mostly, though, I hope to be acting on real feedback from real players who might also be real readers reading this right now. If that's you, please go play and tell me what you think using this neat feedback form!