Behold as I pretend that I am a game developer.
Here at Rain Delay Games, I impose one-week sprints upon myself. At the end of each one, I'm going to write a post that recaps all of the stories I tried to get to with a little bit about what I learned (or didn't) from the process. With no further ado, here's my first weekly retrospective.
Implementing a controller configuration mechanism was absolutely critical for Ensue going forward. I'm going to be more actively soliciting feedback from people as the game matures and I won't always be doing so in person where I can control the environment and give them a known-working controller. Just posting a link on Reddit or Discord means that testers will be using their own controllers, so they need to be able to, in fact, use their own controllers. Although I specified "D-pad only is okay" in this story, it really isn't: all of the buttons on a controller need to be configurable. Thankfully, it was pretty easy to accomplish this with a primitive mechanism that just asks the player to hold down a button for each action every few seconds. The really killer part of it is that I'm saving the configuration settings into localStorage
so the player doesn't have to do it again (unless they want to). Of course, it's also very valuable to offer a "Reset to Defaults" button in case the player is getting unexpected results.
It would have been nice to implement a more robust solution, especially within the game's user interface (which is just about nil at the moment), but I'm happy with where I got in just a few days. It's also opened my eyes to the idea that I'll want to make some kind of debug report so, if things are acting strange for a player, they can send me some data that will, hopefully, allow me to remotely figure out what's going on.
In a very similar vein to allowing the player to configure their gamepad, I needed to make sure that Ensue could be played with keyboard input. This previously existed, as you might expect. Much earlier on, I was just moving a little square left and right and using the spacebar to jump. Once I found out about the JavaScript Gamepad
API, though--and especially once I found out how quickly it supported my SNES-to-USB adapter--I was heavily prioritizing my development around gamepad support. Eventually, it became clear that the polling-inspired interface that the Gamepad
object is designed around (i.e. you have to ask a Gamepad
object what its state is) is not trivially compatible with the event-based interface that keyboards use (i.e. they tell JavaScript when it needs to care about them). It's actually kind of annoying that there's no abstract Keyboard object that I can just ask the state of whenever I'm interested in it but I suppose somebody could just as easily take issue with the only Gamepad
-related events being gamepadconnected
and gamepaddisconnected
(speaking of which, I should probably support those). In any case, the asymmetry becomes a bit easier to deal with when I specifically tell Ensue that it only has to care about either gamepad or keyboard input, instead of always having to deal with both.
I expected this to be a lot more annoying to do than it ended up being. The final near-term frontier is two fold: a) support QWERTY layouts in addition to Dvorak; b) allow the player to reconfigure the keyboard if they want to. I suppose the final long-term frontier would include testing the game to an extent that everything can be completed by only ever pressing two keys at a time, which is something I'm thinking about because I noticed my keyboard wasn't always willing to register three or four simultaneous keypresses. Although my main vision for Ensue isn't that it will be played with a keyboard, I should be careful not to lose sight of it.
The previous two stories were certainly more essential to getting feedback from others but, let me tell you, this story was the developer's personal favorite. It's been so annoying to have to go into the code or the JavaScript console to change which level I'm currently looking at. I can't imagine how annoying it'd be if I were using a language that, for instance, had to be compiled in order to be run. Anyway, nothing fancy here, just a plain-old drop-down menu, populated manually (which: bleh, it's fine for now), that instantly jumps to a different level whenever one is selected. It's so good.
I wasn't expecting to even get to this story this week, let alone flirt with the concept of contributing what I learned back to the community in the form of an npm package. Pairing the Switch Pro Controller with Windows was trivially easy and both Firefox and Chrome were instantly able to recognize it as a JavaScript Gamepad
. Armed with my new controller configuration mechanism, I quickly tried to use it. That revealed several issues with how I'd implemented the configurator, the main one being that I was essentially assuming that everybody's controller would have exactly eight buttons, the way my SNES controller does. The Switch controller has fourteen (!) so that forced me to generalize things a bit. I knew that analog stick support was unlikely to work out of the box, so it was interesting learning about how that typically gets implemented. To keep it simple, I just set a threshold for the analog values to meet so as to be considered "on" or "off". A more robust implementation, of course, would take into account that analog can be somewhere in between as well. (To be honest, I noticed that Celeste just uses an on/off implementation and that was enough to convince me that I was fine doing the same. We'll see how it fares long-term.) Regardless, in retrospect, I almost should have considered it essential to implement analog stick support for this sprint because many people using controllers are going to be using more modern controllers, not SNES controllers.
In playing around with things, I noticed a bit of a browser incompatibility. Specifically, Firefox doesn't seem to support the Switch Pro Controller D-pad at all. Chrome, on the other hand, supports it but not in the same way that the SNES controller's D-pad works. The basic idea is that horizontal and vertical are exposed as two different fields (axes
in Gamepad
API parlance) and they're either -1
, 0
, or 1
, depending on which directions are pressed. In Chrome's world, though, the entire D-pad is represented by one field that has nine different possible values (up, down, left, right, up-left, up-right, down-left, down-right, and neutral). It's obviously all of the information you need in order to fully support the D-pad but it was still unexpected to see just one number representing its state. Further, the numbers are kind of strange. Up is -1
, which is fine. Up-left is 1
, which, well, at least it's a familiar number. Left, though, is 0.7142857313156128
. Neutral is 1.2857143878936768
. It's definitely not clear whether this the controller is actually intending to output these specific numbers or if it's really outputting another type of data that looks strange when interpreted as a number. The 1
and -1
values lead me to believe the former but I don't really know. I'd like to get my hands on another controller to see if they're the same. I should also probably see how differently the Joy-Con acts.
As a Firefox user, I really only fire up Chrome to test random things and use random sites that, for some stupid reason, don't work right in Firefox (looking at you, check-in-to-your-flight page on the southwest.com mobile site). I was aware that Ensue didn't quite work in Chrome but wasn't actually sure why. The reason ends up being with what Navigator.getGamepads()
returns. In Firefox, it returns an Array
of Gamepad
objects; in Chrome, though, it returns a GamepadList
of Gamepad
objects. This subtlety means that I can't use Navigator.getGamepads().filter()
in Chrome because GamepadList
doesn't implement the filter()
method the way a global Array
does. That's it. All I had to do was just stop using that--and, instead, assume that the player's controller is always the first element of whatever gets returned by Navigator.getGamepads()
--and Chrome worked great. This is just as important as controller configuration and keyboard input because most people out there use Chrome. Now I can actually get their feedback.
After watching my girlfriend playtest a little bit, I decided to add a little indicator to the hero so you can always tell what direction he's facing. I'm not actually sure if it helped the others who playtested the game but I kind of think it was important. It certainly helps reinforce what happens when you execute a wall jump and I think it demystifies what's going on a little. Long-term, this will be rendered obsolete because there'll be actual artwork that shows you the hero's orientation at all times but, for now, in this everything-is-a-box state, it's been a good addition.
Lastly, it feels great that I was able to get a new music possibility tracked in a basic state. I think it's going to work well, logistically, to just afford myself time to work on the music or art whenever I feel inspired to. Certainly it was easier to not have the feeling that I was wasting time after I saw my short-term-critical stories get done pretty quickly.
This sprint was all about getting the input system--the most important system by far--into a state where it could be handed off to others who are willing to give feedback. To say the least, I feel way better about the idea of sending a link around to somebody and expecting that they'll be able to, in fact, play the game. Sprint #1 was definitely a success.
For Sprint #2, I'm going to be focusing on polishing and experimenting with game mechanics. I'll certainly be looking at what can be done about the triple jump and wall jump but I'd also like to examine the glove and bat as well. In playtesting, it was really cool to see how quickly people grasped the glove mechanic (no pun intended) but it's not clear that they really knew what they were doing. Consider me convinced that feedback from others is invaluable.