Grab Bag 3

I kicked off this week of development with a feature that I’ve been wanting for some time: attachment points. When I brought placeholder assets from Zelda 2 into my editor a few weeks ago, I was able to start testing melee combat feel, but I knew I would need some additional features to accomplish everything I wanted to do.

link_sword

Link’s melee animations have his weapon drawn into them. This means Link can only use this sword, never an axe or a hammer or a lightsaber. In Gunmetal Arcadia, I want to have interchangeable weapons, which means the weapon art asset needs to be decoupled from the player sprite.

link_wo_sword link_sword_only

This introduces a new problem: aligning the weapon sprite with the character’s hand. If my art assets were locked down and I knew they would never change, I could hardcode this offset, but I’m trying to avoid those sorts of quick, dangerous hacks in this game. (Also I have no actual art assets yet.) The right way to tackle this problem is to provide data to position the weapon sprite in the appropriate location regardless of what my sprites and animations look like.

Enter attachment points. This system allows me to specify named points on a sprite which may exist only on one frame, or across an entire animation sequence, or for the entire duration of the sprite. Regardless of the scope of the attachment point, its location may vary per frame, as well. Using this system, I can place an attachment point on Link’s hands for the appropriate frames of the melee animation. At run time, I can look up the location of this point and spawn the weapon sprite at this location. When this frame ends and the attachment point is no longer in scope, the attached weapon sprite is automatically removed.

Compared to Super Win the Game, I’ve been moving away from relying mostly on implementing features in XML markup and towards providing an interface for facilitating features for this game specifically. To that end, I augmented the attachment point editor with a feature for automatically spawning an entity and associating it with the specified attachment point. This allows me to handle combat mechanics almost entirely through the editor and will make it much easier and faster to add new content in the future.

link_attach

As a test, I replaced Link’s sword with a battle axe. Fun times.


A few months ago, I gave a talk at the Dallas Society of Play about the CRT simulation in Super Win the Game. You can find the slides and some source code from this talk here:
http://superwinthegame.com/dsoptalk/

One of these slides mentioned that I had considered an interlacing effect but had rejected it due to its framerate-dependent nature. In giving this talk a second time last month, however, it struck me that I was already using a couple other framerate-dependent effects which can be automatically toggled off or reeled in when vertical sync is disabled. Since then, I’ve had a note to myself to at least give it a try, which I finally did on Friday.

The good news is my plan for implementing the effect worked exactly as I’d imagined. The bad news is it’s a little hard on the eyes. Maybe not too surprising. Nevertheless, it fits within my target Shader Model 2 instruction count overhead, it’s easily tunable, and it adds a fair amount of authentic retro grit, so I’m leaving it in for now.


The last big feature I worked on this week is another one that I’ve been sitting on for a while. I’ve had a note on my whiteboard for a month or two that says simply:

ladders

Ever since I set up the physics for Gunmetal Arcadia, it’s been apparent that vertical traversal will be significantly different than in Super Win. In that game, the jump height is moderately high from the start, and it can be amplified with a double jump and wall jump. By contrast, the jump height in Gunmetal is fairly low and gravity pulls harder on the downswing. There may or may not be powerups to increase jump height or add double jump or wall jump, but it’s clear that in the base case, jumping is not going to be a significant means of reaching higher ground.

Ladders and stairs seemed like the clear choice for diversifying levels by adding some vertical elements without requiring the jump height to be higher than I wanted. The question then was how to implement these. Ladders and stairs (of the NES Castlevania variety) tend to be a little awkward to implement because they add modal gameplay rules. For instance, while climbing on a ladder or stairs, you typically won’t be affected by gravity, you may not be able to attack or perform other standard actions, you’ll play a custom animation that may have some rules of its own, and so on. It represents an odd circumvention of normal gameplay systems, and that makes it a little more difficult to implement and more prone to introducing bugs.

stairs

My original idea was to implement ladders and stairs both in the same way, by placing invisible “mount/dismount” entities at the top and bottom of the path and specifying an animation to be played while traversing this path. I prototyped this implementation but ultimately rejected it for a number of reasons. It felt bad to only be able to mount a ladder from the ground, as opposed to in the air. It made dismounting from the top of a ladder difficult, and it required me to hack in some fixes to prevent the player from falling through the top of a ladder.

In light of those difficulties, I pushed stairs to the backburner and decided to focus on ladders, as they are the more interesting and versatile tool. Rather than using invisible entities to toggle the climbing mode, I added ladder tiles as a new type of world tile. For reference, other world tiles include solid blocks, harmful blocks, shallow ledges, water, and so on. Ladders are now a new kind of tile which the collision code can query and react to. They can be stood on and jumped through just like shallow ledges, but they can also prompt the player character to enter climbing mode when the proper criteria are met.

I’ve looked at a number of examples of ladders in 2D games, from classic NES games to modern platformers and roguelikes. I’m using Faxanadu as my model for how ladder traversal should work in Gunmetal Arcadia. In particular, I’m allowing horizontal movement while attached to a ladder, which allows me to use a string of ladder tiles in a row as “monkey bars” for bridging long gaps.

Grab Bag 2

This has been a productive week, but also a scattered one. It’s difficult to pinpoint any one thing to blog about, as I spent most of the time jumping from one engine or platform task to another. So I guess I’ll just do another “Grab Bag” entry and write a series of mini-blogs about each of these.

As I was revisiting Super Win the Game for an upcoming update, I took the opportunity to make some much-needed improvements to my Mac and Linux build processes. I use Visual Studio on Windows, Code::Blocks with gcc on Linux, and Xcode with Clang on Mac, and each of these has its own quirks. For instance, Code::Blocks requires that libraries be linked in a specific order, while VS and Xcode can sort these out for themselves. (This is presumably a gcc issue and not a Code::Blocks issue specifically, but as I’m using the two together exclusively, it has only presented itself in this particular environment.) C::B also does not automatically re-link the executable when dependent libraries have changed; these libraries must be explicitly specified as external dependencies. Meanwhile, Xcode defaults to producing intermediate content in a jargon-named external path that is difficult to utilize and searching for libraries in paths that are not relative to the current configuration. For the last year, I’ve been working around these quirks in awkward, cumbersome, and often time-consuming ways, and I finally took the time to understand and address these issues. As a result, making iterative builds on Mac and Linux should be a much less painful process on Gunmetal Arcadia than it was for the Win the Game titles.

autocomplete

I made a small but worthwhile improvement to the autocomplete feature of my game console. It will now display any console command that contains the specified text, as opposed to only commands that start with that text. For instance, in the above example, only the first command would have been found previously. Now it finds four other potential matches. I’ve been relying on the console more and more over the course of the last few games for in-game debugging, and as the set of commands grows, this change will be useful for helping me find what I’m looking for without resorting to searching through code.

button_glyphs

I’ve supported Xbox 360 button glyphs in my engine since early 2011, and I added generic numbered glyphs for DirectInput devices for Super Win, but with the recent prevalence of the DualShock 4 as a PC gaming controller, I figured it was high time to add those glyphs as well. Initially, this was only going to be a user setting to allow the player to optionally override the default glyphs at their own discretion, but as I started reading more about USB vendor and product IDs, I realized it would be easy to identify a DualShock controller and default to these glyphs. I also took this opportunity to provide nicer strings for commonly used controllers. By default, the DualShock 4 identifies itself as “Wireless Controller” on a PC. My engine will now recognize the GUID and change this to “Sony DualShock 4” as seen above. I’m a little wary of whether these changes will behave consistently on Mac and Linux due to the way SDL handles device GUIDs, but I can cross that bridge when and if I come to it.

Finally, I did some server backend work to support two separate features that I hope to utilize in Gunmetal Arcadia. The first is a daily challenge mode a la Spelunky. This allows the game to retrieve a random number once per day which may be used to seed a session. This number will be the same for all users on any given day, so players can attempt the same session as their friends.

dailies

The second backend feature is one that I began working on last summer, brought to a more or less finished state, and have been sitting on ever since. It’s sort of an asynchronous multiplayer component that will harness social media to enrich the game experience. The pitch goes, as you play Gunmetal Arcadia, you may trigger events which are tagged in some way as social events. This could be anything from unlocking a new level to opening a rare treasure chest to being killed by the final boss. When this happens, you’ll have the opportunity to post a URL to social media. When your friends visit this URL, they’ll receive a code that they can enter in the game to receive a reward or an optional challenge or whatever else may be appropriate.

As an example of how this could have worked in a previous game, recall the Twitter button from Eldritch. This would launch a web browser and author a tweet telling how the player died. Now imagine that same thing, but it goes on to say, “When I died, I dropped 50 gold pieces. Use code ‘ABC-123-FOO’ to retrieve them!” Now someone else could launch their copy of the game, enter the code ‘ABC-123-FOO,’ and start a session with 50 extra gold pieces.

I’ve left some of the specifics of this system deliberately vague because I want to leave it open to whatever possibilities I may dream up. These will always follow the paradigm of one player’s in-game event creating a code that another player can use to affect their game, but beyond that, it could be just about anything, depending on how ambitious I want to get and how well early playtesters respond to the concept.

Theft

I’ve been playing a bunch of roguelikes recently — as one does when one is making a roguelike — looking for interesting elements to deconstruct and possibly adapt for Gunmetal Arcadia. Today I’ll be talking about shops and shoplifting.

Item shops are a staple of RPG and adventure games, and roguelikes are no exception. The opportunity to exchange currency for new abilities, upgrades, or other resources can offer the player a number of interesting choices. An item shop should present the player with a multitude of potential upgrade paths. In a typical situation, assuming a well-balanced economy, the player should not feel that they can afford everything for sale, as that would not be an interesting choice. There are exceptions, of course; the player may not have collected any money prior to visiting a shop early in the game, or they may choose to amass a fortune before spending anything. But in the general case, we want to feel like we can choose at most one, maybe two of the items available. In essence, we are making a bet based on the information available that these items will improve our chances over the course of the run.

In being presented multiple options, we have a choice to make, but a more subtle benefit is that we have tangible evidence that the remainder of the session could take a different form depending on this choice. This gets to the core of what makes roguelikes appealing to me, and it is vastly preferable to leaving the shape of the session entirely in the hands of the random number generator or hidden knowledge, although those can have their places too.

Seeing items you can’t afford may be frustrating for beginners who want to experiment with every possible option right off the bat, but there are benefits to this experience as well. It offers a glimpse of future opportunities, the proverbial carrot to permadeath’s stick. It also imparts value to the in-game currency. Shiny money pickups may be fun and moderately compelling to collect on their own merits, but if we find that we always have enough cash to buy everything in stock, then these pickups are rendered useless.

That’s my rough baseline for what I would expect an item shop to be, and practically every example I can find meets these goals. Things get more interesting when we look at the interactions involved in the shopping experience and the alternate paths these afford the player. I’ll be looking at a few cases from recent games, not all of them roguelikes, as I home in on the appropriate interface for Gunmetal Arcadia.

theft_spelunky

In Spelunky, shop inventory is present in the world. It can be picked up and carried just like any object in the game. Doing so will prompt the shopkeeper to approach the player, and if the item is carried out of the store, the shopkeeper will become aggressive.

These shops are intuitive and well integrated with the rest of the game. They reuse familiar controls and don’t interrupt gameplay with a modal menu. Using the RB button to purchase items is a little strange insofar as it is also the button used to enter doors, but as these actions can never occur simultaneously, there is little chance of confusion.

This implementation is thoughtful in that it makes accidental theft difficult. The button prompt encourages a purchase, and shoplifting is not clearly made an option. In order to steal an item, the player must choose to deliberately pick it up and carry it outside the shop, ignoring the shopkeeper’s attracted attention.

The player may also choose to kill the shopkeeper, in which case the items will no longer be purchasable but may simply be collected as if they had been encountered outside a shop. Any aggressive action towards the shopkeeper will instantly make him hostile, however, and as all shopkeepers are armed with shotguns, they are dangerous foes. Whether by design or coincidence, it is also easy to accidentally anger shopkeepers, e.g., by detonating bombs near a shop or by allowing a shopkeeper to be injured by another enemy’s attacks.

theft_eldritch

Shops in Eldritch were largely modeled after those in Spelunky. A lone shopkeeper oversees his inventory, which may be bought or stolen. These items do not behave exactly the same as others in the world, however. Ordinarily, items may be collected with a single button press. Within shops, interacting with items will instead launch a modal menu prompting the player to buy or steal the item.

It’s interesting to note that the game pauses while this menu is open, but the interruption is minimal. All shops in Eldritch are placed behind closed doors, so they tend to feel like safe spaces, isolated from the hostile outside environment.

theft_skyrim_2

Although not roguelikes, I want to bring up the Elder Scrolls games because they have an interesting and unusual implementation of shops and shoplifting. Stores are manned by shopkeepers who serve as the interface for making purchases. This is done through a modal menu which does not have an option for theft. What is particularly interesting is that some, but not all, of a store’s inventory is also reflected in the environment. These items can be stolen, and the normal “Take” prompt becomes “Steal,” written in red letters to indicate that it will draw the ire of onlookers.

theft_skyrim_alt

These in-world items are linked to the entries in the shopkeeper’s menu; purchasing an item from the menu will remove its representation from the world if it has one. However, some items in the world do not correspond to menu entries. These may be stolen, but they cannot be legitimately purchased. These tend to be decorative items like cups and plates that serve no functional purpose but still have some small monetary value.

theft_isaac

The Binding of Isaac does not have a shoplifting feature, but it is worth mentioning here because its shops have some other merits that could be relevant to Gunmetal Arcadia. Shops in Isaac are safe spaces. They do not contain enemies, and although a statue is present as a sort of symbolic shopkeeper, it serves little functional purpose. As with all items in Isaac, shop items may be picked up by walking over them. If the player can’t afford the iteam, it simply remains on the ground.

Every shop is found behind a locked door, and the majority of locked doors lead to shops. However, some locked doors lead to a mini-boss fight instead. Therefore, making the decision to spend a key unlocking a door serves as a risk-reward gamble. Pricing also comes into play here. As keys may be rare in the early game and throughout, the decision to unlock a shop is often made based on how much money the player is carrying. Shops will always contain a major item priced at 15 cents, but there is a chance it will be marked down by 50%, so it is sometimes worth entering a shop even without the requisite 15 cents.

New to the Rebirth remake of The Binding of Isaac is a donation box that appears within shops. Money donated to this box persists across sessions (a notable exception to the rule in this game) and can unlock additional features once it has collected enough coins. It can also dispense coins if a bomb is detonated next to it. The offers a little more flexibility in play without completely upending the sense that every run is viable.

theft_superwin

Finally, shopping in my own Super Win the Game occurs entirely within menus, with no ability to steal. I bring this up not because it is particularly interesting or relevant to the discussion of shops and shoplifting, but because, as the technological predecessor to Gunmetal Arcadia, it represents the path of least resistance in what I could choose to implement for that game.

There are things I love about all of these implementations, and it’s easy to imagine that bits and pieces of any of them could find their way into Gunmetal. At the moment, I’m imagining shops to be single-screen rooms branching off from the critical path. I like the idea that every door in the background is a gamble. Maybe it leads to a tech shop with an assortment of shiny implants to make you run faster and jump higher. Or maybe it leads to a pit of dire wyrmvipers that want to eat your face.

For as much as I’ve talked about it here, I don’t yet know for sure whether Gunmetal Arcadia will actually support shoplifting at all. One of my goals with this game is to follow the mantra of “say yes to the player,” and in that regard, it feels like an obvious win. But I suspect whether it makes the cut and what form it takes will depend in large part on how the economy is balanced (i.e., does shoplifting feel worth the risk?), what sort of persistent narrative elements exist (how will the bad karma affect future runs?), and so on.

I should be back to normal development this week, so next week’s blog will probably be a big long technical rant about entity refactoring or somesuch. We’ll see.

Palettes

This week was an exciting one, as a number of systems in progress coalesced and I saw the promise of what Gunmetal Arcadia will become begin to appear.

As I showed in last week’s video, I’ve been getting animations for melee attacks wired up using sprites from Zelda II as placeholder content. I continued working on melee combat this week, adding collision checks and knockback in response to hits. This prompted me to migrate a system of inertia and friction which had previously been roughed out specifically for the player character in Super Win the Game up into the base game engine so that any entity can take advantage of it. In Super Win, the player normally has no inertia; movement is instantaneous and corresponds 1:1 with player input with no ramp-up or ramp-down time. The one exception is for walking on ice, in which case there is a great deal of inertia to make surfaces feel slippery. For Gunmetal Arcadia, I want a slight amount of inertia on normal surfaces, not only for the player character but also for enemies and NPCs. Surfaces can now define a friction scalar relative to a default value, and any entity with a physics component will react to this friction and set its inertia accordingly.

The next big feature I worked on last week is one that’s been cooking in my head for a while, and that is palette swapping. This is a feature I wanted for Super Win, and I did some rudimentary prototyping of it for the NPCs in that game, but I’ve now made it a real first-class feature with editor integration and everything.

The process begins with source art authored as I intend it to appear in the game. In this example, I’m using the Wayfarer sprites from Super Win.

capman_source

This content is drawn using the standard 56-color NES palette with an additional palette entry for transparency.

palette_default

When I load a bitmap into the editor, it is analyzed for validity; it should contain no more than four colors, and one of these should usually be the transparent color. The opaque colors are then sorted by brightness and reassigned indices 0, 16, and 32, which are the top three entries in the leftmost column.

palette_grayscale

The editor then resaves the bitmap with these indices. It will remain in this state all the way until it is loaded into the game.

capman_grayscale

When the bitmap is converted to grayscale, the original color palette is also saved to editor data, where it may be previewed and updated.

Screenshot 2014-12-08 14.10.44

Screenshot 2014-12-08 14.13.46

These changes are also reflected in the entity construction tool.

Screenshot 2014-12-08 14.11.58

editor

When packaging content into a format the game can use, the editor saves the bitmap with the grayscale indices alongside the colors for the palettes specified in editor data.

When the bitmap is loaded into the game at runtime, the palette is altered to swap the grayscale entries (indices 0, 16, and 32) to be pure red, green, and blue colors.

palette_runtime

This allows the sprite shader to isolate each color of the sprite by looking only at the red, green, or blue channel. These components can then be multiplied by the palette colors provided by the editor, and the end result is the recolored sprite as we expect to see it.

capman_shader

output

A couple of notes on this: the grayscale version isn’t actually necessary. I could just as easily alter the palette to include the red, green, and blue entries within the editor so that the bitmap could be used exactly as it is when loaded into the game. However, doing this at runtime is trivially cheap, and leaving the bitmap in a grayscale form makes it easier to view and modify in case I need to go back and make changes to the sprite. Another alternative would be to leave the source art intact and map the original palette indices to new palette indices, but I kind of like altering it because it helps me to think of my source art as not being associated with any one true color palette.

It’s also worth noting that as I am strictly enforcing four color sprites, I could minimize file size by saving the bitmaps as 2-bits-per-pixel, but at the resolution I’m dealing with, reducing file size is a non-issue at this time.

This feature is exciting for a number of reasons. Along with sprite mirroring in shaders and various other changes I’ve been making recently, it represents a better, fuller, more robust implementation of a feature that was hacked into Super Win. It opens the door to a number of cool features that are evocative of retro games: rapid palette swapping to produce a flashing effect when taking damage, altering enemies’ palettes to represent variations on similar archetypes or “champions,” possibly even doing some fullscreen palette swapping trickery to “fade” screens in and out in discrete increments as was often seen on the NES. It may even be the first step on the road to character customization, which is something I wanted to do in Super Win but had to abandon because it was beyond the scope of that game.

The last thing I’ve done this week is to split out the player character entity into separate representations for the side-view action scenes and the top-down overworld map scenes. This was done in the interest of code legibility. This player character implementation began its life in You Have to Win the Game and grew out of control throughout Super Win to incorporate a number of disparate features. By using separate entities to represent these different states, I can manage the code more easily and also avoid some of the hassle associated with keeping a single entity alive throughout transitions to and from the overworld map. In Super Win, the player entity is constructed once when the game launches and destroyed when the game is closed. All changes to the player’s state, from saving and loading games to moving between levels, are represented in that one object. I’m moving away from that pattern in favor of one where the player entity is destroyed and rebuilt with relative frequency and persistent data is maintained external to that entity.

Implicit to this change is the notion that an overworld map will be part of Gunmetal Arcadia, and indeed, that’s something I’ve been considering. I haven’t decided exactly what this will look like; it’s possible I’ll go for more of a “board game” sort of map a la Super Mario Bros. 3, but in any case, I do expect that individual levels will be connected via an overworld map. I’ll figure out exactly what this means as I get deeper into the roguelike design of Gunmetal, but some of the questions that I’ve been pondering are whether to allow backtracking, how many branching paths may appear, whether or not some branches are clearly labeled as easier or harder, and so on.

The next few weeks are going to be spent on some tasks unrelated to Gunmetal Arcadia, so I’m not sure what next week’s blog will look like — it might be a good opportunity to ramble about high-level design a little more as I did last month. Stay tuned!

Contextual Cues

Even in the midst of Turkey Day and Consumerism Weekend, last week managed to be highly productive, so I have a lot of ground to cover in today’s blog.

I kicked off the week with a task to help facilitate these devlogs. As I mentioned in an earlier blog, I keep each of my projects in a separate Subversion repository for legacy reasons. This can make it difficult to review commit logs for the previous week, as I have to check each repository separately. What I really need is a way to view a list of all commits made to all repositories for the entire week, sorted by commit time. So I wrote a script to do exactly that. You can see the output here. This script runs every morning and prints out messages from all commits made in the last week for easy review. As this is publicly visible, it’s also a good reason to step up the quality of my commit messages. “Yurp,” “whatever,” and “this” are probably not terribly useful messages.

I’ve talked a little bit in the past about how visuals can affect game feel. Animation can have a huge impact on how we perceive a player character’s weight and movement. Art can also provide visual cues that subconsciously affect our expectations of how characters should move, and developers can harness this phenomenon in order to better tune game feel.

Way back when I was starting to write the jumping physics code for You Have to Win the Game (code which I’ve continued to improve and reuse to this day), I found that by replacing my placeholder sprite with a picture of Mario from Super Mario Bros., I immediately recognized the failings of my physics settings. My foot speed was too slow, my jump height was too low, and gravity was too light. Of course, my goal was not to recreate Mario’s physics exactly, but these observations helped me move in the right direction.

I recently had an opportunity to exploit this phenomenon again, and to a much greater extent. I’ve been making some big changes to my animation system recently, and I had the realization that I now had all the tools necessary to drop in an existing sprite sheet from a different game, and — fingers crossed — it should just work. I didn’t mention it explicitly, but when I was initially tuning the physics settings for Gunmetal Arcadia a few weeks ago, I was modeling it after Zelda II and The Battle of Olympus. Naturally, I chose to use a Link sprite from Zelda II as my test content. This time, however, instead of a single static image, I could imitate an entire suite of animations.

I haven’t changed any of the physics settings in Gunmetal Arcadia since adding this test content. I haven’t felt the need. A side-by-side comparison will reveal some clear, if subtle, differences between Zelda II and Gunmetal Arcadia, and that’s a good thing; I’m not trying to remake Zelda II here, but I do want to evoke it. This puts me in a really good position to understand other needs beyond physics. Now that I have Link running around in my test map, I have expectations related to melee combat, which is the next big system I’ll be tackling. I’ve been deconstructing the intersection of movement and melee combat in a number of games, not just Zelda II, but also The Battle of Olympus, Faxanadu, Castlevania, and others. There are some interesting subtleties that arise when you look closely at how melee attacks work in conjunction with walking, jumping, crouching, and I want to be sure I capture those subtleties to the best of my ability, maximizing good game feel as well as retro authenticity.

I woke up early Thanksgiving morning with the sudden desire to implement input recording and playback. I’ve had that feature at the back of my mind for a while now, most recently after demoing Super Win the Game. I noticed that the game tended to attract a crowd while it was being played. While it was idling at the title screen, most people would pass it by. This is an old problem and a solved one; arcade games have used attract modes for years for exactly this reason. An attract loop in which the game plays itself for a short time is an easy solution to this problem and is relatively low cost, at least in theory. You load a particular level and provide faked player input to move the character as if they were being controlled by a human player. Where this gets interesting is in making sure it behaves reliably when played back on every machine, as even a small change in the game state can dramatically throw off the rest of the simulation. Fortunately, the confluence of multiple existing systems helped solve many of these problems for me.

About two years ago, I implemented an option for using a fixed delta time for updating the game state in my engine as explained by Glenn Fiedler here. Historically, I’d always used a variable delta time, and this is still the default behavior in my engine, but I recognized that in certain situations, the determinism provided by a fixed delta in desirable. My use case at the time was integrating shots in a bullet hell shooter; I never made that game, but I did get as far as refactoring my entire engine ticking process to allow the game state’s delta time to be fixed.

My input system handles control bindings, which allows me to ignore details about individual input devices and focus on high-level controls as they would appear to the player. Consider the case of polling for input to move the player character. Rather than needing to explicitly query the state of individual arrow keys and joystick axes from game code, my control binding system abstracts these specific devices away so I can just ask, e.g., “Is the ‘move left’ control active?” Additionally, controls may be flagged as relevant to the game simulation or the engine, which affects when and how they are polled.

Having these features at my disposal made input recording a fairly simple process. Rather than having to record the complete input state of every device connected to the PC, I could reduce my data set to the states of the high-level controls defined by the game. I could further reduce the data set by only recording control states when they actually changed, as opposed to every single tick. Finally, I could ensure that the playback would match the recording exactly by dynamically toggling a fixed 60 Hz tick in both cases. (I should note I’m making the assumption here that the initial state is the same for playback.)

Eventually, this will become a real attract mode for Gunmetal Arcadia. There will other problems to solve along the way, including making random level generation and events deterministic (another solved problem, thanks to the Mersenne Twister). Another potential use case, and one that I’m extremely excited about, is the ability to automatically record and upload whole replayable sessions from playtest builds (or Early Access builds, should I choose to go that route). I learned so much and made so many improvements to Super Win the Game just from watching people play it at events, and being able to collect that information from any number of players across the internet would be absolutely awesome.