Devlog 2021-04-25

  • Added obstructions to map I drew last week
  • Got bridges working

Bridges

I wanted to talk about a topic that is one of my personal bugbears for any top-down 2d games: bridges. Specifically, bridges where the player can walk on top of, or underneath them.

Traditionally you’ve got essentially two layers of “stuff” – what is behind the player sprite, and what is in front of it. Other things that are on the same layer as the sprite, but are tall (so sometimes the player should be drawn in front of them and sometimes behind them) complicate things a bit, but you can fix that by sorting the sprites by their position and layering them that ways.

When you have a whole section of the map, though, that should be drawn in front of the player sometimes, but not others (e.g. if they approach a bridge from underneath it vs. from on top of it), it’s a whole other issue. The drawing is relatively easy to deal with, KIND OF, but once you have other entities occupying the space, and when you might have events that should trigger when you’re on top of the area but not below it, things get rather complicated!

It may seem like a weird thing to fixate on, but it can allow for more interesting map exploration flows, and it’s always kind of fun to revisit an area you’ve been in but from a different angle. In that sense, it’s like the other “walk around the map stuff” I was writing about a few weeks ago, but it’s a little more subtle since it’s not something the player does specifically, it’s mostly about presentation. In the best case, it’s not really something the player ever thinks about. Of course you can walk under a bridge if there’s ground under it.

VERGE in particular did not handle this well. You were able to modify the renderstring in real time (which allowed you to handle the drawing reordering, sort of) but there was only ever one entity-layer entry; if you reordered the entity drawing it reordered it for ALL entities. If you had any NPCs in the vicinity of the bridge they followed the player’s draw ordering. If you wanted to trigger some zones only if you were over the bridge, you had to manually do checking on things in the zone. It was a pain.

When I built SimpleQuest I knew I wanted this to be a solved problem, in particular because I was using it as a way to build out a framework for RPGs I wanted to use for bigger things, and others might use. I only ended up including one bridge, as a proof of concept, but the functionality was there. None of the code was something I could carry over, but I carried over the principles, and one of them was the way of handling this particular problem.

With the Black Mountain engine, my layers are much more complex than just a single tile map or a list of sprites – in fact, each Map is made up of one or more MapLayer objects. The MapLayer objects contain at least two tilemaps (more, if you want to add them), any arbitrary extra sprites which can sort above or below the tilemaps and entities, a shadow layer, obstructions, and a container for entities, including step event shapes. When checking for triggering events (attached to entities or otherwise) I only check the ones in the player’s current MapLayer entity container; similarly an entity will only collide with obstructions that are in their current MapLayer. Moving between the layers means identifying a good transition area where, when the player passes them, they should go from one layer to the other. The actual move is accomplished by “just” moving the player entity into the other layer’s entity container (it’s a little more complex than just a reparenting, but not much).

Anyway, this all works now. I had been using the MapLayer setup for some time now, so really the work this week was just writing the layer switching code (which, as I said, isn’t that complex). Still, I’m glad it’s done, and I can now continue building maps with the assumption that it’s available.

The player character standing under a bridge, partially hidden by it. The player character standing on top of the same bridge.

See you next week!