Collision Refactoring

Fair warning: This is a very programmer-y post. It’s a post about refactoring, the kind that ends with a triumphant, “And everything worked exactly as it did before!” which is perhaps not the most interesting thing to read.

In You Have to Win the Game and Super Win the Game, world geometry is completely static. Anything that can move or change its state is implemented as a separate entity, including enemies, which mostly bounce between walls, and platforms that may move, crumble when stepped on, or pop into existence when bopped from beneath. Everything else is locked in place and may never change. Some tiles may have different effects, for instance spikes can inflict damage and water can change movement physics, but these tiles can never become anything other than what they are.

This limitation is due in part to how world collision is generated. Each time the player enters a room, a static set of collision surfaces is generated for the entire room, as shown below. In order to improve performance, adjacent surfaces are merged, reducing the number of collision elements over which we must iterate each frame. This process is too expensive to repeat frequently, so we do this once at entry time only.

volver_collision_1

In Gunmetal Arcadia, I’ve made a change that will facilitate dynamic environments should I want them (e.g., for destructible walls, etc.). I now generate a small set of collision surfaces as they are needed. As the player moves through the world, we search for collision surfaces only within a box containing the entire path of the traversal. Because this is done on a per-frame basis, we are dealing with very small movements, so these search areas tend to be very small as well. In this case, there is no need to merge adjacent surfaces because the set is already so small, as shown in the example below.

xan_collision_1

xan_collision_2

(Note that I’m representing this with Super Win assets only because I have not yet begun designing sprites for Gunmetal Arcadia. To be clear, this change does not exist in Super Win; that game is bound by static geometry just as You Have to Win was.)

Because collision is generated on the fly every single frame, I now have the option to change the structure of the world at runtime, and the collision should react accordingly.

I have yet to do a proper performance test of the old and new methods, but by a naive FPS test, there is no difference. What this tells me is that collision is probably not my bottleneck in either case. In the event that generating collision surfaces for multiple moving actors every frame becomes prohibitively expensive, I could optimize the process by caching surfaces and invalidating these caches if the world structure changed.

I should mention too that I haven’t actually tried changing the structure of the world at runtime yet. There will be other problems to solve before this can be a real feature, such as updating the renderable mesh, which has also historically been static except for animated elements. This is one step of several on the road to facilitating destructible or otherwise dynamic environments. But for right now, it’s just in a place where old code was replaced with new code, and everything worked exactly as it did before!

Physics and Game Feel

Game feel is, I believe, the single most important aspect of any game, and yet it is often overlooked in favor of visuals, audio, storytelling, and any other number of easily communicated features. As today’s blog is the first to document actual development progress, hopefully that will give you some idea of the importance I place on game feel.

As I mentioned in my first entry, Gunmetal Arcadia is going to be built off the technology that I developed for Super Win the Game. That code gives me a good foundation for doing many of the sorts of things I would need to do in any 2D platformer, and it would be wasteful to write those systems again. Much of it was originally written for You Have to Win the Game, with a few subtle changes made to retain the same game feel for Super Win in the context of a different screen resolution and aspect ratio. But it’s important that Gunmetal Arcadia not be identical to those games in terms of game feel, and with that in mind, I’ve been making some adjustments to movement and jumping physics recently.

The biggest change I’ve made is to the jump height. In Super Win, you can clear three blocks in a single jump (where one block is 16×16 pixels). In Gunmetal Arcadia, I’ve lowered the jump height to just under two blocks, but you also get a small height increase while walking which allows you to clear two blocks. Increasing jump height with lateral speed is a fairly common trope among old school platformers, but it was one that I avoided in the Win the Game series because I felt it was antithetical to the precise platforming those games require.

In reducing the jump height, I also found it necessary to reduce the jump duration by nearly 30% to avoid floatiness. (I’ve blogged in the past about how the constants that govern jump physics can be derived from a number of sources; I prefer to establish height and duration and derive velocity and gravity from these.)

I’ve finally made peace with non-parabolic jumps and implemented higher gravity while falling. This is an old trick dating back at least as far as Super Mario Bros., and it serves a few purposes. It makes the character feel heavier, and it gets you back on the ground faster after you’ve peaked, which is usually what you want. It also has the side effect of reducing the horizontal distance you can jump, which isn’t necessarily good or bad as long as the levels are tuned properly.

In Super Win, there is no momentum except when walking on ice, which is to say, the character’s movement speed normally corresponds 1:1 to the player’s input. Press left and you immediately move left at full speed. Press right and you immediately change directions, regardless of whether you’re on the ground or in the air. In Gunmetal, I’ve added a little bit of momentum to grounded movement and a significant amount while in the air. This reduces the fidelity of movement relative to input, but it gives the character a more tangible, weighty feel.

Lastly, I’ve lowered the maximum walking speed by about 10%. It’s not a significantly noticeable change, but it complements the other changes I’ve made. And though I haven’t yet drawn the player character, it’s highly likely he or she will have a larger sprite and collision box than Super Win‘s Wayfarer, which will affect the character’s perceived speed and weight.

The goal of these changes is to give the player character a better sense of physicality, which is something that I hope to maintain throughout the development of Gunmetal Arcadia. This game is not about precise platforming as Super Win was; it’s about combat and adventuring, and it’s important that the moment-to-moment game feel support that premise. I’m not done tuning it yet; likely I won’t be for a very long time, but I’m confident in the direction I’m headed.

Source Control

I don’t have any real development news this week, as I’ve mostly spent the last few days patching Super Win the Game and preparing non-Steam builds on all platforms in order to sell the game via Humble Widget. As a follow-up to last week’s notes on setting up a source control repository, I thought it might be interesting to talk a little bit about how I structure my projects.

Since 2007, I’ve been developing a game engine that I’ve used for nearly every game I’ve released or prototyped in that time. It was clear from a very early point in development that it would be useful to decouple common, game-agnostic code from any one particular game’s source, but the exact nature of this relationship took a few different forms before I was happy with it. The earliest implementation involved creating projects for various subsystems such as audio and rendering, and building a game on top of these. This was a good first step, but many of the features that I put on the “game” side of the game-engine line turned out to be features that I wanted to reuse; these included windowing, fonts, UI, and so on.

The next step was to create a “base game” project which could sit between the lower-level subsystems and the actual (“derived”) game. This layer would handle the implementation of common features while also deferring to the derived game when specific content were required. A simple example is the construction of the game window: a subsystem project provides the code to create a window; the base game uses this functionality to create and manage the primary game window, and the derived game provides the text for the title of the game that appears on the window’s frame.

I’ve been using this pattern since late 2008, after finishing my first indie game Arc Aether Anomalies. In order to keep the common subsystems and base game current for all derived games, I set them up in their own repository which is then included as an external in the derived game’s own source control path.

The most recent change, and one that I’ve waited an embarrassingly long time to make, was to branch the engine for shipping a game. After I finished You Have to Win the Game and began working on my next game (the untitled and unreleased “Project Vanguard”), I ran into a few problems when I wanted to make some updates to YHtWtG and had to deal with reconciling recent engine changes that had broken that game. My solution for dealing with this problem on Super Win the Game was to create a new branch of the common engine code for shipping Super Win. Changes made to this branch as part of post-launch support work can easily be merged back into the trunk, and should I ever need to bring over future engine work for an update to Super Win, I can integrate those changes on a case-by-case basis.

If I were to start from scratch and do it all over again, I think the one change I would make is to keep everything in one repository, with separate folders for each game and for the common engine code. This is analogous to my current implementation, but there’s really no benefit to keeping each of these in its own repository. That decision was mostly born of my unfamiliarity with SVN years and years ago, and while it hasn’t hurt me, it doesn’t offer any advantages either.

I’m not yet sure what the next week will look like for actual game development, as Real Life Things are encroaching on my schedule currently, but I’ll try to find something good to talk about by then.

First steps

Tonight I’m taking the first steps towards prototyping Gunmetal Arcadia by setting up a new Subversion repository for the game and its editor. These are copied from the current version of Super Win and its editor, as I will be using that game as my starting point, in the same way that You Have to Win the Game served as the starting point for Super Win.

I give all my projects code names. This is something I picked up from my time at Gearbox Software. The thinking goes, if you choose a title in advance (as I’ve done with “Gunmetal Arcadia”), and you start using that name throughout your code, you run the risk of changing that title prior to shipping. If that happens, you’ll either have to rename all your classes and files or end up with a mish-mash of different names. Choosing an unrelated codename that can persist throughout development avoids these problems.

I don’t have a standard convention for my codenames. Typically they’re just words that I think sound cool. Sometimes they’re related to my perception of how a game should feel. Arc Aether Anomalies was “Sublime.” You Have to Win the Game was “Volver.” Super Win the Game was “Valkyrie.” Gunmetal Arcadia is “Xanadu.”