Top down games have a lot of potential for
adding pseudo 3D, and I love when games do
this, so this week I added bridges that you
can walk over and under as well as a roof
that reveals the interior of a house, and
fixed my TileSet which will save me hundreds
of hours of work when building levels.
Howdy and welcome to Game Endeavor! Where
I post weekly devlogs for my game Zoe and
the Cursed Dreamer.
I’ve always loved when 2D games implemented
depth to them, such as crossing a bridge over
an area that you previously explored. I wanted
to add a bit of depth to my game as well,
so this week I added a layering mechanic that
will allow for this.
To do this, there were a few things that I
needed to consider, such as the layer transition,
rendering, and collisions. I needed this to
work per entity, so I can’t just toggle
the bridge’s collision or adjust its rendering
layer. I started working on the render first,
because at the end of the day when I’m showcasing
my progress, I don’t need my Discord thinking
that I’m a complete failure. And if I can
do these devlogs up until now without adding
collisions to my cliffs, then my bridges don’t
need them either.
To transition between layers, I have a node
that listens for character movement up and
down the ramps. It has two areas, one for
the top and one for the bottom. When a character
exits either shape, then their `set_layer`
method gets called which will adjust things
about them such as their rendering and collisions.
This works for every character in the game
including enemies and pets, so they will be
able to use these bridges as well.
Handling the rendering is pretty straight
forward. I’m just adjusting the z_index
as I need to. If the player is standing on
the ground, then they have a z_index of 0.
If they move up the ramp, they get a z_index
of 10. The value of 10 is arbitrary just to
give myself some breathing room between the
layers, as I’ll mention here shortly about
the bridge.
Godot’s YSort node is used to render other
nodes in a way that you would expect for a
top down game. Nodes with a lower y position
are drawn before nodes with a higher y position.
I mention this because the bridge gave me
a bit of hassle getting it to render how I
wanted it to. This sorting is based on the
position of the node, which is why you may
have noticed that I place my character’s
feet at y position of 0. I do this purely
for sorting reasons. You’re supposed to
place the origin of your sprite at where it
touches the ground. The trouble with the bridge
is that this is at multiple locations.
There’s the point where the front stakes
touch the ground, but also where the rear
stakes touch the ground, and then there’s
actually each individual railing touches the
ground, but I don’t intend to have anything
on the other side of the railings, so I can
actually just render these above and below
the characters and use collision to keep them
from getting too close. The walkable part
of the bridge as well, it can render under
all the characters on this layer, which I
do by lowering its relative z_index by one,
actually putting it on layer 9.
So there’s at least two nodes that need
sorting. The trouble is that for nodes to
sort, they need to be inside of a YSort node.
I usually group everything together into a
typical Node2D. I tried converting this into
a YSort node, but interestingly enough the
YSort doesn’t seem to consider its own layer
when sorting. This actually gave me a bit
of trouble trying to figure out why my bridge
wasn’t sorting correctly when I tried creating
a specific YSort z_index per layer. Instead
I’m probably going to have to set its child
layers via code, it’s only one bridge so
far, so I’ve set this manually. But this
is easily prone to breaking if I don’t automate
it.
But since I can’t use the YSort this way,
I’m instead reparenting the back railing
so that it’s within the YSort node. I don’t
particularly like having to do this, especially
since I’ll need to do this for every complex
node that has multiple ground locations. But
for now this works. Also if I ever need to
remove the object, then I’ll need to remember
to remove the reparented child as well.
An issue that I recently discovered with this
layering technique however is that if two
characters are overlapping each other then
this messes up their y sorting because the
entity that is higher up now gets rendered
over top of the lower entity. Unless you pretend
the skeletons are boosting each other over
the cliff. So I will need to find a way to
get around this. I’ve known about this for
really tall entities, like the tree which
I have the top of rendering higher than everything
else. But this solution won’t work for the
characters.
Now for the fun part: Managing the collisions.
If you’ve used Godot, then you might be
wondering how I disabled the collisions for
these tiles specifically, allowing you to
walk across the bridge. A TileMap only has
one collision_layer for the entire TileMap.
It can not be set individually for each tile.
First let me explain the collision_layer system
real quick. Earlier I mentioned that when
a player runs up a ramp, they have a method
that adjusts their z_index. Well it also adjusts
their collision layer while it’s at it.
In the inspector, Godot will allow you to
assign the first 20 bits to your collision_mask.
But through the code you can assign even more,
so I’m using these extra bits for the layering
system.
If the player has LAYER_BLOCK_1 enabled, then
they can’t pass collisions on that layer,
but they can walk over or under it on a different
layer. This is how the player is able to pass
under the bridge, but they get stuck on it
when they move up to its layer. With LAYER_BLOCK_0,
the ground layer, this prevents them from
walking onto the cliff from below, but allows
them to cross onto the bridge from above.
I still need to set the collision for those
individual tiles however, otherwise the player
could walk off of any cliff face. This is
where the hacks come in. If in my previous
devlog, you thought my use of two tilesets
for my structure walls was bad, then you might
enjoy this. Though I did fix that one by the
way. More on that in a bit.
I’m actually using two TileMaps here again.
But before you get upset, know that it’s
handled automatically at runtime, so I don’t
have to manually do anything. In the engine
itself, I build out the cliffs with one TileMap.
But there’s also an empty TileMap. Other
than the missing tiles, this one is exactly
like the other one in every way.
However, at runtime I set their collision
bits to be different from each other. The
main one has its collision bit set for the
layer that it’s on and the layer above it.
This is so that the player collides with the
cliff while walking into it from below, and
also collides with the cliff to prevent them
from walking over the edge. The empty TileMap
however only has the bit set for the bottom
layer. This allows them to walk onto the bridge.
The bridge scene has some areas on the ends.
The purpose of these is for me to perform
an intersect shape to get the tiles that are
under this bridge. I then use that to unset
these tiles so that the player can pass through
them, and the tileset is set up to respond
when this happens by setting the tiles on
the now not so empty TileMap. So the tiles
get unset, but immediately replaced by the
other TileSet.
This week I also added some major quality
of life improvements to my TileMaps. In my
previous devlog I mentioned how I had separated
my structure walls into two different TileMaps.
This is because the top part of the wall acts
like a typical auto-tile, but the bottom part
only needs to go along the bottoms of the
tops. Which means that it’s taller at some
areas than it is at others, notably the horizontal
walls vs the vertical walls.
However, reddit user golddotasksquestions
posted a link on my reddit post about how
they handle this with only one TileMap. They
do it by using a taller TileMap for everything,
but offsetting the texture and shape so that
they overlap when placed. As you can see from
my tilesheet, I can have the full wall sprites
in here, but I only need a small piece of
the vertical wall sprite because it gets offset
and placed where it needs to be.
This was a mind blowing revelation for me.
For some reason I had never considered using
a different sized TileSet than my TileMap
size. This is not even the best part though.
This got me thinking. If I can use offsets
and overlaps to fix this sort of issue, then
I have another more painful issue that I really
needed to fix. That being my cliffs.
Previously, I had been building cliffs by
placing the tops of my cliffs first, and then
going through and manually placing the bottoms.
The trouble with this is my cliffs are not
flush with the tileset. I have a little extra
space for placing shadows underneath them.
This means that the little elbow pieces where
a cliff connects to itself needs to have the
cliff sprite behind it.
The trouble here is that depending on how
much of a y bend I added to my cliff, this
could actually vary. By a lot. I actually
created 12 different bend pieces to make these
connections, and as you can see from this
painful video of me building out the town,
it took a lot of time to place cliffs. So
long that I was seriously dreading building
levels in the future. I thought it was going
to be something that I would just have to
force myself to do. Work through the pain
and boredom.
But the offsetting from the walls got me thinking.
What if I were to offset my cliff textures
horizontally so that they render underneath
the side pieces. I can use the offset trick
to scootch them into place. And it worked!
After having implemented this, I am now able
to build cliffs instantly with the click of
a button.
There was one small issue. Because of the
grass shadow underneath the cliffs. They render
over top of the cliffs. So I had to separate
these into another tilemap and write a tool
script that sets the shadow dynamically through
code underneath the cliff.
But this is such a breakthrough for the game.
I actually enjoy building cliffs now and want
to use them everywhere. I’ve always thought
that cliffs add a lot of aesthetic to a top-down
game and so now I am excited to be able to
use them more going forward.
A bonus from this is that I can also overlay
cliffs over top of other cliffs, giving them
even more depth. I wanted to do this for the
previous devlog, but with the other way of
making cliffs it would’ve been too much
of a hassle to implement. And now I get this
feature for free. This is because the cliff
tiles are taller than the actual tiles they’re
using, so they’re able to overlap the tiles
behind them without messing them up.
There are still some issues though. For example
with my ramps going up to the top of a cliff.
Due to the padding on the base of the cliffs,
they will overlap the ramp, which I have to
fix by raising the z_index of the ramp so
that they render on top. This also means I
need to lower the z_index of the cliffs otherwise
the ramp will render over top of the player.
The issue with this is the YSorting that we
mentioned before. It’s now out of the question
for the cliffs because they need to be on
the same layer as the player. So the player
will be unable to walk behind cliffs. I’m
not too upset by this, and maybe it can be
fixed somehow, but I was hoping to get a little
bit of depth from this.
In my previous devlog I mentioned how I was
going to be doing houses in this game. I want
the player to feel immersed in the world,
so instead of transitioning to a new scene
when they enter a house, the houses will be
built into the level and when the player enters,
the roof will be removed to reveal the interior.
I ran out of time last week to make a graphic
for the roof, so I did it this week instead.
I first drew a thatch roof for a more rustic
feel, but after spending too long trying to
make it look interesting and not noisey, I
gave up and settled for a shingled roof instead.
I may still attempt the thatch again later
for a different roof option, but I think I
prefer this look for now.
Originally I was thinking of doing a retro
inspired transition where the roof is pulled
back from a single position gradually over
time. But when I did this, I wasn’t too
happy with the effect. After discussing it
with my Discord, we decided to skip the fancy
transition for now and go with a more basic
fade. I would like to improve on this later,
but it’s not important enough for me to
get hung up on it at the moment.
I was a little sad though at having made the
reveal shader and not using it, but it still
taught me something that could be useful in
the future. I’m not that experienced with
shaders yet, so any shader knowledge will
be a boon when I start using them to polish
the game. This one in particular will be especially
useful because it’s able to find the world
position of each vertex. I imagine I could
use this to create my own lighting effect
that has that retro feel but with a modern
twist.
I added a blackout over the interior to give
it a little extra pizazz, and this will slowly
fade out as well when the roof does. This
is achieved with a tileset, so that I can
draw it over the various shaped houses. It
was a little tricky though because I need
this to go over the interior of the house,
but also look like it’s behind the walls.
Trouble is the walls are on the same z_index
as the interior, just y sorted. So I had to
draw the tileset so that it looked like it
was tucked underneath the lower walls, but
it actually sits over top of the walls just
under the roof.
I stream here every Tuesday, and this week
we designed some enemies that may be used
in the future. Ideally I try to design at
least three things during each stream, but
I ended up trying and failing to animate one
of the enemies, which took up a bit of time.
The two that we did design were a necromancer
skeleton and a dark spirit that wears a skull
on its head. The big bad of the game is a
necromancer, so expect to see a lot of skeleton
and spirit based enemies when it relates to
the main story quest line.
I found the necromancer skeleton to be an
amusing one, because I don’t think I’ve
ever seen one in a game previously. The thought
of a skeleton raising more skeletons hits
that sweet spot.
This other enemy is one that I’ve had in
my head for quite some time, so it’s nice
to finally get it down into pixels and start
the process for designing it. It’s a ghastly
spirit that quietly sulks about. I tried to
make him look sad which was more difficult
than I anticipated. It’s also not meant
to look blobby, but that’s something I’ll
need to tweak when I sit down to work on it
some more later.
Our Discord community is hosting a beginner
friendly casual game jam, if you’re interested.
You can see the details here. It will start
from August 30th 2020 and run for a week.
I will announce the theme at the start of
the jam, and you’re allowed to use anything
that you are legally licensed to use. In our
community, we tend to focus more on the game
design and how great your game feels to play.
If you join then check out #notification-roles
to get tagged when the jam begins. There’s
a link in the description to the Discord and
I look forward to seeing you there.
