Switch Hitter Development Log

Behold as I pretend that I am a game developer.

Previous Page

Sprint #10: "The components of a great sprint."

August 26th, 2018

With a ton of travel and guest-entertaining planned for August, I've been trying not to stress too much over lower productivity during this sprint and last. It's really tough to maintain a work ethic when you're in a different location or when you have a guest in town. It really helps, though, when your host and your guest have just as much interest in a productive day of work as you do. As such, I was able to surprise myself and work two full days while I was in New York City and two full days (along with another half-day) while I had a guest in town back in Seattle. None of the changes I'll be talking about have been released in the prototype yet because I'm still regression testing them but I'll certainly plan on a release after the upcoming sprint.

Experimenting with jump sizing

One of the most important pieces of feedback I've gotten on Ensue so far has been that it's not really obvious when you're triple jumping, nor is it obvious that you're going any higher when you do. This got me thinking about how Super Mario 64--which has been the main inspiration for using the triple jump mechanic in the first place--solved that problem. In that game, if you're only looking at Mario's jump height, it's not necessarily clear that the single, double, and triple jumps differ at all. Instead, the game relies on animation and sound to reveal that something different is going on. Here's a GIF from the Triple Jump page on Super Mario Wiki showing the graphical flair.

As you can see, when the player correctly executes the third jump, Mario is doing somersaults through the air (while shouting "Yahoo!"), which tips off that something different is happening. That GIF isn't a perfect example of this effect because the player isn't using the full height of the single and double jump, which makes the triple jump just obviously look higher, but you get the idea. As for the double jump, although there's a different sound effect used for it, the game doesn't ever really teach the player that it gives Mario a little bit more peak height than the single jump (a tactic that SM64 speedrunners use a ton) and instead chooses to just sort of let the player figure that out as they go. To my recollection, there are hardly any spots in the game that force the player to know about the double jump where they couldn't also reasonably use the triple jump.

In any case, it's been in the back of my mind for a while that I'd like to do something to make things more obvious in Ensue and I think I'd prefer to not have to rely on sound effects--and ideally not just a paragraph of text explaining the mechanic--to do it. Thus far, the approach I've taken is turning the hero a different color whenever he jumps, yellow for a single jump, orange for a double jump, and red for a triple jump.

Generally speaking, however, players don't seem to notice the colors or, at least, don't exactly understand what they mean. That definitely has made me wonder if it's just a little too much on the screen at once and I'd be better served by just turning the hero a different color whenever the third jump is made. Purely graphical solutions feel like what I'm most interested right now but I spent a little bit of time this sprint experimenting with a mechanical alternative: greatly restricting the height of the single jump. That made the single-double-triple sequence look like this.

I haven't yet playtested this with anybody but, to my eyes, it seems a little bit more obvious that you get more height by doing more jumps in a row, especially comparing the third jump to the first. Further, in this setup, I've made the double jump gain a little bit extra height compared to the single, as opposed to the current system that has them peaking at the same height. I'm a little bit wary of making a change like this, though. Besides having to go back and make sure that all of the jumps still work in all of the levels (and, assuredly, they won't), I'm worried that I'll be creating an environment that makes it feel like you constantly have to be triple jumping everywhere. Obviously, to some extent, that's the direction I'm going with Ensue because I don't want it to be an easy game overall but I also don't want it to feel like you just can't do anything until you master the mechanics. It's a delicate balance to strike and one that I'll be looking into a lot more in the coming weeks.

Word of the week: "componentization"

Until this sprint, I've had a pretty concrete distinction that some things are Tiles and some things are Actors. The distinction has mostly been related to answering the question, "Does this thing ever move?" If it doesn't, it's a Tile; if it does, it's an Actor. (Platforms, regretfully, are their own thing. I don't know.) This means that the ball and strike entities that show up in a handful of levels have been treated as Tiles. At some point, though, this was getting to be too restrictive. In my code, a Tile must always be positioned at an x and y coordinate that's a multiple of 32, the base tile height in Ensue, while Actors can exist at any location. What if I want the player to be able to swing his bat and launch a ball (or a strike!) into the air as a projectile?

This led me to try to finally unify the two concepts through componentization, described in excellent detail by Robert Nystrom in Game Programming Patterns. To summarize, everything can be an Entity that has (or doesn't) have certain components: a graphics component if the thing needs to be drawn to the screen, a physics component if the thing needs to exist in the game's physical world, an input component if the thing needs access to the actual input the player is creating, etc. In that sense, everything then just either cares about some combination of those components or doesn't. The hero, for instance, certainly would want to be drawn to the screen, be affected by physics, and have access to the player's input. A decorative bush, however, probably wouldn't care about either physics or input. A cutscene trigger zone might only want access to the collision system so it can tell when the hero has overlapped it.

In practice, I haven't exactly eliminated the concepts of Actors and Tiles because they're still distinctly interested in different systems. I have, however, greatly DRYed out and decoupled the implementations because, now, they're not constantly having to redefine, for instance, how they get drawn to the screen. They just reference one simple method within the graphics component and then the system detects whether they even want to be drawn in the first place. Maybe I want an Actor that doesn't happen to get drawn to the screen or a Tile that doesn't have to permanently exist in one location. I now have much greater flexibility to create those things.

Aoeu

Finally--and I need to apologize in advance because, again, this isn't actually released in the prototype yet; I promise it will be there soon!--I added keyboard mappings for the Dvorak Simplified Keyboard, which is the keyboard layout I've been using for sixteen years now. Yeah, I'm one of those. Also, it's way better.

Closing thoughts

So, even though I spent just about half of my two-week sprint on the road or otherwise occupied with social obligations, I was still able to crank out some major changes that will, hopefully, be big long-term benefits to development. I certainly credit the Pomodoro technique that I wrote at length about last sprint because I feel like it's made my days so much more predictable. Really, just having any type of plan for productivity is a good thing (and I admit that I could just still be in the honeymoon phase with the shiny new process) but it's continued to be great for me.

Next sprint

I'm not sure what I'm going to focus on next sprint but I might go big on redoing the level editor. Right now, the level editor is pretty literally just a <textarea> of JSON that I make changes to when I want to move enemies to different starting positions or whatever. It could definitely be better and it will definitely need to be once I'm in a world in which everything is just an Entity object. I'm very quickly getting to that point, so maybe it's time to invest a little time in the tools. But, you know, maybe I should just make some music and art. Either or.

Sprint #9: "Trying to avoid the expensive meeting."

August 12th, 2018

When a former coworker of mine sensed that a meeting of more than two people crossed the line into not being productive for everybody, he wouldn't hesitate to remind everybody about how expensive meetings can be. If you consider the salaries of five software developers and one project manager, it doesn't take long for the company to be spending thousands of dollars on something that ultimately amounts to wasted time for everybody involved. It's a concept that's stuck with me ever since and feels especially relevant as I've been enduring a bit of a lull with Ensue development. I've spent a good amount of time trying to dissect that lull in my notebook writings that I don't care to regurgitate here (and, yeah, it isn't lost on me that the effort spent trying to figure out why I'm not as productive as I want to be could've been better spent on, you know, actually being productive) but I do want to call out a concept I learned about during this sprint and has, so far, been a huge help for my focus. I'll also go through some video game stuff that I did.

A timely talk

Some people reading this may know who Jason Rohrer is but I imagine most do not. Truth be told, I barely know who he is, having never played any of his games. I first came across him in the bonus footage of the excellent Indie Game: The Movie entitled Indie Game: Life After as he was working on Passage. I encourage you to look into his (extensive) game library but I bring him up because I happened to see a Gamasutra post linking to his GDC 2018 talk, "Don't Break the Chain: Maintaining Productivity on Your 19th Game".

In the talk (which, of course, is highly recommended), Rohrer analyzes his productivity habits by looking at his revision control system. After having somewhat of a mental breakdown while crunching on his newest game (One Hour One Life), during which he was failing to honor time commitments he'd made to his wife and three kids, he was led to the Pomodoro Technique, a time management method created in the '80s by Francesco Cirillo. As a quick synopsis, the Pomodoro recommends breaking your day into working periods into 25 minutes of focus on a particular task followed by a five-minute break that increases to a longer break after the fourth work period. In Rohrer's situation, he realized that two cycles of four working periods meant that he'd be spending 200 focused minutes per day on his game, which he felt was all you could particularly expect of peak performance from anybody. It also made his hours far more predictable, especially when he allowed himself to pursue those typical distractions--Discord, email, web--during the break periods and strictly not during the work periods.

The whole talk really connected with me and there's more to it than just Pomodoro but that concept was certainly my major takeaway. My prior process had been to go to a coffee shop every morning and write in my notebook until I didn't have any more to write, then go home and work until some nebulously defined time. In practice, this often meant starting work after lunch and working until about 5pm (sometimes earlier, sometimes later). When I decided to give Pomodoro a shot this past week, I decided that I'd flip it around: I'd spend two full cycles, broken up by lunch, working on the game (i.e. writing code, composing music, drawing sprites), and one half-cycle writing about what I did, what I will do tomorrow, and any other thoughts I have about things.

I'm only a handful of days into this new process and, in general, people are pretty good at sticking to new things for a short time, but I feel like it's been great for me so far. I commit myself to 200 minutes of focused work, 50 minutes of reflection on that work, and I can usually enjoy a beer while I write, which just feels a lot better than a second or third cup of coffee. I do still need to get better about knowing exactly what I'm going to be working on next (which I think will motivate me to start expanding Storybook's functionality) but so far, so good.

Priority, as dictated by playtesters

I had the opportunity to introduce and watch a couple of people who'd never seen Ensue play through it. It's well documented why this kind of thing is useful--you get to see what's too easy, too hard, the player's expectations, the player's decisions, etc.--but I had a somewhat new experience this time around. For a while, I've noticed that, every so often, the game will throw an error that reads TypeError: actor.state.bat is null and, unfortunately, brings the game to a screeching halt, requiring a refresh. Perhaps stupidly, I didn't consider this bug to be high priority, mainly because I wasn't really sure what was causing it, which made it feel like a very rare case. In observing the new players, though, this bug kept coming up. It's not really worth going in to what the fix was (it was literally a one-character change) but I think it's important to document that, sometimes, it's not even clear that something isn't a rare occurrence until you start seeing it affect other people. So important was this fix that I actually pushed it to production the instant it was done.

Tweaking tiny things

Maybe this isn't really a "tiny" thing but it's always struck me as somewhat unexpected that the hero in Ensue can bounce (and destroy) two enemies at once. Consider the following video.

It's not like it's the worst thing in the world to allow the player to kill two enemies with one set of feet but I've just never really intended for this to be the way that Ensue acts. This wasn't really a pressing issue or anything but it was staring at me in my backlog and I decided to take care of it. This type of encounter now looks like this.

A more robust solution might attempt to make it predictable which enemy you'll be attacking (it seems intuitive for that to be the one that's rendered on top of the other, unlike what happens in that video) but, for now, I think this works well enough.

A platform for creativity

Finally, the most significant thing I worked on during this sprint--taking several days to finish--was a complete genericization of the concept of platforms. Previously, I had six or seven subclasses that would inherit from a Platform class, all implementing slightly different behaviors. For this story, I wanted to put the onus much more heavily on the data to define a platform's behavior, under the assumption that every iteration of a Platform is a combination of a handful of different traits: a) how that platform gets activated; b) how that platform gets deactivated; and c) how that platform moves. Generalizing a platform's movement to be an arbitrarily defined script of coordinates allowed me to realize a feature I've wanted for quite some time: scriptable platforms. Visually, that means I can now have platforms that move like this.

All of the other types of platforms have been preserved in functionality by this one generic class that gives the data much, much more control, which will, hopefully, make it easier think of new ways for platforms to behave. I'll do my best to resist the autoscroller temptation but, I've gotta admit, in getting acquainted with level design to the extent that I have, I'm starting to see why they're so appealing to include in games.

Closing thoughts

All told, the adoption of a new productivity process and finally accomplishing something that's been on my mind for a while (and, at the same time, getting to use the word "genericization" more than anybody else in the world probably ever has), Sprint #9 went well. It seems like the expectation of "only" 25 minutes of focus at a time is much better for me and it's not even clear that I'm getting less done than I otherwise would be. I'm certainly less distracted, which is a big win no matter which way we define productivity. Again, I highly recommend watching that talk from Jason Rohrer, so much so that I'm going to link it again.

Next sprint

The next few weeks are filled with travel for me, starting with a trip to New York City from which I'll drive up to Quebec for a wedding and back to Seattle from which I'll drive up to Vancouver for a fantasy football draft. I've only penciled myself in for an expectation of four full working days during that time but I'll see what I can get done. I think I'm going to try to spend Sprint #10 experimenting with things, mostly tweaks to existing game mechanics that make things behave a little differently, just to see what happens. I should also probably design some more levels.

Next Page