Thursday, April 28, 2016

Hammer devlog 17

I did an event flag system this morning. No gif because it's an event flag system: just take my word for it, if you open the chest in the starting room and reload the scene it stays open. Excitement!

Anyway, I had one of those moments while I was doing it: I was lamenting how I couldn't very easily fit all my event flags into one enum, and I was thinking of a way to handle that! I had halfway designed this completely ludicrous solution which would require a custom inspector, and included both an int to cast to the necessary enum and a separate index value that we'd use to look up the enum type to cast to and the parameter in GameStateManager we needed to compare that to.

Basically, it would've been a giant clusterfuck that'd break horribly if you looked at it wrong.

But then I realized that, no, wait, why was I trying to do this?

So I just defined a generic FlagManager type and decided that things would take a reference to that, and I could then extend FlagManager to implement the abstract methods that'd actually do the heavy lifting. You don't need to do some overcomplicated quasi-dynamic type system to figure out which enum this flag should be cast to and what to compare it to - just stick the appropriate FlagManager on the thing, pick the flag from the dropdown, point the thing that needs to look at the flag to the FlagManager.

I spent more time designing and scrapping the ludicrously overcomplicated, look-how-clever-I-am solution to the problem of "event flags" than I did actually implementing the thing that's in place and works. And it's not even ugly or anything? There's a little bit of code repetition that's completely fucking worth it because it lets me Just Say No to dynamic typing, but it's eminently readable in the way that the "smarter" solution I came up with in the first place definitely would not have been.

I do hope the compiler basically inlines the FlagManager object out of existence, though, lol. Since an enum isn't a "real" type - it's just a friendly face for the integral type behind it - it'd be really embarrassing if the result of this design was that I wound up repeating the same tiny section of machine code 20 times and having different things using different repetitions of that code to do their checks for no apparent reason.

[​IMG]

Event flags being a thing means keys can be a thing, so keys are now a thing.

Also: man, I really need to build a fight that's not complete shit sometime soon. Well past the point where that room with the ghosts is useful. 

[​IMG]

WIP minimap and a subregion name popup thing. Subregions are different "areas" within the same scene, so of course the minimap doesn't try to fill cells that exist but aren't part of the current subregion.

Minimap only tracks rooms right now; it doesn't include any support for identifying which rooms you've visited, and it doesn't display connections between map cells. But it does populate automatically based entirely on the layout of rooms in the level and behave nicely with big rooms, so that's cool. Tracking visited rooms is easy enough and I just haven't bothered to implement it yet, but I'm not entirely sure how I want to handle connections. I definitely want this to display that information - but the problem is that (as you can see here!) internally, there's no such thing as a room-to-room connection. Every room is connected to its adjacent rooms; some of them just have collision in the way. I don't want anything as clumsy as a separate array stored with the RoomController that just tracks where to draw connections and whether they're room-to-room or represent fused big room cells, but I might have to do that, really. I could generate connections at runtime from big room cells, but there's nothing reasonably performant I can think of to go over the entire level and immediately check which cells are accessible from which which doesn't leave room for error. And I want to be able to do this within the space of one frame, so - probably am gonna have to suck it up and have rooms specify their connections manually?

Obviously: I really need to optimize the code that handles player world coords updating on big maps. That framerate is pretty gross considering there's nothing else on the map.
 

Monday, April 25, 2016

Hammer devlog 16

[​IMG]

Weapon pickups. Progression!

At the end of this gif, you can also clearly see the new energy regain animation - which is a "fake bullet" that enemies "fire" on death that tracks the player with ludicrous homing properties and heals you on contact whether you're dodging or not. This is a lot more intuitive and nicer-feeling, (Even if you can't really see the graphic against the floor that easily right now...)

Which brings us to the next point: homing bullets. They're in and I've got a neat little setup that gives them a lot of granularity - anything from ludicrous Macross missiles that do hairpin turns in the air to chase their prey to a more subtle aim-assist. I just don't have any visual way to show that off apart from the health whatsit homing right now, sorry!
 
[​IMG]

Overworld textboxes!

With the ability to slice up a block of text of arbitrary length into smaller blocks that can be printed in sequence, and an awareness of where the player is on the screen such that they'll try not to cover that position.

Also, the item pickups now have a textbox and a fanfare and a pose and everything. Which feels a hell of a lot better than "walk into gun to get gun."

Thursday, April 21, 2016

Hammer devlog 15

This isn't action either.

[​IMG]

Implemented a tile priority map system so bullets would behave in a more logical, psuedo-3D manner on big maps with a lot of steps and cliffs and whatnot, like this one. Basically: before a bullet even does its collision checks for the frame, it looks at where it is relative to the priority bounding boxes. If it intersects a lower-priority bounding box, it keeps moving even if there's a scenery collider there, because that collision is "under" it; if it intersects a higher-priority bounding box, it assumes that it hit something whether there's collision there or not.

This is a really silly thing to do in Unity, because Unity is a 3D engine and it could just do the proper 3D collision logic even if it was displaying a bunch of sprites on an orthographic camera, but it's necessary for the aesthetic and gamefeel I'm going for. I don't want to handle this the "right" way, per se - I'm trying to create the illusion of a game running on a much simpler piece of hardware than any this will ever run on. I want bullets with piercing properties to climb "up" walls and hit things on top of them; that sort of thing - at once obviously nonsensical as a representation of physical systems and intuitively correct as the behavior of a fairly primitive 2D environment that fakes 3D logic only to the extent that the GBZ80 and 8 kilobytes of RAM will let it get away with that.

Sometimes, you want to make sure that the wires are visible.

I also made the Demon's Spine's behavior a lot less janky and unpleasant. You can get a feel for what that's good for here.

Also also: your energy regenerates in checkpoint rooms, which is just a quality-of-life thing that lets you ensure you do have enough energy to get around, even if you don't have a firefight to get into.
 

Wednesday, April 20, 2016

Hammer devlog 14

[​IMG]

This is a menu. Weapon select menu is in. It does all appropriate menu things and complies with all standards and regulations. It looks at the weapons you have unlocked, puts a revolving selection of sprites on screen, and tells the weapon manager that your equipped weapon is whatever is in the center slot here.

It also puts some text on the bottom of the screen to tell you what's happening.

That background is kinda hideous, I know, but I can change it!

To be honest, I'm not too stoked about this menu in general; I can see it being a bit of a pain to scroll through a decent-sized list of weapons. But it does what it needs to and conveys the information it needs to, so I can work with this for now, and drop in something nicer down the line if I really want.

Fun fact: there's not actually any of the nice Unity UI stuff happening here, because having Unity handle this in a resolution-agnostic manner would completely break my aesthetic! This is just a bunch of ordinary non-UI sprites doing ordinary non-UI sprite things. I'm already twitching a little bit over the fact that I can't completely eliminate font smoothing and it's introducing intermediate shades of gray that are outside of the 2bpp grayscale palette I'm working with. I'm not entirely certain that I won't wind up rolling my own bitmap font solution at some point.

Saturday, April 9, 2016

Hammer devlog 13

Trying to keep providing updates at a decent clip, even if I don't feel too great about the content in question! But it works, which is what matters at this stage.

[​IMG]

So, this is really shitty - it's not a dynamic fight at all, and the boss should really move to track you with its standard shots - but it's recognizably a boss fight with its own mechanics. Dude sits still and shits bullets until he decides to try to run you down, then covers his ass during the vulnerable period after he finishes those shadow charges by summoning that crazy arrow-rain attack. You need to look at the layout of the projectiles and your screen position quickly to find a safe firing position during that brief window of opportunity.

There are these eye-things on the floor that'll hurt you if you run into them, and they're making the otherwise-optimal corner positions a whole lot less desirable. You can shoot the eyes to destroy them, and they even count as enemies, so they'll refill your energy - but these are the only energy refills in a very dangerous fight, meaning you have to be smart about when to pick them off.

Not shown: if you pick all four eyes off, the boss starts using the horizontal and vertical arrow rains simultaneously, instead of picking a pattern at random. Don't get greedy!

This is, as mentioned, a shitty boss. This is Bed of Chaos levels of shitty boss!

But it's a boss. Which means I can build the furniture of a boss fight around it. The kind of detailed, in-depth design that'd be required to build a good boss fight isn't happening right now because the mechanical fundamentals aren't solid enough yet - anything I do at this stage is a shitty boss, so this is as good as any.

So my immediate priority is getting things in place for some sort of progression now.

The progression in question is: a key should be dropped in the Fuckton of Ghosts Room, which is required to enter the Shitty Boss Room. Beating the Shitty Boss will result in dropping a third weapon.

Some sort of placeholder inventory menu will allow you to equip the third weapon, and that'll resolve an otherwise-intractable obstacle in the snowy room.

Monday, April 4, 2016

Hammer devlog 12

[​IMG]

Dying'll now respawn you at the last checkpoint you activated and reset all the enemies or other volatile objects in the area.

There's an animation bug you can see with one of the enemies respawning here, which I need to track down.

Also, since this test map is fucking nonsense, you respawn on the wrong side of the false wall and get stuck in the collision. It goes without saying that you'd want to use a save flag for a false wall that could be accessed from the wrong side, instead of just resetting it whenever the level is refreshed.

Saturday, April 2, 2016

Hammer devlog 11

Before we can talk about death, and how that's handled, and what that means... I guess we've really gotta take a deeper look at the overall structure of the game, huh? Until now, we've been focused squarely on the moment-to-moment things, but that's only half the story, really.

Okay, so: we're definitely strongly influenced by 2D Zelda games - particularly the Game Boy titles - and the combination of an open, exploratory world structure, action/puzzle dungeon crawls, and light RPG elements. However, we can't just do that. The moment-to-moment demands of a Zelda game are very manageable; it can ask you to perform through the length of an entire dungeon, without a break, and that's fine, because there are relatively few moments when you're really put into a do-or-die position in a given Zelda dungeon. By contrast: every combat encounter here is do or die. If you don't take the enemies seriously, even trash mobs can proceed to kill you with brutal efficiency. And, from another angle: the place where Zelda does have its difficulty is basically irrelevant for Hammer. Our systems don't just make resource conservation irrelevant; they make it impossible. Fire away and keep firing.

Well, let's think some more about what we do want with the Zelda formula: First thing: inventory-driven exploration a la lite-Metroidvania. The various guns you acquire open up new paths and passages. I mentioned a grappling gun as an example, earlier - but it's not just that. A flamethrower can melt the ice blocking off a cavern entrance; a grenade launcher can just blow up cracked rock walls; a flying drone can adjust its path based on your cursor as it moves, following paths no conventional projectile could. Each gun you acquire opens up new possibilities, and not just in combat - but as a tool for moving around and solving puzzles. And the problems these weapons solve can almost always be solved in multiple ways, creating a very satisfying effect where you can sequence break freely if you solve puzzles with the "wrong" weapons. For example - think of the shotgun that's implemented right now. It's something that presents itself as a very conventional, mostly-just-combat sort of tool - but you might be able to abuse its spread firing pattern, and that's encouraged. You might have a scenario where you're intended to position mirrors and prisms to guide a laser beam through a maze so it can strike two switches simultaneously, but if you line yourself up just right and fire the shotgun, it does the same thing without all the hassle. That's good. The starting gun is the only one that should be mandatory. Everything else is just a potential means of solving problems, and the order in which you tackle different sections of the world and how difficult you find them will vary with the tools you happen to have available to you. Adaptability is the name of the game, both on the micro level - within combat, recognizing where you need to be at any given moment and being there, reading the rhythms of battle and feeling what to do at any given time - and on the macro level. You're rewarded for seeking out new tools and thinking of unconventional applications for the ones you have. The "everything is a gun" paradigm amplifies this - exploration and puzzle solving require you to make heavy use of incidental functionality of tools designed for combat first and foremost. It gets you in the right mindset.

What we don't need here: the hard division between "overworld" and "dungeon" spaces. Exploration isn't something that happens in a separate space to the more complex puzzles and combat scenarios - you're continually encouraged to keep your eyes peeled and be willing to change your plans. The "dungeon" spaces wrap around on themselves, intertwining with each other in a very Metroid-y way, and the "overworld" is scattered throughout the map to provide a more natural rhythm for the brief, intense nature of our firefights. Brief "sprints" - frenetic ballets with bullets and mind-bending environmental puzzles - are more naturally punctuated with open, atmospheric and exploratory spaces at a more regular rate than can be provided by adhering rigidly to Zelda's formula.

It's worth considering what Zelda's dungeons do for the overworld exploration, though! They take a situation where the player is just sort of dumped on a sprawling map and give you direction. You have a clear set of goals and at least a rough idea of where you need to be heading off to accomplish them, and that's something we want to preserve.

So, at a broad structural level: Metroidvania-style world plan, heavily interconnected, and mixing short groups of intense, challenge-focused chambers with larger areas that are allowed to be quieter, more restful, focused primarily on pure exploration. Each "main" area is home to one of the game's bosses, and your goal is always explicitly to kill each of these bosses in order to advance to the endgame - but you can choose which order to tackle them in, and you'll generally have to partially explore at least a few different regions before you come face to face with any of the bosses. They exist at the farthest reaches of the world, basically - encouraging the player to explore because "pick a direction, keep walking until you see a president, shoot the president" is a sound gameplan. Guns are distributed throughout the world, some hidden away in secret chambers, others at the end of difficult gauntlets, and some even simply on store shelves - and each of these makes the player stronger by increasing the number of strategies available to them.

Getting around a world like this could be difficult, tedious if done poorly, and the nature of how bosses are distributed requires you to explicitly head for the areas furthest from anything else. So it probably makes sense for fast travel to be a thing, and more specifically, for fast travel to be unlocked for an area by defeating its main boss. Defeat the boss and the nodes throughout become active as fast travel points - you've slain the area's master; you are the area's new master. Fast travel isn't exploitable, since reaching the boss requires you to prove your mettle against the region's themes and gimmicks; getting the right to zip around freely comes as the culmination of a gradual process of getting control over the initially-hostile elements of the region and putting them to work for you, at the moment when the area in question ceases to be somewhere where you have an end-goal and instead becomes a place to move through en route to other destinations and comb over for missed secrets.

These fast travel points are a natural checkpoint system. Highlighting them on the map screen provides a clear set of intermediary goals for the player as they make their way around the world. Travel means combat, and combat is inherently dangerous - intense, stylish, rewarding, but having high execution demands and being very punishing if you can't keep up on either a tactical or a reaction level - so finding these nodes is a key part of constructive safe pathways through the world, whether your destination is the next boss or just that funny-looking rock you think might have a cool gun under it. When you die, you respawn at the last one of these checkpoints you visited. And since these checkpoints are very visible, very obvious, you know exactly where and when you last visited one - so when you wander into a combat scenario, you have to decide whether to push through or to back off and keep exploring. When you're far afield, fighting isn't always the best option - especially if your current tools aren't really suitable for the fight in question.

The only progress loss for death, though, is being returned to the last checkpoint. You don't lose any resources or equipment. You even keep any map cells you've filled in. You just wake up in the last checkpoint room and continue on. You should never feel like your time is being wasted - even if you walk into a room and promptly get your ass handed to you, you're respawned relatively close, and you now know "maybe I shouldn't go in there yet." Easing the metagame around death enables me to get as mean as I want with a clean conscience.

Hammer devlog 10

I think this is an important milestone: this is finally looking somewhat like a video game.

I did another WebGL build.

Click on this and it'll take fucking forever to load, but when it's done, it'll promptly dump you into a firefight. You will probably die. When you die, you'll have to reload the page again because dying is just a softlock.

Move with WASD or arrow keys, double-tap a direction to dodge in it, aim with the cursor, fire the shitty weenie gun with the left mouse button, fire the slow fucking shotgun with the right if you have enough energy remaining. Try to kill all five ghosts. You'll need to put that dodge to work, though, and make good use of the blocks in the corners for cover.

It's still really rough, obviously! But this is the first time since I started this project that I feel like this first proof-of-concept firefight basically works. It's tough, but fair, at least within the bounds of something this early. (Obviously: it's not "fair" by release standards. You start in an exposed position, and they're random enough that if they all do the right thing right when the map loads you're completely fucked.) Reflexes alone won't win it for you, and neither will executing the right tactics poorly - you need situational awareness and adaptability, the ability to quickly form a workable gameplan and then change that as the situation around you changes.

If you kill all five ghosts, you're allowed out of the room. You can then wander around some test rooms, or even take a WIP warp event on one of the staircases to arrive in a room with no collision with the camera controller in an inconsistent state that will basically guarantee anything you do ends in soft and/or hard locks. Excitement!

A design snarl that occurs to me at this time: at a structural level, this is very Zelda, but the moment-to-moment gameplay is much more demanding than Zelda, with death being a very real possibility at any given time. Some time later today I'm gonna hash out how I want to handle death in this thread, because if I handle that "like Zelda" it'll be tedious and unfun. I can't handle death like an arcade shmup, either, of course, because this is a hell of a lot less linear and controlled. So that should be a fun problem to work out!

ALSO: WebGL really isn't my target platform. So, a quick warning - make sure you keep the cursor on the display. If you right click the background, you open a context menu instead of firing, and you're almost certainly dead.

Friday, April 1, 2016

Hammer devlog 09

[​IMG]

On display here: energy bar and big rooms.

Big rooms were actually way more of a pain in the ass than I was anticipating, but whatever: they're in and they work. The scrolling could maybe be a little cleaner, but y'know, whatever. If the most readily apparent issue is purely cosmetic, that's a good day's work in my book.

I also went ahead and beat the tilemap editor into actually working. That's not visible here, but rest assured that it was an integral part of making the copy-pasted Big Room there happen.