Grab Bag 7

I spent most of last week working on a new shopping interface, but I’m saving that one for Wednesday’s video because it works better in that format. Instead, this week I’ll be looking at a handful of ongoing changes to the game in the context of a shifting schedule. That’s right, it’s Grab Bag Time!


Let’s start with the GIF-able stuff.

GunPreq 2016-02-27 04-00-22-264

I posted this one on Twitter a couple days ago. I had been toying with the concept of homing projectiles for a miniboss in a slightly different context (detailed below), and I thought it would be interesting to see how they worked in a more typical case of aimed shots fired at the player. The big takeaway was that it was frustrating to not be able to destroy them, so I added that option. They can still be a little overwhelming when there’s more than one or two of them on screen, so this is something I’ll have to use sparingly, but it’s a nice unexpected addition to my toolbox.

GunPreq 2016-02-28 00-11-16-239 panoptic

This is the boss of “Basil,” which is the…fooouuurth level, maybe? Maybe the third. Almost certainly one of the wilderness levels, in any case. The concept for this boss was, “How do I make an immobile turret challenging?” My solution was to give it aimed shots, place it out of reach of many attacks, and throw in some additional enemy spawners as a distraction.

GunPreq 2016-02-28 00-08-41-175 gourd grail

This is the miniboss of the same level. It’s a pair of enemies, tentatively titled “Gourd” and “Grail.” Gourd is large and moves quickly but has no ranged attack and is fairly harmless alone, while Grail flies around and fires projectiles at its companion. These projectiles harm Vireo on touch, but they fully heal Gourd if they reach him, so Grail must be dealt with first.

As with most of my minibosses, I’m imagining these guys will make additional appearances later in the game, perhaps in scenarios that alter the dynamic with different environmental hazards and such.

GunPreq 2016-02-28 00-22-26-768 event lock

Hey, remember this room from the vertical slice build? It previously contained another “Parity” who would drop a chest when he died. That wasn’t really what I wanted, but it wasn’t until just a day or two ago that I finally added support for a feature I was intending to showcase here: lock-in rooms.

This is an idea I’ve blatantly lifted from the likes of Wonder Boy in Monster Land. Every door in the background presents an opportunity for risk and reward. Some of these might be item shops, some might be optional platforming challenges to reach some desirable loot, and some of them will lock you in and make you fight monsters. There will be a reward for clearing these rooms proportional to the challenge, but when you’re running low on health or lives, I want there to be some tension in deciding whether it’s worth the risk to see what’s behind a door.

That dynamic is one that I’m especially excited to see take shape in the roguelike Gunmetal Arcadia, once levels are randomized and the contents of a door can’t be learned and known in advance. But for at least a first playthrough, hopefully it will be an interesting and exciting element of Gunmetal Arcadia Zero as well.


newhud

Keen-eyed readers may have spotted some small changes to the HUD this week. I’ve updated the art for subweapons and removed the square brackets around this icon, which in turn cleared up space to expand the money counter to four digits. So let’s talk about that.

When I started laying out the HUD and choosing resource caps, I was looking at Binding of Isaac primarily. Isaac caps money at 99, but that cap is rarely reached. A standard item costs 15 coins by default, and in many runs, that price is high enough to give pause before making a purchase. Coins are few and far between, and it can be tempting to spend them on consumables and recovery items.

That balance works well for Isaac, but unfortunately, it necessarily precludes something that I love about Castlevania games and want to integrate into Gunmetal Arcadia, and that is the notion that everything drops items all the time. In Castlevania, virtually every torch or sconce can be destroyed, and most of these drop money. In Symphony of the Night and its derivatives, these return every time a room is revisited (along with enemies), guaranteeing an endless supply of things to attack. Part of the reason SotN works as well as it does is that it’s fun to simply move through the world, jumping and hitting things, and this feature provides an incentive to do so. And yet it’s not really practical to grind for money by repeatedly reentering rooms and breaking the same torches over and over, because on repeat visits, they will only drop small amounts of ammo or coins worth a single gold. (For comparison, a single potion costs 800 gold.) But the value isn’t what really matters in this case, it’s the experience of hitting something, getting the feedback of seeing it be destroyed and drop an item, and then collecting that item. That’s where the fun is.

All of that is to say that I was having trouble reconciling the desire to drop loot all over the place because I know that’s it’s fun to collect with a relatively low money cap. My solution is to effectively decrease the minimum amount of money I can drop at once. Since we’re dealing with integers and each pickup was already worth only one unit, that means increasing the cap, in this case by two orders of magnitude. In doing so, I decrease the relative value of a single coin and can justify dropping them as frequently as I would like without worrying about unbalancing the game.

A second axis of balancing currency is how I scale things from the start of the game to the end. Going back to the example of Isaac, that game doesn’t scale prices at all over the course of a single run. Items cost 15 coins at the start of the game, and they cost 15 coins at the end of the game. The value of a single coin never changes.

At the other end of the spectrum is…just about every RPG ever made. Prices are only one facet of the ubiquitous rise in numbers throughout RPGs; health bars get longer, armor ratings get higher, and the numbers just keep going up. This is, I suspect, most often a gating mechanism to ensure the player has spent enough time fighting monsters and leveling up before attempting to progress to the next leg of the game, but it also creates an interesting mechanical aesthetic in which, in the best case, the player constantly feels like they’re getting stronger and stronger, even while remaining relatively balanced to everything. (In the worst case, the player never feels like they’re quite strong enough, no matter how big those numbers get. That can be a tough line to walk, and it’s one of many reasons I haven’t pursued experience points and leveling in Gunmetal Arcadia.)

I can say with certainty the balance in Gunmetal Arcadia Zero is going to be closer to Isaac, but I’m not sure it’ll be entirely flat like that. It’s possible I’ll still have enough wiggle room to capture the feeling of escalation that accompanies seeing numbers get bigger. We’ll see.


As always, I’ve been plugging away at new ideas for tunes whenever I have the opportunity. Here’s some of my more recent snippets. None of these are finished, and most of just a single repeating measure, but they could grow into finished pieces by the time at least one of these games ships.


That’s it for this week! Let’s take a look at what’s coming up…

Upcoming tasks for the week of February 29, 2016:

  • Monday: Create “Cilantro” boss
  • Tuesday: Create “Cilantro” midboss
  • Wednesday: Create “Mint” boss
  • Thursday: Create “Mint” midboss
  • Friday: Record Ep. 29, write blog, addl. work as time allows
  • Saturday: Create “Fennel” boss
  • Sunday: Create “Fennel” midboss

Yep, it’s gonna be boss city around here for the next week or so. You may also notice I’ve started scheduling tasks for the weekend. I’m in full-on crunch mode and probably going to be working every evening and weekend until launch. I was already on a pretty aggressive schedule for a June release but I have an opportunity to launch a little bit sooner, so I’ve shaved down my task list where I can, and I’ll be putting in extra hours to get as much content as possible into the shipping game.

GDC is only two weeks away! As I mentioned before, I probably won’t have a new blog or video that week (or possibly the next, depending on when scheduled content goes up), but it should be a nice change of pace in between weeks of crunch.

One last note for my Patreon supporters! Please keep an eye out for a very short survey I’ll be posting soon. I’m in the process of finalizing the credits for Gunmetal Arcadia Zero, and I need your responses! If you’ve contributed to my Patreon in the past but are not currently contributing, please get in touch with me by Twitter (@PirateHearts) or email ([email protected]) so I can make sure I get your response as well!

Watermarks

I realized as I was preparing this blog post that I totally forgot to continue my newly proposed habit of posting upcoming tasks for the week last time. For reference, it would’ve been three days of enemies, one of NPCs, and one day for recording and blogging.

So I’ve been doing a lot of work on enemies recently. Most of this has been spriting, and I’ll be talking more in Wednesday’s video about some of the new sprites I’ve drawn and changes I’ve made to older sprites to bring them more in line with where this game’s art style has wound up. But I’ve also been taking a high-level look at my entire rogues gallery and trying to identify any missing pieces that I can address before it’s too late. I still have a week or two scheduled for bosses and midbosses later this month and into February, but I’m quickly approaching the cutoff for new enemy types to make it into Gunmetal Arcadia Zero.

For some time now, I’ve been wanting to implement a burrowing enemy. I sort of knew intuitively that this thing would need to be able to switch between two different states (burrowed and surfaced) and have different functionality in each state, but until this week, I hadn’t really gone through that whole process yet. I guess the next closest thing would be the biped enemy, which has different behaviors depending on whether or not it’s aware of the player, but even that one didn’t change its physical appearance and collision bounds in response to this event.

GunPreq 2016-02-15 15-22-32-825

I already had most of the pieces necessary to make this work, including the option to alter collision bounds depending on the current animation, but the two things I couldn’t do were alter the entity’s idle animation and hurt animation (respectively, the one that plays by default when no other animation is playing and the one that plays when the entity takes damage). Since this state is fundamentally different enough that it wouldn’t make sense to fall back to a generic idle or hurt anim (as the player can when taking damage while crouched despite that change in posture and bounds), I finally had cause to add support for these changes.

Next, I turned my attention to wildlife. Wild animals (and wild elves, who are probably worth discussing in a later blog for their narrative importance) are docile until provoked, at which point they will attack the player just like any other enemy. You can choose to engage them or not, but they may also appear in situations in which they are likely to get caught in the crossfire between the player and Unmade monsters, potentially introducing another hazard there.

GunPreq 2016-02-17 12-47-29-346

As I mentioned in a recent tweet, I gave wild elves the ability to use the same throwing knives the player can use, with impressively deadly results. This will probably require some tuning, but I’m happy that I was able to reuse content in this way and have it mostly just work.

GunPreq 2016-02-17 15-07-11-907

As of the time of writing, my enemy count (not including bosses) is up to something like 22 or 23. My goal was to have at least 20, my reference points being Castlevania (14), Battle of Olympus (22), Faxanadu (30), and Zelda II (35). I’m planning to have a number of variants of each of these as well, with different palettes, names, projectiles (where applicable), health values, behavior timing, and any other sort of balance tuning I might want to tweak. For a six-level game, that feels pretty jam-packed, and it’s always possible some of these concepts might slip a bit and get pushed back to the roguelike Gunmetal Arcadia, but this should also be the sort of content that’s super fast to produce, so I’m optimistic.

Oh! Here’s a cool thing that almost slipped through the cracks between when I wrote last week’s blog and when it went live. That Saturday, I finally took a stab at a feature I’ve been wanting for as long as these games have existed: boss intros a la Ocarina of Time. These serve two purposes. First, they clearly delineate boss fights as a major event. (By contrast, midboss fights, though functionally similar in terms of locking the player in until the boss is dead, will not utilize these intros.) Second, they offer the chance for just a hint of additional narrative by virtue of describing the boss not only by its name (which will be unique, unlike normal enemies and possibly midbosses), but also by a “class” or “archetype,” as in the of the Cardamom vertical slice boss “Absolved,” whose class is “Lucid Facade.”

GunPreq 2016-02-13 18-23-56-115

One of these days, I’ll probably write up some notes about how and why I’m naming enemies this way; the short version is that I love the names of the angels in Bayonetta and wanted to establish a slightly different take on a similar concept.

Upcoming tasks for the week of February 22, 2016:

  • Monday: NPC/vendor sprites and behavior
  • Tuesday: NPC/vendor sprites and behavior
  • Wednesday: Create “Basil” boss
  • Thursday: Create “Basil” midboss
  • Friday: Record Ep. 28, write blog, addl. work as time allows

Somehow, GDC is only three weeks away! I’m pretty happy with where my talk is; rehearsals are consistently hitting under the 25-minute mark and I’ve smoothed out the transitions between slides, so I’m feeling pretty good about that. Depending on what my schedule looks like and whether I have any additional material to discuss, I may take that week (or the following) off from blog and video updates. In the past, I’ve made an effort to have content scheduled even when I was away from work for some time, but since I’m so far into content production at this point, I may not have anything extra that fits that bill. We’ll see.

Nonlinear

In my continuing efforts to confuse the linear nature of this blog, today I’m documenting the process of fixing a bug that I’ll be showing off in Wednesday’s upcoming video, recorded last Friday. So it goes.

The bug looked like this.

GunPreq 2016-02-12 17-12-37-296

I had seen this bug a handful of times over the last few months, dating back to October when I initially implemented shallow water. I first noticed it when bombs began falling through the world, and I was later able to reproduce it with the player character. But it popped up so rarely (largely due to the absence of water in most of my test maps) that I kept forgetting or choosing to ignore it.

I did finally find a consistent repro, as seen in the GIF above, and that has allowed me to fix the bug. I’ll get to the fix in a bit, but first let’s take a look at what’s happening here.

I fabricated this repro case based on an observation that this tended to occur when the player hit the corner of a solid tile adjacent to water while falling. This didn’t immediately offer any indication of what might be causing the bug, but it did help me find a more consistent repro. As it turned out, the exact situation necessary to reproduce this issue was slightly framerate dependent and involved the player character moving far enough in a single tick to collide against both the surface of the water and the adjacent wall, as shown below.

collision

Once I’d had this realization, I found it even easier to reproduce the bug, and I could begin tracking down exactly why the player fell out of the world when this occurred. To fully explain why this was, I need to start by explaining how some parts of my collision system work.

As I discussed in one of my earliest posts on this blog (and these later ones) the collidable surfaces of the environment are dynamically generated (and then cached and retrieved for better performance) in response to sweep attempts made through the world. I chose to implement this by representing the world’s collision as a single primitive that may be represented by arbitrary geometry depending on the nature of the thing colliding against it. This is unusual in comparison to most other things in the game, which are typically represented by a single box primitive that may be decomposed into its four sides for sweep tests.

When a sweep test collides against something solid (a “blocker” in my engine’s vocabulary), the sweep path is interrupted and possibly redirected based on how the sweeper wants to react. A typical reaction is to slide along the blocking surface until another collision occurs.

When a sweep test collides against something non-solid, things work a little differently. We cache off the result of the collision such that we can react to it, but we do not interrupt the sweep and instead continue testing against everything else in our path.

The world’s dynamic collision primitive is once again highly unusual in that it may consist of both solid (blocking) and non-solid surfaces. Floors and walls that the player can stand on or collide against are solid. Water is non-solid. This dual nature turned out to be a fundamental part of the problem.

If, in a single tick, the player character’s sweep was to pass through both the surface of the water and the adjacent wall, here’s how it would go: First, we would touch the surface of the water. We would react to this appropriately, altering our physical constants to slow our movement. The surface of the water would be flagged as non-solid, so we would continue our traversal. In fact (and this may be an error in and of itself, and certainly something to investigate in any case), we would effectively repeat the last step of the sweep, beginning to end, rather than continuing from the last known point of intersection. We’d test against every primitive in our range, including the world itself, but here’s where the bug was: We’d see that we had a previous collision result against the world, and that that result had been non-solid, and we’d assume therefore that the entire primitive — that is to say, the entire world — were also non-blocking and that it would be redundant to test it further. We’d opt out of any more tests against it (tests which would otherwise have collided against the adjacent wall), and the sweep would continue unhindered. The player character would pass through the wall unobstructed, and we’d never get a collision result saying we had exited the body of water, so the physical constants would remain altered.

If that seems like a complicated mess to digest in written form, I can assure you the code itself does little to elucidate the matter. My collision code has never been pretty, and though I’ve made some attempts to reduce its size by breaking common patterns out into their own functions, game by game it’s grown into a monster stretching across multiple files and projects. My concern as I moved from understanding the bug to fixing it was that I might inadvertantly break other cases without realizing.

In order to minimize the risk of introducing side effects, I tried to alter the program flow only in this one particular case. I added hooks to the core collision system to allow this case to be trapped and handled by other code elsewhere. When checking whether a primitive is redundant by virtue of having previously generated a non-solid collision result, I now allow the primitive itself the chance to forgo this early out if it believes itself to be important. In this way, the world’s dynamic collision primitive can be tested again even when a previous collision occurred against a water surface in the same tick. The other side of this coin, however, is that the primitive must then ensure that it actually does not produce redundant results, as the sweep test could enter an infinite loop if it did. Any time a collision result is generated, it’s compared against previous results if and only if the previous result were one that could have prompted this retest. If a match is found, the redundant result is discarded and the sweep continues as normal.

All said, it took a few hours to find and fix this bug, which isn’t too bad considering its nature. Along the way, I also discovered another bug that I initially thought to be related (and probably was in some fashion, although its fix was simpler). This turned out to be a silly mistake in offsetting collision surfaces relative to tile boundaries, such that the player was reacting to exiting a body of water that they had not previously entered when standing directly over it and jumping.

GunPreq 2016-02-12 16-09-25-968

Fixed that one too. Game quality plus plus.

Nooks and Crannies

The Witness is a really good game and I can’t stop playing it and I think I might have to cancel the Gunmetals Arcadia so I can spend all my time playing The Witness. :V

January was pretty chaotic, as I tried to wedge in every last little feature I needed for vertical slice on top of the content creation tasks I already had scheduled. This month, as I return to a normal development groove, I’m trying to be better about accounting for those sorts of unexpected tasks and bug fixes so that maybe I don’t have to spend every evening and weekend working.

GunPreq 2016-02-05 17-06-57-064

I’ve begun grayboxing a few more levels (“Basil” and “Cilantro,” in keeping with my herbs and spices motif). Having previously finished the “Cardamom” level for vertical slice, I have a better idea of what works and what doesn’t, and I’m looking for ways I can play to my strengths. One of my goals (as I discussed previously in this episode, around the 14-minute mark) has been to develop a sort of verse/chorus dynamic throughout each level, not only in the pacing of tension and release, but also in the direction of travel and the aesthetic design of each location. You can see this in Cardamom, where long horizontal stretches are divided by vertical rooms. There’s a return to the surface following an underground sequence, and this stretch is once again concluded by a downward traversal before the final boss. I don’t necessarily think Cardamom is the best representation of this concept, but hopefully the ideas are coming through in some fashion, and I’m hoping to improve this sort of dynamic with each level I make.

As I’ll discuss more in Wednesday’s video, I’m curious to find a format that works well for the sorts of content creation tasks I’m going to be doing over the next four or five months. Since these are generally going to be same sorts of tasks week after week and not really conducive to the sort of problem-solving blogs I often write, I may start taking a more in-depth look at very specific areas. In addition, I’m also going to start posting my actual schedules for the week here.

Upcoming tasks for the week of February 8, 2016:

  • Monday: Graybox “Mint”
  • Tuesday: Graybox “Fennel”
  • Wednesday: Graybox “Rosemary”
  • Thursday: Implement two new enemy types
  • Friday: Record Let’s Make Gunmetal Arcadia, Episode 26, write next week’s blog, additional features and bug fixes as time allows

“Rosemary” should be an interesting level, as I had already put some time into it prior to vertical slice to get a feel for what grayboxing would actually entail. Barring any surprises, it will be the last level I graybox for Gunmetal Arcadia Zero, and I’m sort of curious to see how it will shape up and where it will fit in the narrative. (As I’ve mentioned before, I’m trying to develop these graybox maps in such a way that they could potentially arranged in any order. In practice, I usually have at least a vague sense of what I’m building, but “Rosemary” is legitimately a wildcard at this point.)

At some point in there, I’m also going to have to figure out how to transition from one level to the next, possibly with the option for Ninja Gaiden-style cutscenes in between and after the final level. That should hopefully be the last obstacle standing in the way of a (very rough) complete playthrough of Gunmetal Arcadia Zero, and I can start to get a sense of the scope of the entire thing, which is going to be crucial as I move into populating and balancing levels.

Oh, in other news, my GDC talk “Building a Better Jump” (a part of the Math for Game Programmers tutorial) was approved this week, so yay that! If you’re attending GDC this year, stop by and watch me try to cram 35 minutes of content into a 25-minute talk! :V

In-Dev Build: Vertical Slice

A wild development build appears! For a few months last summer, I was trying to make weekly builds a thing, but that collided with contract work and planning for events, and it quickly became apparent that there wouldn’t be enough week-on-week changes to warrant that model. Then I introduced Gunmetal Arcadia Zero to the mix and didn’t think about publishing new builds for several months. But at the back of my mind, it’s been something I’ve wanted to return to for a while.

I just completed a vertical slice milestone last week, and that seems like a perfect time to drop a new public playtest build.

vs_announce_1

Download:
Windows: GunPreq.zip (4.20 MB)
Mac: GunPreq.dmg (5.54 MB)
Linux: GunPreq.tar.gz (6.33 MB)

Notes:
If you’ve played a previous build, existing data may no longer be valid. You may wish to delete your saved configuration data and control bindings before , and you may need to manually delete it before you can play this build. You can locate the folder containing this data by opening the console with tilde (~) and entering “path” without the quotes.

High-performance mode:
I’ve recently added an experimental mode to help the game run faster when CRT sim effects are disabled. This mode also disables a number of other visual features, including brightness adjustment and colorblindness simulation/correction. There is not currently a toggle for this option in the game menus, but if you would like to test it, it can be toggled through the console using “set highperfmode true” and “set highperfmode false” without the quotes.

Bugs:
There are probably a lot of bugs in this build, but compatibility across all platforms should hopefully be pretty stable at this point. If the game doesn’t run at all (or gets stuck on a blank screen at startup, etc.), let me know! If you see anything else that looks strange/wrong/broken/whatever, feel free to ping me on it!

vs_announce_2

I can’t say with any certainty whether I’ll be releasing any more public test builds between now and shipping. It’s a good habit to be in, as it forces me to keep the game running on all platforms on a regular basis, but for a game like Gunmetal Arcadia Zero, I risk essentially giving the whole game away for free as it nears completion. I’ll have to strike the right balance there.