Shattering scenery

Since I first implemented foreground layers, like the little bits of vegetation that grow on things, there’s been a bug where when a collision layer tile is destroyed, any foreground tile growing off of it stays around, floating in thin air. That’s OK for some tiles, but not others. Here’s a video featuring this bug:

I fixed that bug today, mostly. Now certain foreground tiles are designated as being attached to a collision layer tile, and get destroyed along with them. Take a look:

There’s still a bit more work to do — this only works with foreground tiles that haven’t been rotated and that are located above their attachment point. To handle rotated tiles attached to arbitrary surfaces, so that the vegetation is growing out of the side of rocks, for example, I have to once again wrap my mind around the way that Tiled stores its tile map data. Each tile can be arbitrarily rotated as well as flipped horizontally and vertically. This is reduced internally to a bit field that records mirroring on the X axis, Y axis, and diagonally. It’s still not obvious to me how these three bits correspond to arbitrary rotations and mirroring of tiles, and while figuring it out I found a bug in my earlier tile code. I enabled some debug output with known patterns of tiles to help me figure out what was going on in the data.

Not a cave drawing or art nouveau. Only for debugging purposes.

I should have this working correctly tomorrow. It has already occurred to me that there’s a good chance I could simply design my way around this limitation in the current implementation, and that I shouldn’t let my urge to engineer solutions to problems that might not actually exist. But I also already told that objecting part of me to fuck right off, so I’m committed to a complete solution.

So sick of camera control

I’m ready to take a little break from it. But I wasn’t satisfied until I had a semi-working implementation of transitioning from a horizontal passage to a vertical passage, something that, although rare, the camera system will need to handle. I’m reasonably happy with how things are working now, although I know I’ll end up screwing with it some more. Take a look:

I added a couple debugging indicators to help visualize what the camera direction was up to. The green cross-hair shows the target position for the camera center, which the camera is always moving towards. The red cross-hair shows where the camera system would prefer to place this target if not for constraints imposed by room boundaries. For single-screen-high or single-screen-wide rooms, the area of constraint is a line running down the center of the passage. For larger rectangular rooms, it’s a rectangle in the middle of the room. The camera director is always trying to get the character into the center of the screen when he’s standing still, and to get his future-projected image into the center when he’s in motion.

I have a lot more ideas about the camera, but I’m starting to feel like a crank with this laser-like focus, so it’s time to move on to the next item on my long list of serious issues to fix before the next batch of level design and artwork.

I have a lot to learn about level design

After three nights of trying various approaches, I still wasn’t satisfied with the camera control in my L-shaped room. Here’s a diagram of the issue in its most basic form.

Five years of computer science education, wasted

The red outline represents the camera frame when the character is moving up out of the vertical shaft and walking to the left in the horizontal passage. In order for the camera to not clip the corner of the the room, and therefore inadvertently reveal the contents of the next room, it needs to slide straight up the vertical shaft, then move straight left in the horizontal passage. As it turns out, writing a general algorithm to accomplish this simple feat is, well, fraught. Nothing I had come up with over three nights was doing the trick, and I was beginning to go way off in the weeds, considering maybe doing a heuristic search with A* or something equally intense.

But then I was talking with my friend Jesse about the issue, and he had an interesting thought: maybe I don’t need to worry about corners getting clipped. Just don’t put anything in those corners, so there’s nothing for the camera to give away when it clips them. Honestly, I was kind of taken aback by this suggestion. I was approaching the problem like an engineer, trying to build a correct solution that would work in all cases with no fudging, and that meant handling the case where there was a room butting right up against that other one in the most inconvenient spot. In other words, I was building a system with rigid constraints and figuring out how to design levels around them, rather than designing levels and figuring out how to make them possible technically. It’s the classic programmer’s fallacy, and I walked right into it.

Still, I felt like a sissy for giving up, so I consulted my holy book, Super Metroid. What Would Samus Do in this situation?

No corner issues here

Sure enough, Super Metroid’s map is composed almost entirely of strictly rectangular rooms. The majority are simply one-screen-wide vertical shafts or one-screen-high horizontal passages, taking a cue from the original NES title. In the few places where there are concave corners, they are almost always filled with empty space, avoiding the clipping problem entirely. The above area, Maridia, has the most convex corners in the game, and as you can see they all follow this rule. There’s only a couple places on the map where this principle doesn’t apply, where my camera problem would actually matter, and there the game just, well, cheats. I was actually kind of pissed off to discover this.

A part of me died when I figured this out

This is a pixel-for-pixel screen grab of the game. Notice how the rooms seem to overlap. They do. When you’re standing on the left, in the blue area underneath the monster head, the camera reveals part of where the tan-colored room should be, but all you can see is more of the same dark blue rock that makes up the background. Essentially, the game displays two completely different things for that region of the map, depending on where you’re standing. I guess I shouldn’t be so shocked — call it a tribute to Super Metroid’s excellent map and level design that I had taken it as an article of faith that this sort of thing simply wasn’t done. I have much to learn from the masters.

I played the game for an hour or so, wandering around various parts of the map where I was curious about camera controls. Approaching it as a game creator, I’m noticing all sorts of things I hadn’t before. I’m definitely planning a 100% run with my new-found critical eye and assembling a video analysis about the game’s camera controls, so watch for that in the coming months. Unless that’s already been done, in which case you should just point me to that analysis.

Revisiting room-based camera control yet again

The camera control system is a continually evolving and complicating machine, one I’m positive I’ll keep tweaking right up until the release of the game. At the moment, I’m still trying to come up with ways to resolve relatively fundamental issues, such as something I call “room peeking.” The following video demonstrates the problem:

The empty area the camera briefly pans over as the character turns the vertical corner in that room is part of another room in the map (or could be; it’s just empty space right now). Under no circumstances should you be able to sneak a peek into an adjacent room by walking its perimeter, and the camera needs to enforce that constraint. I have some ideas for making that the case which I’ll be working on later this week. In case this issue isn’t clear, the image below illustrates what I’m talking about. The area on the map to the left of the character’s current position shouldn’t ever be seen, since it’s not part of the current room.

Still my favorite implemented feature

There are some related issues I’m noticing as well, such as the fact that the screen doesn’t divide perfectly into 64-pixel tiles, which means I’ll need some sort of obscuring border around the screen for the PC version (the XBox version should be fine, since TVs cut off the edge of the display anyway). More testing is in order.

Today I had to spend some time paying down some design debt, climbing out of a hole I dug by writing a camera and mapping system without fully understanding the requirements of it. This is the way of all software, and I’m still very much committed to learning game design the hard way. It feels good to have a much cleaner implementation in place now, with better separation of concerns and responsibilities — but it still kind of smarts to spend a whole evening slinging code to end up where I started.

Horizontally opening doors

Maybe you hadn’t noticed, but the doors in vertical passageways were opening up and down, like the doors to horizontal passages. This was bugging me a lot, so I fixed it.

I was planning on a lot more bug fixes on the bus from Seattle to Portland, but it ended up being a lot more difficult place to work than I had imagined. But the new few cycles will be focused on paring down the list of critically annoying problems sitting on my legal pad.

Fine tuning shot placement

You may have noticed in past development videos that bullets didn’t appear to come exactly out of the player’s gun. That’s because I just got it roughly accurate (within half a tile width) and called it good enough. But now that I’m making enemies and environments relatively rapidly, it’s beginning to be important that the height of shots match up to their final production values.

To determine how much the shots needed to be nudged for each character pose, I used the run-time parameter adjustment mechanism I created a few months ago to manually position the bullets as they are created. Here’s what that looks like:

I actually resorted to pen and paper to make notes about how far in the X and Y directions the bullets needed adjusting from their present locations for each pose: standing, kneeling, and jumping / falling. In addition to slowing the bullets way down so I could see what was happening, I paused and advanced the game one frame at a time so that I could observe small details when in motion.

Spraying in all directions

The final result, with the bullets still moving at a snail’s pace, looks like this:

The shots are drawn in front of the player at the moment for ease of testing (and because I’m too lazy to change it), but that’s a simple fix. I still need to tweak the walking, jogging and running animations for their own shot placement, but that’s work for another day.

Get out of the walls, you stupid bug!

Finally able to resume work on the game with help from my good friend Afternoon Caffeine, I tidied up a collision detection problem I was having, illustrated by the video below.

When a block is destroyed in the game, it counts down a timer until it reappears, then asks the game if it’s OK to come back. This amounts to asking whether there’s something else in the world occupying that space, and bailing out if so. It’s incredibly important to answer this question correctly, because the terrain is composed solely of its perimeter edge, and once a game entity falls into the interior of this loop shape it won’t be able to get out.

The issue is that I was trying to keep track of each game entity manually and determine if any of them overlapped a given area of space. This looks something like this:

public static bool EntitiesOverlapping(PolygonShape shape, Transform transform) {
    Manifold manifold = new Manifold();
    foreach ( IGameEntity ent in Instance._entities ) {
        Transform entTransform = IdentityTransform(ent.Position);
        PolygonShape entShape = ent.Shape;
        if ( entShape != null ) {
            Collision.CollidePolygons(ref manifold, shape, ref transform, entShape, ref entTransform);
            if ( manifold.PointCount > 0 ) {
                return true;
            }
        }
    }
    Transform playerTransform = Player.Instance.Transform;
    PolygonShape playerShape = Player.Instance.Shape;
    Collision.CollidePolygons(ref manifold, shape, ref transform, playerShape, ref playerTransform); 
    return manifold.PointCount > 0;
}

There are a couple issue with this approach. One, it’s inefficient when there are a large number of entities nowhere near the target area. Two, it only works with PolygonShapes, and then only if the entity is composed of exactly one of these shapes.

I tried to convert the code to work with axis-aligned bounding boxes (AABBs), but then I was having way too much trouble getting them to match up when the entity’s body was rotated, as happens with the beetle enemies.

If only someone would write some sort of, I don’t know, engine to manage collisions between simulated objects… Oh yeah. This code was old enough that I still was pretty unfamiliar with most of the features of Box2D when I wrote it, and didn’t know enough to let the engine do the heavy lifting for me. This is not only much faster, since Box2D uses quad trees to cull out bodies that aren’t nearby, but is much harder for me to screw up.

public static bool EntitiesOverlapping(AABB aabb) {
    bool overlapping = false;
    Instance._world.QueryAABB(fixture => {
        if ( fixture.GetUserData().IsPlayer || fixture.GetUserData().IsEnemy ||
                fixture.GetUserData().IsProjectile || fixture.GetUserData().IsDoor ) {
            overlapping = true;
            return false;
        }
        return true;
    }, ref aabb);

    return overlapping;
}

AABB collisions aren’t as accurate as polygon collisions, but since the whole point of this exercise is to be conservative with when a block can reappear, it’s just fine.

If you’ve made it this far, enjoy this bonus video from Burning Man!

I am an oathbreaker

When I started working on this game back in June, I swore a blood oath that I wouldn’t cut my beard until it was complete. Like Samson, my wavy locks would be a symbol of my indie dev powers and the proof of my dedication. And if I do say so myself, the beard I grew was pretty magnificent.

That beard is a national treasure.

But here’s the thing: when I made my pact with my beard, I was actually naive and optimistic enough to believe I would be able to create the entire game in three months. In a way, I’m glad I was so adorably cavalier about my ability to complete a giant project in a language I’d never written, in a framework I’d never used, with a skill set I had to build from scratch. Without that naivete, I might have thought twice about committing to a project this large, and self-doubt is the only really deadly poison a creator can swallow.

Easier than it looks, but not for the weak of heart.

This is all a long-winded way of saying: I didn’t think the duration of this beard oath through. And seriously, it was starting to become a disaster. Ever tried to keep a giant beard clean while eating peanut butter pancakes smothered in syrup every morning for a week in a place with no running water? It’s a trainwreck of epic and gooey proportions. And besides the hygienic issues, the beard didn’t exactly scream “software professional.” Even after trying to tame it with the most luxuriant beard oil money can buy, it was a still a wiry mess poking out of my face at whatever angle it felt like. It’s true that you can have a bird’s nest of a beard as a software developer, but the bigger the beard, the smarter you have to be in order to be taken seriously despite it. I was at least a half-inch over that threshold.

Knowing that I couldn’t possibly hold out for the year or so it’s going to actually take me to finish the game, I decided to cut my losses early and went in today for my first ever professional beard trim. The stylist did an admirable job, and my beard feels much more like a long-term sustainable project.

Anyway: I’m back from Burning Man, ready to start development once again. I had a great time and saw a ton of amazing interactive artwork, like this giant representation of the Mayan calendar:

I also plied my skills on the unicycle to take part in a parade, which ended up as a death match at the Thunderdome. Two wheels enter, one wheel leaves.

I’m excited to get back to work on the game, and should have some weighty updates in the near future.