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!

Sprint #17: "Worlds of content."

December 2nd, 2018

A few days off for Thanksgiving meant a short sprint, which, hopefully, means a short post, as well, especially considering that the vast majority of work these two weeks surrounded just gluing levels together and calling them "worlds". I was hoping I hadn't yet provided a screenshot of the title screen but, alas, I've preempted myself for content. Visual learners won't like this post very much.

Just a quick reminder

Before I get too far into this definitely-not-very-long post, it's worth reminding the reader of the goal for Switch Hitter as it stands right now. In January, I'll be going to Awesome Games Done Quick to meet up with a bunch of speedfriends and, while I'm among literally 2,200 people who are interested in video games, I'm hoping to get some good feedback on this project. In order to feel comfortable with what I'm making them play, though, I've created a finish line for myself: three worlds, some notion of music and sound effects, a start screen, and an end screen. If I get all of those things into Switch Hitter, I'll consider it "AGDQ-ready". There was actually a fifth goal as well: an extra world with a bunch of very difficult levels. Given the demographic at AGDQ, I think it'd be a little disappointing if I didn't have some over-the-top challenge to show off. In any case, Sprint #17 was all about finishing the construction of those four worlds.

See for yourself

I could write about all of the various thought processes that went into making these worlds but, I dunno, it's nothing fancy. I've already written a bit about how I decide how "challenging" a level is. For the most part, World 1 has easy levels, World 2 has more moderate levels, World 3 has tough levels, and Hell (the bonus world) has levels that vary from "precise" to "why?". It's better to go play them for yourself (and I've been pretty good about making sure they can all be beaten with keyboard controls this time!).

Final decisions

One of the things about locking down an AGDQ-ready product, though, is having to make decisions regarding the game design that are essentially final. In my case, I've decided that, indeed, the balls-and-strikes health system will not make it to the speedrunning marathon. In fact, I'm also removing the notion that outs have any meaning besides "you have to start over at the beginning of that level". Further along, I have visions that these things could contribute to some sort of "mastery metric" for each level or world (compare to what it means to get "100%" in Yoshi's Island or find all the strawberries and hearts in Celeste) but, for now, I'm just not convinced that they're interesting mechanics and I feel like they confuse and obscure what is actually fun about Switch Hitter: the platforming.

Unfortunately, removing all of that stuff ends up removing the need for the scoreboard, which I was pretty excited about going further with. I think it's for the better, though, because it seemed like people were having trouble grasping how the scoreboard related to the game in the first place. Getting it off the screen just makes things simpler. "Get hit once and you have to start over" is a well established system at this point that I think it comes across without having a HUD of any sort.

An indulgent interlude

It wasn't all just chore and drudgery this sprint, though. I allowed myself a little bit of time to mess around with a musical idea. I ended up tracking it and I think it came out pretty well. It's entirely possible that this is the overworld music I use for the AGDQ release.

Closing thoughts

In making the "end screen" for Switch Hitter (which is nothing special, really, but I'm going to make you earn it to be able to see it), I found myself getting a little emotional. It wasn't necessarily "happiness" or "sadness" but just a quick swell of appreciation while thinking about how much work I've put into this game, how far (or not) it's come in that time, and then envisioning somebody playing it and enjoying it enough to bother getting all the way to that final screen. I guess it made the "finish line" concept a lot more concrete in my mind, which certainly isn't nothing.

Next sprint

The final thing keeping Switch Hitter in obviously-not-ready-for-release purgatory is the lack of music and sound effects. In Sprint #18, I'll be working on that, and I've actually made a promise to myself that there will be no new music composition. I've already got plenty of tracks that I can surely use one of for release. It's far more important to focus on actually building the music/sound system into the game and, in fact, trying to create my sound effects from scratch. I have no clue how that's going to go, though, so I'm also prepared to hit up Freesound if it comes to it. Two weeks from now, I hope to have something of a "release candidate" to show off.

Next Page