Since our last post, there were a lot of concurrent systems that got resolved that came together to form what felt like some of the most productive months in a while! On top of that, we have quite a few animations to show off — mostly centered around the Reptile. Without further ado, let’s get into it!
Reptile
The Reptile is another one of our soldier
enemies. The Reptile has very fast, unpredictable movement. Tony Wojnar has really captured the chaotic nature of this guy and it has been fun seeing it come to life.
Walking / Running Weapon Animations
The next major addition from our art department is walking / running weapon animations. Actually, this was a joint effort between programming and art! Currently there are 12 different types of walking animations for each soldier
enemy, as well as our hero. Plus, each of the aforementioned have four run animations and four stand frames. Multiply this for each weapon type and the number of unique animations would spiral out of control real fast. We ended up coming up with an idea where each weapon, for each direction, has a couple of reusable still frames to choose from. Then, programmatically, we specify the exact frame and position for our enemies / hero. We save on the number of assets, but we do have to tediously figure this out by hand. Luckily, this is the type of work I like to do on vacation during travel / downtime, so this worked out perfectly. Tony concepted out a few of these, so below are what we’d see in game programmatically:
We did run into a problem though. One of the big things we’ve been conveying from a gameplay standpoint is the difference between balanced and agile / heavy weapons is the fact that balanced are one-handed weapons (that can be used with a shield) and agile / heavy weapons are two handed weapons (that cannot be used with a shield). Unfortunately all of our current walking animations assumed one-handed animations. We tried to “cheat” with an example animation below:
However, it didn’t quiet feel right. We ended up resolving this by adding two-handed stand, walk and run animations. Luckily we could reuse a lot of the base animations and change the positions of the hands to make holding a two-handed weapon work. Below are a few examples of all of this coming together (again, positioning programmatically, these are just references):
Other Notable Updates
As mentioned at the beginning of the post, we’ve made a lot of progress / resolved a lot of work on concurrent systems that have been in development for several months now. The biggest of which was the layerDepth
system. The layerDepth
system was introduced back in 2019 when we added bridges. The simplest way to convey this system is if we are standing on a bridge, layerDepth
is most likely 1
, and if we are supposed to be under the bridge, layerDepth
is most likely 0
. As mentioned in the linked post back as early as 2019, this system worked well for the hero, but applying this to all objects ended up reworking a lot.
Now, we didn’t just work on this system for three years (which we hope is obvious by the other posts on our blog 🙂 ), but integrating with all of the other systems took a bit of work. Not only that, but when we discovered that the collision system we built originally was not going to handle layerDepth
very optimally, we decided to update other systems (e.g. which is one of the reasons the Tile Object
was introduced, to help speed up the collision system). We’ve been talking on an off about all of these systems for a while now, but the final frontier was making all of this work with enemies, weapons, and other interactable objects.
Some interactable objects were pretty easy to update while others (like our soldier
enemy) were a bit more involved. For example, we had to update the path finding algorithm to account for different layerDepth
s. This took a bit of reworking, especially around the transitions areas, which we called rampTile
. RampTile
s used to be single individual tiles, but we ended up merging that with our Tile Object
system for optimizations. As a reminder, RampTile
s are essentially the triggers for switching an object’s layerDepth
. So, for an enemy to find a point in a different layerDepth
, the enemy first needs to find the nearest ramp to toggle the enemy’s layerDepth
, then the enemy needs to find the best path to that ramp, and finally, the enemy needs to compute the best path to the target. Whew!
That was a more complicated interaction to figure out. Below are a few other interactions we had to update and fix to make the layerDepth
system work:
- Updating an enemy’s “seeing” and “hearing” logic (i.e. enemies can normally see targets in different
layerDepth
, unless the target is under a bridge, for example) - Determining how collisions should behave with different
layerDepth
s / trigger points /RampTile
s - Updating the
Renderable
system to draw objects correctly - Updating the
Buildingable
system to determine whether an enemy is inside / outside and accounting itslayerDepth
- If an enemy / hero is using a weapon or holding something, determining how that interaction accounts for
layerDepth
, as well as interacting with theBuildingable
system
These bullet points are not an exhaustive list either! As you can see, there were A LOT of complicated systems converging! Of course, we’re now play testing the game again and encountering some bugs / edge cases / minor issues (which is normal with a system as complex as this). However, we’re extremely proud of how well it all came together!
Finally, here’s a list of some other important updates we’ve completed:
- Sound Effects / Pitching
- We are in the beginning stages of updating our old, crusty sound effects with some new ones. With new sound effects came the need to pitch the base sound effect randomly when needed. Therefore, we did two things:
- Figured out how to take Game Maker Studio’s pitch functions and use them with industry terms, such as octaves, semitones and cents.
- Added a string definition (for easier reading, not optimally performance-wise) to indicate how we want to randomize these (e.g.
snd_SlashBalanced: "semitone:-1..1;1"
would take the balanced sound effect and give us three pitches relative to the base, between -1 semitone and 1 semitone (0 would be no change, so really giving us two “new” pitches)).
- We are in the beginning stages of updating our old, crusty sound effects with some new ones. With new sound effects came the need to pitch the base sound effect randomly when needed. Therefore, we did two things:
- Transitions of Regions
- As an example, the transitions from the green grasslands to the lower mountains was a pretty hard line. Now we’ve added some softer / smoother transitions into regions. This will be expanded on once all of the art for backgrounds has been finalized, but that will be a long ways out. Below are a couple of screenshots:
- Updated Long Grass Tiles
- We also updated the art for the long grass tiles. Below are a couple of screenshots:
- When cutting the grass tiles, there was no concept of changing the neighbor tiles to visually look correct. This was quite the undertaking to understand how auto-tile systems work. Before we actually understood it, we were hardcoding different values with this cheat-sheet:
- However, we soon recognized a pattern. We’ll try to keep this brief and simple, but it does deal with binary, so hold on to your seat!
- The first tile from the cheatsheet,
255
in binary is11111111
. This tile has 8 neighbors, because it is a full tile. Each of the1
represent a neighbor. The last tile from the cheatsheet,0
in binary is00000000
. This tile has 0 neighbors, because it is an empty tile. Each of the0
represent a neighbor. - So, for example, if we wanted to represent a tile visually with a left neighbor only,
8
would be that number, and could be represented by0001000
. Here is a visual:
000
1 0
000
- So, if we wanted to represent a tile visually, with a left and right neighbor, visually it would look like:
000
1 1
000
The binary string would be00011000
, which in our normal system would be the number24
.
- The first tile from the cheatsheet,
- We also updated the art for the long grass tiles. Below are a couple of screenshots:
- Projectiles Shot Off Cliffs
- For a while, we’ve had the ability to shoot projectiles / throw objects over cliffs. However, with the introduction of the
z
,zPseudo
, we were trying to figure out how the shadow should be drawn relative to going over a cliff. We spent a couple of weeks playing with different approaches:- When the object landed, continue bouncing / falling off the cliff
- Increasing the
z
when moving over a cliff top and then decreasing by the same amount after moving past another cliff top of the same height
- We ended up settling on keeping everything the same, as the fake
3/4
‘s perspective didn’t seem to make it feel off in anyway. However, we added a new construct that when a projectile lands within the cliff, if something broke from the projectile (i.e. rock breaks and a treasure came out) that this treasure will fall to the bottom of the cliff. That way, these types of things won’t get stuck in the cliffs for the player to never be able to collect.
- For a while, we’ve had the ability to shoot projectiles / throw objects over cliffs. However, with the introduction of the