Minotaur Updates

These past couple months have seen many art updates, font cleanup, stability fixes and performance increases.  We’re excited to showcase the highlights below.

Minotaur

At the beginning of 2023, we began coming up with a few designs for the newest member of the Soldier enemies, the Minotaur.  Tony, as always, comes up with several great designs that we then have to decide which fits best with the game, story, etc.  Below are a few of the initial designs:

Minotaur Design 1
Minotaur Design 1

 

Minotaur Design 2
Minotaur Design 2

 

Minotaur Design 3
Minotaur Design 3

 

Minotaur Design 4
Minotaur Design 4

Without going into all of our rationale, we decided to go with the head of the second design and the body of the first design.  This yielded the fifth design:

Minotaur Design 5
Minotaur Design 5

After some further tweaking, we ended up with our final design:

Minotaur
Minotaur

The Minotaur has more HP and strength compared to the Orc and the Reptile.  To illustrate this from a gameplay perspective, we decided to make the Minotaur significantly larger.  We originally went with 1.5 times larger, but that seemed a bit large comparatively.  We also tried 1.25 times larger, but that seemed a bit small.  Therefore, at about 1.33 times, the Minotaur stands tall at 42 pixels (our hero is 32 pixels for reference (~5’9″)).  We also wanted to showcase the strength with its intimidating walk cycle, as shown below:

Minotaur Walk Down
Minotaur Walk Down
Minotaur Walk Left
Minotaur Walk Left
Minotaur Walk Up
Minotaur Walk Up

Reptile Updates

December found us finishing up some Reptile animations with the bow and two-handed walk cycle.  However, as we were preparing the Minotaur, we had realized we forgot to do idle animations for the reptile.  Below are those animations:

Reptile Idle Down
Reptile Idle Down
Reptile Idle Left
Reptile Idle Left

Cliff Updates

We also decided to touch up the cliff walls a bit, as well as add a few palette updates for the cliffs in different biomes shown below:

Upper Mountains
Upper Mountains
Snow Mountains
Snow Mountains

Target Updates

We finally decided to give an overhaul to the targeting system, both artistically and functionally.  Functionally, we added a “pause” concept that would only change the targetable enemies every one second, or when the player made a selection.  Even though the computer could calculate accurately which targets were “next”, having them change so rapidly made it really hard for the player to choose.  This delay or pause concept really helps in selecting.

Visually, we added three states:

  1. Light blue bracket — the “next” target if we quickly let go of L-Trigger and press it again
  2. Yellow bracket — the current target we are locked on to
  3. Directional arrows — if we press the R-Stick in the direction of the arrow, that enemy will become the “next” target

Below is an illustration of what this looks like:

Orc Fight
Orc Fight

You may have also noticed in the above screenshots that we moved the HUD elements.  We haven’t officially decided if we like this, but moving these elements to the corners of the screen really helps with the vertical screen real-estate.

Font Updates

You might have noticed in the above screenshots that the font is much different than before.  We overhauled the font systems and used / touched up some elegant pixel art fonts, as showcased below:

Updated Font
Updated Font
Updated Font
Updated Font

Other Notable Updates

Path Finding Part Two

In our previous post, we explained our problems with the path finding / grid system native to Game Maker and our current solution of using our own grid system.  By using our own, faster grid system, we also had to use our own implementation of A*, which essentially made us break even with the performance gains (because Game Maker’s mp_grid_path function is impossibly fast).  However, we hinted at our backburner task of rolling out the path finding (A*)  on a different thread.  Game Maker Studio has the ability to pull in from external resources, and we finally got around to offloading the path finding in C++ as well as on a different thread (spoiler, this gave us extreme performance boosts).

I (Dan) finally had a few consecutive days off after Christmas where I was able to dedicate 100% of my time with no interruptions learning how to make external DLLs that Game Maker Studio could then import and make calls out too.  The journey was tough — and honestly, I thought it was going to take longer to figure out than it did.  Most of our learnings came from these forum posts / guides:

  1. https://forum.gamemaker.io/index.php?threads/getting-started-with-c-dll-extension-creation-in-eclipse.73728/
  2. https://forum.gamemaker.io/index.php?threads/asynchronous-c-dll-extension-creation-in-eclipse.74176/
  3. https://help.yoyogames.com/hc/en-us/articles/360015676137-How-To-Create-DLL-Extensions-For-Windows-Games

We ended up going with Visual Studio instead of Eclipse, mainly because we already had Visual Studio installed for Game Maker’s YYC compiler.  After about the first day, we had a simple “Hello World” program made where we were able to talk to Game Maker and back to the DLL.  Day 1 and 2 also saw us converting our A* from GML to C++.  I haven’t touched C++ since my college days, so it took a little bit of time to remember how good ole pointers work.  After about Day 2, the A* algorithm was able to compute within a main program within the DLL (meaning, it was converted successfully).

Day 3 was the trickiest as we had to convert our aforementioned grid system of the previous blog post to buffers.  The only way to send large amounts of data to a DLL is to send the memory address (pointer) of the buffer from Game Maker.  Therefore, we had to convert our ds_grids to buffers.  Even though this was a pain, buffers are not only faster in Game Maker, but the size in memory was about half, so we inadvertently gained some performance.  Day 3 also saw us learning how to use threading properly in C++.  Even though native C++ is faster than GML, it still didn’t really make since for us to spend all of these new CPU cycles sending to the DLL if we were still running the A* on the same / main thread as the game.  Therefore, we had to figure out how to implement C++ threads.

There were two threading libraries we looked at.  The first was pthread, which we ultimately scrapped as it is meant for Unix computers.  Though there are ways to make it work on Windows (the eclipse link / we had it kind of working at one point in Visual Studio by importing the pthread library, but eventually gave up) we finally went with thread, which seems like it is native to C++ now.  After a few hours of experimenting, we were able to get threads working within C++.

By the fourth day, we were able to successfully send the grid data to the DLL, create a thread, compute the A* path and send the path data back to Game Maker!  When I first got the logs of the path data in Game Maker, I screamed at the top of my lungs and scared my wife!  A few minutes later, we were able to convert that data so that our Soldier enemies could move again!  We also were able to figure out ways to cancel computations / threads in the DLL.  For example, if an Orc dies while computing its path, we no longer need to compute the path anymore, since its dead.

Seeing the fruits of this labor paid of majorly.  We’re even thinking of moving our boid enemies (Globs, Bats, Violets) so that the computation is also threaded / asynchronous, as we eventually want tens of Violets on screen.

“Asynchronous” Zones

If we recall from previous posts, as our hero / camera moves from one location to another, we load in zones that are slightly off screen the direction we are moving and unload zones that are slightly off screen in the opposite direction.  If the whole world was computing all at once, our game’s speed would crawl.  In the spirit of async, we decided to make our loading / unloading of zones “asynchronous”.  We put asynchronous in quotes because, unlike the aforementioned A* which is truly asynchronous, the loading and unloading of zones is spread (vs. done all at once) amongst several frames.  For example, if we need to load in 4 zones, and it has taken more than 500ms to do so, we tell that system “hey, you’re taking a long time.  Let’s continue loading the next frame”.  So, instead of loading 4 zones in 2000ms (remember, a frame should compute and draw in ~16000ms), we load 1 zone each frame for about 500ms.  Since these zones are slightly off screen, there is still no need to worry about a jarring “pop in” effect.  By offloading this task to several frames of the game, we are able to prevent stutter slow.

Other Stability Increases

We also improved the frame rate of the game by removing a few particle effects that we were planning on replacing anyway.  For example, blood was a particle effect that we don’t believe was getting removed properly.  Recently, if an enemy dies, its body remains until the player unloads the zone and then comes back to that zone a few minutes later.  However, if the player never returns back to the zone, the body and its particle system remained in memory until the game ended.  By removing the particle (we’re eventually going to create a system for handling dead bodies / other objects that linger around like this), this in turned freed up memory, which in turn, frees up the CPU.

We also improved the draw_container routine for the inventory.  All other draw_container calls cached the container that is being drawn, except the inventory screen.  This was mainly because refactoring this was going to take a bit of time and was easier to just leave alone.  However, keeping the inventory from redrawing the container each frame would create hundreds of structs per frame, which would cause memory to spike.  Game Maker’s automatic garbage would eventually clean this.  However, the amount of time garbage collection has taken on Game Maker’s part has become quite burdensome for Violet recently.  Essentially, there have been stutter slow downs, similar to the aforementioned loading / unloading of zones.  However, unlike loading / unloading of zones, we don’t control Game Maker’s automatic garbage collector.  Therefore, anything we can do to help avoid unnecessary structs / memory on our part we’ve noticed helps keep Game Maker’s garbage collector more stable.

Weapon Degrading / Capacity / Shards

On Christmas Eve, I (Dan) was playing an old build from 2019.  I was mainly doing this just to see how far the game had progressed.  While playing, I realized a mechanic that functioned differently than it does now.  When a weapon degraded, it only moved down by 1 damage point.  Though there was nothing in 2019 indicating that it had degraded, it was interesting to play the game with weapons that slowly degraded vs. now where degrades go down a full letter (therefore, like 20 damage points).  We began thinking “what if we degraded by a smaller amount”?

We decided to try this theory and liked this so much better.  Now, instead of a C ranked weapon dropping to a D, it goes from C to C-, C- to D+ and then D+ to D.  We feel this really helps with the damage output in mid-battle.  However, with degrading only going down by thirds, the amount of weapon shards (which can be used to increase weapon capacity) had not changed, being way more abundant.  We decided to decrease this, as well as decrease the amount hits it takes to degrade a weapon.  Therefore, the degrading happens more (but the damage output is not cut has bad), which yield more weapon shards (but not too abundant).  With these two new systems at play, we also decided to make starting inventory capacity for each type 2.  With more weapon shards, it becomes pretty easy to increase weapon capacity.  With the primary mechanic of merging degraded weapons together for better weapons, we feel like we’ve made better a really interesting game loop with the weapon system.

Horsing Around

It’s been a bit longer between posts than we were hoping for.  I (Dan) usually write these posts on the weekends.  But here in development land and in the real world, it has been pretty busy.  A couple of quick stories before we proceed:

  1. Two weekends ago, my computer started micro stuttering the game weirdly.  At first I thought it might have been something to do with my graphics card.  However, after some testing, it was concluded that my hard drive was starting to go bad.  More on this story later.
  2. We were able to show the game to some familiar faces who hadn’t seen the game in a couple years, as well as new faces who were seeing the game for the first time.  The feedback was amazing as, for the first time, we were able to see a lot of the game mechanics for others actually come together and work as intended.  This was really exciting as it reinvigorated us and reinforced that we have something good here!

The good news in the extra time between posts means there is a bit more to show!

Horse

The title of this post is two-fold.  First, there were several concepts and functionalities that we experimented, or, “horsed around” with.  Second, of course, the horse!

The prototype horse has been in the game for a couple of years now.  It’s hidden away in a barn and we usually don’t tell players about it and let them discover it on their own.  For those players that do discover the horse, they absolutely love it (even in its terrible, prototype state).  We decided to have Tony create a walk and gallop animation for us to test ideas and concepts out with.  Below are those animations:

Horse Walk Right
Horse Walk Right
Horse Walk Down
Horse Walk Down
Horse Gallop Right
Horse Gallop Right
Horse Gallop Up
Horse Gallop Up

The animations feel very good in the game.  However, one of the reasons we haven’t gone “full force” into the horse is of course the additions of all the new different kinds of animations we would need.  We had an idea to potentially save time by cropping out the bottom half of our hero’s animations and replace them with a sitting / riding animation.  However, this idea in practice is probably not going to end up working.  We’re still “horsing around” with ways to make animations go quickly as we know everyone loves the horse.  However, we still have a lot of other art / animations to get done before our Kickstarter goal and reworking current animations just to ride a horse may not be time best spent.

Riding Horse
Riding Horse

Reptile Updates

We also have a few more animations to share about our good friend (rather, enemy), the Reptile, that we introduced in our previous post:

Reptile Heavy Swing Down
Reptile Heavy Swing Down
Reptile Stun Left
Reptile Stun Left
Reptile Death Left
Reptile Death Left

Sound Effects

It’s been long overdue, but at the beginning of July, Noah Flack began replacing many of the old, crusty placeholder sound effects with some new, polished sound effects.  We started down the road of creating sound effects from scratch, but it seemed more feasible to use a library of sounds and update / alter them according to our needs.  The library we are using in their licensing agreement has a restriction of “redistributing” these sound effects elsewhere.  Though this post isn’t intended to be a place where we are redistributing sounds (as well as many of these are heavily modified and would be unrecognizable from the original source), we felt it would be safer not to showcase any of those sounds from that library.  However, we do have a couple of sound effects that we created from scratch.  Here are a few below:

Knight Ghost Hit

Knight Ghost Death

Raining Outside Perspective

Raining Inside Perspective

UI / UX Updates

There was a reason why we wanted to tell the stories at the beginning of the post that we did, and here is the first reason.  While watching folks play the game, we noticed a few reoccurring behaviors that needed to be addressed:

1. Players had a hard time seeing how much damage they were taking in the “heart bar” in the top left of the screen.  Though Violet’s iframes are intentionally small, we still found a way to communicate how much damage the player was taking by making an animation of the heart breaking.  The more damage / combo damage that happens, the longer the delay for the start heart animation to playback.

Losing Health
Losing Health

2. In the same vain, players had a hard time seeing how much health they recovered when eating a recovery item.  Now granted, we still don’t have an eating animation (which we plan to add).  However, adding a heart animation that shows the player how much health they’ve recovered should help with this problem.  The delay of the start of the animation works similarly to taking damage, in that the more health / combo health recovered will delay the start of the animation.

Gaining Health
Gaining Health

3. We’ve also observed many folks in the colder regions wonder why they began taking damage.  After the initial cold damage popup (which players may forget or ignore), there was no way of knowing why the player was taking damage other than seeing the temperature gauge down in the bottom right.  However, before these updates, the needle was very small and hard to see.  We’ve addressed this with a few things:

  • Made the needle bigger as well as change colors the closer it gets to the cold / warm zones
  • When taking cold damage, use a blue color instead of red
  • When taking heat damage, use a red color (like before)
  • When taking any other damage, use a violet color instead of red
  • When taking cold or heat damage, make the gauge turn colors and have a cold / heat animation playback
  • In cold / warm zones, shake the temperature gauge a little to grab the players attention
Freeze Damage
Freeze Damage
Burn Damage
Burn Damage

Doorframes

We ended up reworking doorframes a bit.  We noticed when going through a doorframe with a weapon that the weapon was drawn in the wrong layer.  This is because all we were doing to sell the illusion that our hero was going through a doorframe was turning the visible property on and off at the right times.  This was a bit hacky and we went back and redid the way this works so that doorframes / doorways are on the appropriate layer now:

Doorway In
Doorway In
Doorway Out
Doorway Out

Other Notable Updates

Path Finding

At the crux of our Soldier AI is Game Maker’s path finding algorithm.  In hindsight, Game Maker’s mp_grid_path function is impossibly fast (seriously, if anyone knows how this is implemented, hit us up) — which is unfortunate because our problem wasn’t with this function.  Game Maker has two requirements for creating paths:

  1. Grids, which is essentially “the world” made up of walls and not walls.
  2. The aforementioned mp_grid_path function, which takes a grid and generates a path, most likely using an extremely optimized version of the A* algorithm.

The problem we were encountering was the time it takes to create grids.  Though paths are extremely fast to compute, grids are on the slower side (perhaps Game Maker pre-optimizes the grids, which is why paths are so fast?  We’re still not sure).  We’ll explain why this is a problem soon, but we really need a solution from Game Maker described in this Reddit post.

The way Game Maker Studio encourages developers to use these functions is to create a “world grid” one time and be done.  For the average developer using Game Maker’s mp_grid_* functions, this would be more than adequate.  However, in our case, our world is huge and each enemy has a slightly unique grid.  We’ve still been able to make great use of these functions though by doing a few workarounds.

To get around these problems, each Soldier enemy would create their grid based on the “chunk” of the world they resided in, as well as a few trade secrets.  In the above link to the Reddit post, since there wasn’t a simple mp_grid_copy function, we were manually creating grids every time we needed them (smarter enemies would make a grid every 30 frames for example).  This was costly on the CPU.  We had several tricks to make this less intensive, such as offsetting each enemy to create their grid, essentially preventing multiple grids from being created on every frame.  But this trick can only go so far.

One other problem we were wanting to solve for is the built in path finding deals with points, where our enemies and their hitboxes are bigger than one pixel (essentially wanting clearance-based path finding).  It wasn’t a big deal until recently when we discovered our Centaur enemy, with its big hitboxes, kept running into the wall on a tight turn, and not able to clear it.  With this problem and all the other aforementioned problems, we decided to roll out our own grid and pathing implementation.

We knew we needed to update the path finding algorithm itself, but the first thing we focused on was creating fast grids.  Since we were able to roll out whatever solution we could build, we wanted to solve three things with our implementation of grids:

  1. Have a “master” grid that all enemy / etc. grids would inherit from.
  2. Only update enemy grids with necessary updates (i.e. only update when needed, don’t update everything every n frames).
  3. It needs to be fast.

It took many nights and weekends to solve for this, but the solution we came up with for grids is ten times as fast as Game Maker’s grids!

We even solved a bonus problem introduced by our layerDepth system:  instead of one grid per enemy, it was however many layerDepths there were per enemy.  We ended up solving this problem with our friend, binary!  Our grids represented a wall as 1 and a walkable tile as 0.  We could express walls in layerDepth 0 as simply 1 (0001).  In layerDepth 1, we would express walls as 2 (0010).  But, what if we had a wall in both layerDepth 0 and 1?  We could express walls as 3 (0011).  When we needed to know if a cell in a particular layerDepth had a wall, we could simply pull out the bits of a number and determine whether a wall was there or not.

Our last task was to actually implement our own variation of A* and clearance based path finding.  Rolling this out in pure Game Maker has actually been more of a hindrance than a help.  With the performance gains we’ve obtained from the grids, we’ve essentially lost that and then some with our implementation of A*.  This isn’t because our implementation is bad — it’s actually really clever all things considering.  It’s simply that GML is a language above C++, and the further we get from writing code in native 1‘s and 0‘s, the slower the code becomes.

We did implement one trick with our A* which essentially only computes an enemies path for 100ms for a given frame.  If it takes longer, we store the computations its made and move on until the next frame, where we continue from where we left off.  It’s essentially fake threading and is a good compromise for now.  At the very least, we “break even” with our net performance gains / losses from all of this.

Where do we go from here?  Well, one of the backburner tasks we’ve been wanting to implement is rolling out path finding on a different thread.  Game Maker Studio has the ability to pull in from external resources, and this is the next logical step for us.  Offloading the path finding in C++, as well as on a different thread is going to give us extreme performance boosts — especially with our Soldier AI being so integral to the game behind-the-scenes.

TileCompressedData

Another update we had to do was in regards to our build scripts.  Game Maker 2022.8 introduced TileCompressedData to the IDE, which increases build times by tenfold.  Before, Game Maker Studio did not compress tile data for rooms, which made the file size for larger rooms with many tiles in the megabytes.  When doing builds, Game Maker would do comparison with these rather large room files, taking additional time for each build.  So what’s the problem — this seems like a great thing?!  Well, our build scripts were built with the uncompressed tile data, so we had to account for that.  This was a weekend project, but we were able to reverse engineer how Game Maker Studio stores its TileCompressedData.  That code is available here in our GMS-Tasks helper project.

Recorder / Playback Input

I bet you’re still wondering about the juicy details of what happened to my computer’s hard drive and what caused the micro stuttering?  Well, if we recall back in December of 2020 we introduced a dev feature called “Playback Input” which lets us record all of the inputs we make and if something crashes, we can “playback” those inputs exactly to get the exact crash.  Well the way we were handling this was less than optimal.  The reason for this is not because we are incompetent, but at the time, Game Maker did not have a means of handling crashes.  For example, if the game crashed, there was no way to “save” our input recorder since there was no way of handling unexpected crashes.  Our hacky solution around this was to write out one file every frame of the game the input the player made.  That way if the game crashed, we were able to “glue” those files together to create one big file.

The problem is writing 60 files every second while the game plays for the past two years has been taxing on my hard drive.  Out-of-the blue one fine Saturday morning, our game finally had enough and began running terribly slow.  I didn’t realize at the time that the problem was the Input Recorder.  My brother-in-law was in town and as I was explaining the issue, he happened to noticed the SSD in task manager was maxing out at 100%.  Once I remembered we were writing those files every frame, I turned the setting off and the game played normally again.  After testing on my laptop, confirming no one else was having issues, and reinstalling Windows, that’s when I knew I was beginning to see a hardware failure.

Good news in all of this is I decided to buy the AMD Ryzen 5700x processor and the Corsair MP600 1TB M.2 drive.  The processor cuts build times IN HALF and I’ve seen about 20% increase in build times with the faster read times on the M.2 drive.  The other good news in all of this is unbeknownst to me, Game Maker Studio added the exception_unhandled_handler which lets us handle unexpected crashes gracefully.  This lets us, for example, save out our input recorder, as one, sane normal file!  All of that to say, we needed to update our Recorder Input to handle writing just one file and our Playback Input to read in this one file.  Hopefully we won’t have to worry about future drive issues now 😛

 

 

Reptile Updates

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.

Reptile Walk
Reptile Walk
Reptile Run
Reptile Run
Reptile Backflip
Reptile Backflip
Reptile Breath
Reptile Breath
Reptile Balanced
Reptile Balanced

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:

Sword Run Animation
Sword Run Animation
Sword Walk Animation
Sword Walk Animation

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:

Mace Walk Test
Mace Walk Test

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):

Spear Walk
Spear Walk
Spear Walk
Spear Walk
Orc Spear Walk
Orc Spear Walk
Orc Spear Walk
Orc Spear Walk
Reptile Spear Walk
Reptile Spear Walk
Reptile Spear Run
Reptile Spear Run
Reptile Spear Run
Reptile Spear Run

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 layerDepths.  This took a bit of reworking, especially around the transitions areas, which we called rampTile. RampTiles used to be single individual tiles, but we ended up merging that with our Tile Object system for optimizations.  As a reminder, RampTiles 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 layerDepths / trigger points / RampTiles
  • Updating the Renderable system to draw objects correctly
  • Updating the Buildingable system to determine whether an enemy is inside / outside and accounting its layerDepth
  • If an enemy / hero is using a weapon or holding something, determining how that interaction accounts for layerDepth, as well as interacting with the Buildingable 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)).
  • 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:
      Transition Example
      Transition Example

      Transition Example
      Transition Example
  • Updated Long Grass Tiles
    • We also updated the art for the long grass tiles.  Below are a couple of screenshots:

      Long Grass
      Long Grass
    • 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:

      Auto Tile Indexes
      Auto Tile Indexes
    • 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 is 11111111.  This tile has 8 neighbors, because it is a full tile.  Each of the 1 represent a neighbor.  The last tile from the cheatsheet, 0 in binary is 00000000.  This tile has 0 neighbors, because it is an empty tile.  Each of the 0 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 by 0001000.  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 be 00011000, which in our normal system would be the number 24.
  • 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.

A Hodgepodge of Updates

We’ve been trying to get away from the “Art Updates Part n” titles to be a bit more descriptive with our recent posts.  But this update could very well be a continuation of those parts with the hodgepodge of art and functionality that were updated the last couple of months.  They say the best way to explain is to show, not tell.  So without further ado, let’s show and not tell:

Updated Weapon Icons

When picking up a weapon, or seeing it in our inventory, a different graphic is represented than the graphic used for combat.  We’ve updated all the icons at 4 different resolutions: the smallest for the HUD, 1x for normal gameplay, 2x for the inventory and 3x for seeing the item in descriptive dialog page.  Our artist, Tony, had to draw out each of these essentially four times — it was a blast 😉  Below are a few of these icons at the highest resolution:

Sword Icon
Sword Icon
Spear Icon
Spear Icon
Axe Icon
Axe Icon
Fire Rod Icon
Fire Rod Icon
Long Bow Icon
Long Bow Icon
White Shield Icon
White Shield Icon
Ambush Dropping Icon
Ambush Dropping Icon
Weapon Shard Icon
Weapon Shard Icon
Extra Heart Icon
Extra Heart Icon
Violet Leaf Icon
Violet Leaf Icon

Docks and Bridges

Below are a couple of screenshots in the northern mountains with the newly updated bridge and docks graphics:

New Bridge
New Bridge
New Docks
New Docks

Bow and Arrow Animations

As simple as the bow an arrow animations look, there were quite a bit of updates from a functionality standpoint that we had do in order to pull all of this off in game.  In the Other Notable Updates section, we’ll go into more detail about all of that.  Below are a few animations for the hero and Orc:

Hero Bow Animation
Hero Bow Animation
Hero Walk With Bow Animation
Hero Walk With Bow Animation
Hero Run with Bow Animation
Hero Run with Bow Animation
Orc Bow Animation
Orc Bow Animation
Orc Walk with Bow Animation
Orc Walk with Bow Animation
Orc Run with Bow Animation
Orc Run with Bow Animation

Hero Stun and Death Animations

We also decided it was finally time to have our hero get hurt and die:

Hero Stun Right
Hero Stun Right
Hero Stun Up
Hero Stun Up
Hero Death
Hero Death

Pickup / Throw / Setback Down

We also added all the animations associated with picking up and throwing objects.  Similar to the bow and arrow, we also had to add walking animations for holding and running.  Below are a few updated animations:

Hero Pickup Throw Animation
Hero Pickup Throw Animation
Hero Pickup Setdown Animation
Hero Pickup Setdown Animation
Hero Walk Hold Animation
Hero Walk Hold Animation
Hero Hold Run Animation
Hero Hold Run Animation

Other Notable Updates

Last time we introduced a new system called Renderable, which in summary, gives us a better way of handling shadows and the z axis.  There’s been a lot of work behind-the-scenes on improving on / expanding this system further.  For example, we have added on to this system by giving objects a bouncing property.  There are a few updates that are not quite yet done, but it’s progressing well nonetheless.

We mentioned earlier in this post that there were updates we had to make for the bow to work properly.  For as long as the bow-and-arrow mechanic have been in the game, walking / running while holding the bow has always been a still image.  This worked fine for prototyping purposes.  Once the pull-back the bow string animation is complete, the object goes into a hold state of the bow until the arrow is released.  With our current system we can be in a stand, walking or running state while holding the bow, and the new animations work great!

However there was one problem with the current system — the pull-back of the bow string animation.  This animation is about a second long, which without moving the feet, made our hero seem like he was floating.  We did not want to remove the mechanic of being able to walk / run while equipping (i.e. the bow string animation), and we did not want to add a pull-back animation for each different combinations of walking / running directions we could do.  Therefore, we got creative with the animation and decided to shuffle the feet when doing the pull-back of the bow string animation.  This seemed to solve the problem for the most part, and works well with transitioning into the walk / run while holding bow animations!

The rest of the updates, including the updates to the bow animations, are pretty simple and can be summarized in a quick bulleted list:

  • We updated our soldier enemies to account for the new bow animations.  Mostly, we wanted to make sure that once a soldier enemy had committed to telegraphing which direction they were facing to shoot, that they couldn’t change directions until the animation had played out completely.
  • Speaking of telegraphing animations, we finally got around to updating the soldier enemy to telegraph its attacks.  This essentially amounts to pausing on a specific wind up frame for a given amount of time (easier enemies pause longer than harder enemies).
  • Last time we also mentioned how we allow the player to merge anywhere instead of going back to the town to merge weapons.  This new feature is great, but was definitely becoming a tedious chore after a while.  Therefore, by pressing a button in the inventory screen, we can simply “auto merge” our weapons to automatically rank them up!
  • Finally, we’ve had our hero be able to pickup and throw things for a while.  However, we also needed the ability to set objects back down without them breaking (so we can do the infamous set an object on a switch puzzle).  We updated the holdable system so that they can be setback down (as well as concurrently getting the animations to make this look right at the same time!).

The Future of Violet

It’s been a while since we shared our plans about Violet from a logistical front.  Obviously we’ve been making a lot of progress with art and functionality, but there’s been a lingering question: “when are we going to do Kickstarter”?  We haven’t revealed the when for a while in case what we shared was premature and then to go back with our tail between our legs.  However, in 2019 we wrote a post attempting to explain the current plan at that point in time, and we believe we’re long overdue to share an update.

This past year, Tony and I have been trying to shoot for a date of February 2023. Recently though, after realizing just how much art and animations we still need to do to make the demo “the best it can be”, we decided to move that back to an April 2023 window.  This gave me some time to reflect on what all need to actually get done before then.

Meanwhile, the adviser I met with back in 2019 just so happened to reach out to me to see how the game was coming.  It was crazy as I was considering reaching out as well to get some feedback and opinions.  We setup a time to meet and during that week of prep, I had this uneasy feeling about all the work that still needed to be done if attempting to do a Kickstarter by April, 2023.

There’s a long list of improvements, features, lore implementations, demo direction, among other things that need to be done.  If this project was a full time job, this list would be a piece of cake to complete.  However, this game is a project that I do on nights and weekends which makes this deadline seem daunting.  Therefore, I started having an uneasy feeling about the April 2023 deadline. As I was struggling with that uneasy feeling, I kept dreaming of the opportunity where I could do this project full time, as that has been the long term goal.  As the game and its systems continue to grow and become more complex, it gets harder to revisit those systems to fix bugs / make improvements / etc.  And I know that eventually, nights and weekends just won’t cut it.

Nevertheless, the adviser and I had our meeting.  The first half of the meeting was showing the progress of Violet since 2019, which if you have been following along, you’ll know it’s been night and day.  The second half of the meeting was to get some advice and opinions on what to do next on the logistical front.  The main information I was hoping to obtain was three things: “when is a good time to do a Kickstarter”, “what should I prioritize before then” and “what is a reasonable goal number to reach”.

The when to do a Kickstarter for the first question aligned with what I had originally thought:  sometime in the months of February – April.  “So far so good” I thought.  The advice I received for the second question wasn’t as daunting as I thought it would be.  There were several tips and tricks we could do to pull off a April 2023 window.  This had me excited as the fantasy was starting to become a reality.  However, when I had mentioned my goal amount versus the expectation, the actuality set in.

With the uneasy feeling I was already having about trying to meet the April 2023 window, and then the news about how much to money to statistically expect to receive, I unofficially decided to pivot from the April 2023 window.  This was not an easy decision, especially because doing this project full time is something I have been hoping to do for a while now.  However, even though the systems of the game continue to get more complex, I still am able to make progress during nights and weekends — even if it’s not at the pace I always want.

As I have been writing these posts, it’s been awesome to go back to previous posts whenever I feel discouraged to see the progress the game has made. Back in 2019 we wrote a post attempting to explain the current plan at that point in time.  I actually reread this post and this quote still can’t be more true:

…If the game became a “chore” or another “job” at this point in time, I would not have the motivation to fight for this project like I want to.  I do eventually want to make this something I do full time, but not by sacrificing myself mentally in the meantime.

The biggest thing, even now in 2022, is making sure that the game doesn’t become a chore or a job while I have a full time job.  If I knew pushing for a year meant getting to a point where I could do this full time, then I would definitely go for it.  However, pushing to get this game across a finish line to only receive a fraction of the amount I would really need to fund this project full time is not worth it to me.  And as it currently stands, I am able to fund different aspects of the game (art, sound, etc.) out of my own pocket, albeit at a much slower pace.

As I was accepting this decision, Nintendo announced that The Legend of Zelda: Breath of the Wild Sequel had been pushed back to spring 2023.  If the signs weren’t already clear to me to wait on doing a Kickstarter, this was the final confirmation I needed.  Even though Violet would “compete” in a much different way than one of the most anticipated AAA sequels by Nintendo, running a Kickstarter for a game with many similarities would be foolish, let alone, most likely getting absorbed by the hype surrounding Zelda.

So if not 2023, then when?  And if I can continue the fund the game out of my own pocket, why do a Kickstarter at all?  Those are very good questions and I am glad you asked. 😀

I do think it is wise in setting some “target date” as otherwise, iteration of Violet will go on forever.  At some point, we need to show the game to the general public to get some reception and feedback — and what better way to do it than a Kickstarter where we can hopefully get future fans invested in the project.  After all, we’re not just making this game for ourselves.  And we are not Nintendo, where we can drop a trailer, and that alone can drive buzz and hype for months.  Therefore, we are now targeting a date of February 2024.

Meanwhile, another two years “cooking in the oven” is a lot of time to make progress on the development front, as well as the art and sound.  With more of the game complete and polished, we’ll hopefully be in a better spot where that fractional amount can be doubled or maybe even tripled.  To summarize, here’s something from the same post in 2019:

…I think it is wise to continue being patient, and slowly building out concepts and features at a pace that is fun and rewarding, rather than something that feels like “work”.

Orc Updates

These past couple months we’ve been focusing on updating one of our soldier enemies, the Orc. The Orc is one of the more simpler soldier enemies in that it’s weaker, generally slower and its reaction time lacks.  It’s been fun seeing this guy come to life and we can’t wait to share some of the animations here:

Orc Idle
Orc Idle
Orc Walk
Orc Walk
Orc Walk Backwards
Orc Walk Backwards
Orc Stun
Orc Stun
Orc Run
Orc Run
Orc Death
Orc Death
Orc Heavy Swing
Orc Heavy Swing
Orc Balanced Swing
Orc Balanced Swing
Orc Agile Thrust
Orc Agile Thrust

Other Notable Updates

Renderable

In our previous post, we did not have a notable updates section, mainly because we were still in the middle of updating two major systems.  Both of these systems have to do with depth, or, where the object is drawn on the screen.  The default depth system in Game Maker Studio has served us well, but with the ever increasing complexity of the layer depth system, draw order gets blurry when dealing with transitions between on layer depth and another.  This link explains some of the same issues we’ve been running into.

We started down the road of implementing a z-tilt shader, similar to how this blog implements it.  However, we found a bug with rendering tiles.  As we continue to wait for the resolution, we simply decided to update the default depth system, as well as update different places where layer depth was being triggered.  For example, previously we were triggering the layer depth at the two openings of a bridge over water.  We decided to make all land and bridges over water layerDepth1 and all water and inside caves layerDepth0.

When we jump off a cliff and into water, we trigger layerDepth1 to layerDepth0 and simply multiply the depth by a negative room_height.  When entering a cave, there is a fade transition that sort of masks (or hides) the fact that there is a draw depth problem.  This solved most of the draw depth problems for now — though it won’t solve issues like stair transitions from a lower area to an upper area.  We still plan on using z-tilt in some way as that is really the only to solve for properly drawing objects with this complexity properly.

In the same vein, we’ve also been updating our drawing system (the pipeline to be more consistent) and shadow system, as well as adding a z axis.  z gets complicated when we’re in a 2D space.  What is z?  Where should it be drawn?  Where is the collision with respect to the visuals?  All of these things are very hard to get right, so most of the time, we don’t use z, but something we made up called zPseudo.

zPseudo keeps the current visuals and the collision at its normal y position.  Therefore, the purpose of zPseudo is to render the shadow zPseudo units down from the y position.  z on the other hand renders the shadow at the current y position and renders the image of the object z units up.  In 95% of our use cases, we found that using zPseudo was a better system for visuals and collisions.  For example, a bat that is flying uses zPseudo casting a shadow 32 pixels from y.  If the bat collides with a sword, it made more sense for the sword’s visual to overlap the bat’s visual, so that the bat would get hit.  The 2.5D perspective is very odd, but our brains believe it to be true!

This system was complicated to come up with, but it’s proven to be very useful in making all of the game use shadows, heights, z positioning consistently across the board.  For example, each projectile (arrow, fireball, ice particle, etc.) all implemented their own way of shadows.  Now they all inherited from the parent object, Renderable!  We were also able to therefore implement a consistent gravity function, giving objects a sense of falling or being dropped.  The possibilities are now endless of what we can do with this system!

Ranking System

That last section was complicated, so thanks for sticking through our ramblings!  The rest is straight forward and more fun “game” things!

Our weapon ranking system has been revamped!  We used to use letters EA, S, where E was low quality and A, S was best quality.  We now added the letter F as worst quality, and added +/- rankings for each letter grade as well (except for F and S)!  The reason for this was we found that merging weapons that were not the same letter grade was cumbersome.  Therefore, we added the ability to merge any letter grade.  We still have to merge the same weapon type though.

We also added the ability to merge anywhere instead of going back to the town to merge weapons.  We found merging anywhere to be more rewarding help the player continue to adventure.  With that said, we’ve had to update our merge system quite a bit.  Even though we’ve made some updates to our merge system, we still find it tedious after a while to merge many weapons and will probably implement some sort of “auto merge” system.

Finally, we didn’t want to leave our town’s blacksmith without a job, so we added the ability for our blacksmith to take weapon shards and expand inventory!  Weapon shards can be found when a weapon deranks.  This helps the player to not feel like using a good weapon is a bad thing because they’ll be able to use those shards to make further progress within the game!  Plus the higher the ranked weapon is, the more shards that will drop from a degraded weapon.  Plus, we can easily remerge our lower-ranked weapon back up!

Everything Else

  • In adding our Orc, we’ve updated our soldier enemy a bit to be smarter!  One thing we added was for the enemy to move out of the way of moving projectiles.  Smarter enemies are better at doing this than others.  We still have a lot of rework to do with the new animation updates to make the soldier enemy a bit more seamless.
  • We’ve merged the way our tile layer system handles the tiles so that each layer has three sub layers: the base, overlay and animated overlay.  For example, what we were once calling decor tiles is now in the animated overlay.  Paths on the grass tile would be in the overlay sub layer.  And of course, the grass tile would be in the base sub layer.
  • We noticed an issue when swinging our balanced weapons up that sometimes smaller enemies would not get hit if they were between the balanced weapon’s visual and the hero.  We fixed this so that the balanced weapon has a bit more collision below its normal visual.
  • We updated the targeting system to be a bit more accurate.  Plus, using the R-Stick to move between enemies should be a bit more intuitive and better to use.  Also, instead of using the “Ocarina of Time” triangles, we’ve resorted to a more simpler “triangle over the targets’ head”.
  • Finally, we added a system called “animation position” that let’s us move an object to a position based on the animation frame an instance is on.  For example, our Ambush’s protection can now more accurately be position on the Ambush’s head for each frame of the animation.

Castle Town Art Updates

As we have been updating friends and family about the progress of Violet, we’ve been depicting how great the new art is looking.  But then, when we show the demo, the player is greeted with the old art of the Castle Town — not a very good first impression.  Therefore, this past month we’ve been focusing on updating the Castle Town art.  This included everything from roads, exterior / interior houses, the castle town walls and decor for inside the houses.  Below are some screenshots of the updated Castle Town:

Castle Town
New Castle Town
Castle Town
New Castle Town
Castle Town
New Castle Town
Castle Town
New Castle Town
Castle Town
New Castle Town
Castle Town
New Castle Town
Castle Town Inside House
Inside New House
Inside House
Inside New House
Castle Town
New Castle Town
Castle Town
New Castle Town

Art Updates Part Five

Violet has made quite a bit of progress in the last year.  As we reflect on where we were at starting the year vs. where we are at now, the game is starting to actually look like a retro 2D pixel art game of the past.  Tony Wojnar has really been “killing it” these past few months, and the update we are about to share today is no different.

The majority of the art updates focuses on three of our enemies in the game: Glob, Ambush and Knight Ghost.  Without further ado, let’s get into art!

Glob

Our first enemy update is the Glob.  They are simple, Chu Chu like enemies that move together and attack our hero when threatened.  They come in the colors of green, blue, red and black.  However, only green is showcased below:

Glob Move
Glob Move
Glob Attack
Glob Attack
Glob Death
Glob Death

Ambush

Our next enemy update is the Ambush.  They are Octorok like enemies that, as the name implies, “ambush” our hero by hiding under rocks and bushes.  They come in the colors of green, blue, red and black.  However, only green is showcased below:

Ambush Dive
Ambush Dive
Ambush Shoot Right
Ambush Shoot Right
Ambush Death
Ambush Death

Knight Ghost

Our last enemy update is the Knight Ghost.  They are Wizzrobe like enemies that use element rods to attack and then quickly warp to a nearby location.  They use the three element rods: fire, water and ice.  These elements represent there base colors and then their strength comes in the colors of green, blue, red and black — resulting in 12 different color variations.  Below are the fire / green variations:

Knight Ghost Idle
Knight Ghost Idle
Knight Ghost Move
Knight Ghost Move
Knight Ghost Scare
Knight Ghost Scare

New Element Rod Animations

We also added animations for the Fire, Ice, and Water Rod.  These rods work much like agile weapons where they can be used in any direction.  Unlike agile weapons, rods only have one combo to them as well as shoot an element projectile from them.  Fire rods shoot a fireball that deals good damage, knocks an opponent over, and of course, creates fire that uses the normal fire properties (like spreading and burning).  Water rods shoot a gust of water out of them to push enemies, and eventually objects.  The force of the water can also knock enemies into a wall to deal damage.  This water can also “heal” damaged plants.  Ice rods shoot an ice particle out that can freeze opponents into an ice crystal, dealing freeze damage until the opponent can break free.

Below are the Knight Ghost using the different element rods, as well as the projectile and effect from these rods:

Knight Ghost Attack Fire
Knight Ghost Attack Fire
Knight Ghost Attack Water
Knight Ghost Attack Water
Knight Ghost Attack Ice
Knight Ghost Attack Ice
Fire Rod Effect
Fire Rod Effect
Water Rod Effect
Water Rod Effect
Ice Rod Effect
Ice Rod Effect

Other Notable Updates

This past month we finally merged our GMS 2.3 branch into the code.  This merge essentially included everything in the “Other Notable Updates” section we have mentioned in our posts the last year (as well as the new art of course).  We made an official stable build we’ve been calling “The Thanksgiving Build” for friends and family to try out.

The reason for all of the optimizations, refactoring and improvements is for our objects to be able to handle collisions within different layer depths better.  To recap, since our game engine only exists in two axis, we have to “fake” the third dimension of depth with a system we are calling “layer depth” — which dictates where an object is in the third dimension.  We were noticing before we underwent the refactoring / optimizations that the collision system for layer depths was chugging a bit.

We did add one change to our Tile Object system (yes, that same system we’ve been discussing the past year) to support ice tiles.  Since ice tiles can be created dynamically on-the-fly, we needed a way for our system to handle this type of tile creation.  Before, all tiles were created before runtime.  But now our Tile Object system is even more robust supporting mass ice tiles and we even were able to remove a few TODO items from that list.

With new art updates for a couple of our enemies came some code updates to handle the new art, as well as more accurately depict certain actions.  The changes most notable here were in the Ambush and Knight Ghost enemy, because they share the same parent object, RandomMovement.

We also added a system for objects that have “tails”, or graphics that trail behind the parent object, giving the parent object the illusion that it has motion.  Since objects like fire, water, ice, Ambush dirt, etc. all have this “tail” concept, we decided to optimize this as whenever one of these objects were spawned, the tails were getting a little expensive to process.  Now, we have graphical representation of these tails instead of creating n number of objects to represent these tails.

With our new water and ice projectile graphics, we also added a couple more features around these elements.  With water, if an object gets hit by the projectile, the force of the water pushes an object greatly.  The new feature that we added was if the object hits a wall at a fast enough speed, it will take “crush” damage against the wall.

With ice, we added the ability to be “frozen” in ice crystals (as seen by an earlier screenshot).  The enemy will be silhouetted blue against the ice crystal and taking freeze damage until they are able to break free.

Finally, we updated the weather system so that hopefully it rains a bit less.  If it still continues to rain more than we’d like, the code should be a bit easier to update to reflect the weather patterns we’d like each region to have.

 

Art Updates Part Four

I can’t believe how fast summer has come and gone.  It seems like yesterday we updated the blog with the last round of updates.  A few months have passed and we are excited to show a whole lot more!

The majority of the time spent on art has been adding agile thrusts for our hero and agile weapons.  It took a bit of back-and-forth because we were originally rotating the agile weapon at the angle between the holder of the weapon and its target.  However, pixel art doesn’t rotate well.  After countless hours of trying to solve the problem programmatically without compromising the art quality, we decided to draw out each rotation ourselves.

We decided that thrust animations worked well at 20 degree increments and the actual weapon itself would be rotated at 10 degree increments.  As an example, if the hero and its target is at an angle of 22 degrees, the closest thrust animation is the 20 degree animation (choosing between -40, -20, 0, 20 and 40) and the closest weapon animation is also the 20 degree animation (choosing between -40, -30, -20, -10, 0, 10, 20, 30, 40).  Therefore, the animation we’d use is the 20 degree thrust animation and the 20 degree weapon animation.

There obviously is a little bit of “precision” lost from a combat standpoint, as in the above example, being off 2 degrees is not exactly equal to the intended target angle.  At its worst, the angle could be off 5 degrees.  To account for this, we make sure the hitbox of the weapon is within that +-5 degree offset.  Therefore, Tony made sure as he was designing the art that the agile weapons’ graphics / hitboxes were big enough to account for this margin of error.

Hero Spear
Hero Spear
Hero Shovel
Hero Shovel
Hero Trident
Hero Trident
Hero Long Stick
Hero Long Stick

It was very tedious process, but after playing around with the agile weapons, it not only looks great, but feels great to use as well.

Environment

Right at the beginning of the month of August, we worked on a few trees and plants.  With all of the updated crops, we couldn’t remember if we were making an action / adventure game, or a farm sim!

Farmlands
Farmlands
Cherry Blossom
Cherry Blossom
Evergreens Mountain
Evergreens Mountain
Evergreens Grasslands
Evergreens Grasslands

Other Notable Updates

As we were updating the agile weapons, we realized that combat was weird with the right swings of the balanced and heavy weapons.  We realized that the motion was essentially mirrored and thus when turning the character, the right swings didn’t transition from the up swings, or into the down swings.  We ended up reanimating all the right swings for both our hero and the weapons.

Another weapon mechanic functionality we changed is not allowing the player or enemies to change direction mid swing.  The player could spam the joystick many directions per second which would make the weapon appear all over the place, being it a bit overpowered.  Not only did this solve the overpowered problem, but also fixed and smoothed out the animation between swings.

We also updated a few tilesets / backgrounds.  Some palette swap functionality updates are needed, but the mountain region has a new look and feel as well.

There were several minor TODO items we have cleaned up and polished as well as polishing the Soldier enemy AI.  There was an issue where the player could hide behind the tree and the enemy wasn’t able to compute a path to the player.  This was due to the player’s hitbox colliding in the tree’s hitboxes, which made the tile “walkable” for the enemy (from an A* standpoint).  We make the tile the player is standing on a “walkable” tile so the enemy can compute a path to the player.  However, the enemy is programmed to not actually walk through the tree.  We tweaked the values of the hitboxes as well as a few offsets to fix this.

We had three major components we refactored this time around:  Playback / Recorder Input, Going inside Buildings, and the Soundboard.  In this post, we introduced the feature of being able to record a player’s input to then playback after a session.  This lets us recreate a bug consistently so we can squash it.  When we created the Playback / Recorder Input originally, we hardcoded a lot of things in the HumanInput controller, and we wanted to abstract this to be more OOP, where the InputRecorder was an object and the InputPlayback was also a separate object, both doing their own unique things.

Though we’ve had the concept of going inside / outside of buildings for a while, it was half-baked for pretty much everything but the player.  This system has been completely revamped to handle just about anything.  In our object hierarchy, we added an object type called Renderable that keeps track of what building it is inside of and whether it should be rendered on screen, or fading in / out due to a building transition.

Last, but certainly not least, we refactored the Soundboard object.  The Soundboard object has been growing quite a bit since its inception at the top of 2019, but there hasn’t been a lot of cleanup to it.  We recently started hardcoding different looping sound effects, like rain and fire, instead of putting them in the Soundboard for it to handle.  We’ve now “rewired” this so that it handles a lot more uses cases, and should be much easier to expand down the road.

Art Updates Part Three

A lot of progress has been made on the art front of Violet, and we can’t wait to share with you the progress.  Since the last post, we’ve primarily been focusing on heavy weapons and the hero’s animations.  Much like the balanced weapons, we first start out with a rough idea to make sure the motion seems right and that combat feels right.  Once confirmed, Tony goes through and polishes the animations.  It’s a fun loop and is super exciting to see the progress as each animation comes in.  Without further ado, the polished heavy swings:

Hero Axe
Hero Axe
Hero Mace
Hero Mace
Hero Pickaxe
Hero Pickaxe
Hero Warhammer
Hero Warhammer

We currently have four unique weapons in the heavy weapon category:  Axe, Mace, Pickaxe and Warhammer.  While we were writing the previous post, we were polishing the balanced weapons.  Unlike the current balanced weapons that all look very similar (since they are currently some kind of a sword), each of the heavy weapons have an obvious distinct look to them.  Therefore, we decided to show off each direction of the animation as well as showcase each weapon.  We think it looks awesome and the animation really sells the gameplay.

Environment

The next major art piece that was worked on was fire and all their corresponding animations.  There were tens of different animations we did for the fire as we created not only different intensities and heights, but fire with motion (i.e. fireball).  We’ll only show off one of the animations, but then show an updated screenshot of a wildfire:

Fire Animation
Fire Animation
Wild Fire!
Wildfire!

Tony also worked on a few other static assets as well.  We added a birch tree as well as some treasure chests.  Here are a couple of scenery screenshots showing off these:

Birch Tree
Birch Tree
Treasure Chests
Treasure Chests

Other Notable Updates

Last time we focused on building a tile system that could handle the best of both worlds — using Game Maker Studio’s tile system for better framerate as well as using the precision of objects for collision.  This system has worked great, but with a brand new overhaul comes some polishing and refactoring to that system.  Thus, the last couple months was focusing on refining that system as well as working on other optimizations.

Another reason why we had Tony work on fire animations this time around was because we also wanted to optimize / clean up the way fire was done.  For example, for every step of the game, we would get each fire’s adjacent neighbor.  Instead of doing this every step, we only get the neighbors when the fire was created and removed / updated the neighbors when a fire was combined or put out.  This was a lot easier said than done, but we manage to get it working.

We’ve also noticed an issue with garbage collection in Game Maker that has been causing some frame dips.  We’ve done a few things to try to remedy this, but we’re pretty certain the issue lies within the Game Maker engine and not our game.  GC was a new feature implemented in Game Maker 2.3 and one of the newest minor releases are still working on addressing garbage collection issues.

We also fixed a number of TODOs as well as squashed a few bugs.  One nagging bug was when shooting an arrow would randomly crash the game.  Come to find out when we updated some code around the arrow several months ago, we forgot to update the scenario when an arrow completely stops.  The chances of an arrow completely stopping are slim because it usually would hit the boundary wall, unloading the arrow.  But in edge cases where the player would unload the boundary wall in such a way where the arrow was still flying, the arrow would eventually come to a stop, causing the code in the broken scenario to run, crashing the game.

And finally, we added a feature where talking with an NPC would have them “predict the weather” for the player.  Along the same lines, we also added a feature to have the player ask a “person who controls the weather” to change the weather to be whatever the player desires.