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.

Art Updates Part Two

These past few weeks we’ve been focusing on combat animations for the hero.  When creating a new animation, we first start out with a rough idea to make sure the motion seems right and that it will work within the game engine.  Once confirmed, Tony goes through and polishes the animations — breathing even more life into the character.  We’ll start with the defensive animations:

Hero Front Flip
Hero Front Flip
Hero Back Flip
Hero Back Flip
Hero Side Hop
Hero Side Hop

These may look a little odd on a white background with no shadow — but in game they feel great.  It especially feels good narrowly avoiding an enemy’s attack while the animation plays through.

Next, the offensive dash:

Hero Dash
Hero Dash

Getting a boost of speed with this feels great.  The pose Tony struck up is awesome as well!

Saving the best new hero animation for last, the balanced weapon swing:

Hero Swing Balanced
Hero Swing Balanced

The requirements were to make the animation roughly around the same timing as what was built into the game currently, as the timing before the new animation felt good game play wise.  It was also required to make the last swing “feel more powerful” as that swing will also stun an enemy.  Tony was tasked with a tough mission — but he managed to make a great animation!  And in game, it’s great!

Environment

We noticed the perspective was a little off with the new cliff edges, so we decided to update:

New Cliff Perspective
New Cliff Perspective
New Cliff Perspective
New Cliff Perspective

We also added some great looking water animations as well:

New Water Animation
New Water Animation

And finally, we’ve updated the fort wall graphics.  Tony went the extra mile and added some personality to them as well:

Fort Outside
Fort Outside
Fort Inside
Fort Inside

Other Notable Updates

In the previous post we had mentioned that we were overhauling the object / tile system so that we could have the speed of tiles and the collision accuracy of objects.  After a good solid two months, we have the system nearly complete, and we are able to make the main demo room build again!  It’s been great being able to “play the game”.

To summarize this system, we essentially have “zones” that represent a 480×480 area.  We take the tiles (graphics) that are in that area (what we call a zone) and turn them into a collision mask.  When the game first loads, we load each of those zones, get each tile in that zone, and recreate ONE 480×480 object in that zone that represents the collisions for that zone.  Before if a 480×480 zone was full of 225 wall objects (each tile being 32×32), instead of there being 225 instances to process, we now only process one object that represents the collision of all of those wall objects, while drawing each of them as tiles.  The collision tree in game maker is fast, and the tile draw system in game maker is fast, so utilizing both of these to their potential has given us incredible performance boosts.  We continue to improve on this system, and now with the fort walls, are including depth as well.

One of the more complicated parts has been if a collision happens with the collision mask, determining which tile or tiles we’ve collided into.  Sometimes it is important to do something with those specific tiles (for example, grass, we should “cut it” when collided).  Therefore, we have to not only know what tile we’ve collided with, but also be able to modify the collision mask at runtime.  We may make a dedicated technical post on this in the future as it could be helpful for others using Game Maker Studio.

 

Art Updates Part One

Tony has been creating some amazing art and animations and we can’t wait to share some with you.  When we began our work in January, we decided to update the previous mockup of the hero to be more cohesive with some of the design and game elements that have been created since the original concept. Without spoiling too much about the hero’s attributes (such as name and personality), we had a few concepts that didn’t make the cut:

Hero Concept 1
Hero Concept 1

Originally we were trying to come up with “a Violet scar” on the hero.  We liked the idea, but wanted to try a few other concepts.

Hero Concept 2
Hero Concept 2

Playing off the scar idea, this concept showed a much older looking hero.  However, our hero is in his older teen years, and I don’t know too many teenagers who can grow a goatee that well. 😉

Hero Concept 3
Hero Concept 3

Though this hero looks like a beastly warrior, our hero begins his journey as an underdog.  We originally landed on this concept for our hero:

Original Concept
Original Concept

We decided to use the “scar” idea and have violet leaves growing out of our hero’s head.  However, when translating to 32×32 pixel art, we found out that the leaves made our hero looking like he was wearing a bow, giving him a more feminine look.

Old Hero Idle Left
Old Hero Idle Left

We didn’t recognize this until showing a few people the walk, idle and run animations.  So, we went back to the drawing board and landed on this concept below:

The New Hero
The New Hero

It actually worked out in our favor to update the scar from leaves to, well, a different leaf design.  We ended up going with an idea similar to Celeste where each time the player uses the special dash, dodge or spin powers, the violet in the hair would fade to brown.  It’s a cool subtle detail that helps give the hero his trademark design.  To do this, we take the below artwork and transform the odd colored pixels in the hair into violet colors, depending on how many petals in the UI are remaining:

 

Odd Color Concept
Odd Color Concept

Finally, we have an awesome walking animation and running animation.  Before, we simply just had a walking animation that cycled the frames faster the faster the hero moved:

Hero Walk Right
Hero Walk Right
Hero Run Right
Hero Run Right

Environment

Tony has also updated a lot of the grassland’s environment too — giving new color and animation to much of this biome.  You’ll see we also updated a few UI components as well!  Finally, we updated the graphics of the cliff tileset as well as made them more easy to implement in game:

New Grasslands
New Grasslands
New Grasslands 2
New Grasslands 2
New Grasslands 3
New Grasslands 3
New Grasslands 4
New Grasslands 4

Other Notable Updates

In the middle of January, we decided to update from Game Maker Studio 2.2 to 2.3.  For the most part, the port was pretty simple.  The biggest thing was that other became a struct, so we had to update all other to be other.id.  After that main breaking change was fixed, we began overhauling how walls and tiles worked.  Having proper tilesets for our new cliffs, we decided to start using tiles instead of objects.  However, our wall objects are critical to the AI we’ve created for enemies.  Therefore, we’ve been working on a way to have the best of both worlds.  We are close to having this system complete, but it is still a work in progress.  In fact, the main demo room doesn’t build right now because of the overhaul.  It will be nice to get back to “playing the game” again. 🙂

New Artist and Updates

Over the past year or so, we’ve been looking into what it would look like to hire a part time artist for Violet.  Back in 2019, Hannah, our original graphic artist decided to pursue other full time opportunities.  We took that time as a means to evaluate the progress of the game and to seek advice on next steps.  Over the following months, we decided to polish the game with functionality that was cohesive from a gameplay and story perspective.  In mid 2020, we were ready for an artist, but decided to wait because of the pandemic and the economic uncertainties.  In October of 2020, I paid off my house, giving me a lot more flexibility with my budget.  After some searching, we found an artist by the name of Tony Wojnar.

Tony is a freelance pixel artist based in Illinois with a lot of skill and a passion for games.  He has an eye for design and his attention to detail shows immensely in his pixel art.  Though we haven’t worked together long on the project, I can tell he is going to be great to work with.  Tony is going to give life and color to Violet, and I am beyond excited for what his capabilities will do for the project.

Other Notable Features and Fixes in the Past Two Months

We can easily summarize the last couple months with one word:  polish.  There have been so many bug fixes and optimizations that it would be impossible to list them all.  A big contributing factor to why so many things have been cleaned up was we created an input recorder.  This lets us “playback” the game with the exact inputs on the exact frames, making debugging to the frame possible.  We’re able to step through code and memory in ways we’d never been able to before because trying to play the game that precisely is almost impossible to replicate perfectly.

One big feature we added was the ability to heal during gameplay, instead of going to the pause menu.  We are able to equip an edible material to the d-pad and quickly heal our character this way. This way of healing is more fun and strategic since there is not a reason to menu in the heat of the battle.

Finally, the biggest update / refactoring goes to the Layer Depth system.  Several months ago, we built a system for crossing over bridges and swimming under bridges, depending on where the player approached the bridge.  This was working well for the hero, but enemies, weapons, collisions had no concept of this.  We had a lot of updating of the Solider AI system to account for bridges, as well as adding collision support for being in certain layer depths. Though this isn’t all the way complete, but we have overhauled the system enough that we have a good starting point.  Therefore, once we start building out areas, we should be able to update code in places that need a little tweaking.

How to Throw Objects in 2D Games

In the last post, one of the major clean up items we briefly mentioned was that we updated and fixed throwing of objects.  In this post, we’re going into detail on how that was accomplished.  Heads up — this is more of a technical post, but we will try to simplify the technical parts.

In Violet, we had an issue where if we were standing next to a wall and throwing an object, the object would “get stuck” in the wall.  This is demonstrated by this amazing illustration below.

Problem
Problem

The solution to the problem was not very hard to solve for.  However, we originally overengineered a solution by examining what direction a thrown object was going to determine if it should collide with a wall or not.  Each time we fixed the current issue, we’d find another scenario where the solution failed.  This prompted me to do a quick search on the internet, which yielded little results.  I’d been playing through The Legend of Zelda: Oracle of Seasons recently, so I decided to throw hundreds of bushes to figure out if a simpler solution could be accomplished.  Eventually a light bulb went off and I realized how simple of a solution this really was.  So, how do we throw objects in 2D top down videogames, much like the Zelda games of yesteryear?

How the 2D Zelda Games Probably Handled Throwing Objects

Since we’ve been developing Violet in Game Maker Studio 2, the code and examples will come from this engine.  However, the concepts should be transferable to the engine of your choice.

We have two variables we keep track of for picking / lifting / holding / throwing.  We are calling these variables holdingState and holdingholdingState can have these values:

  • false – we aren’t doing anything with holding objects
  • "picking" – we are currently in the picking up animation of an object
  • "holding" – we are currently holding the object over our head
  • "throwing" – we are currently in the throwing animation of an object

holding represents a pointer to the object we are holding.  For example, if we are interacting with a rock, holding would contain a reference to be equal to that said rock (hero.holding.reference gets us said rock).  We’ll talk about holding soon.

With these core variables in mind, we need the hero to start interacting and picking up the said objects.  This could look like a million different things, but our check is simply check a spot in front of the hero they are facing and see if the spot contains an pickable object.  If it does, and the player is pressing input for picking up objects, then we begin our pickup script.  We’ll talk about what picking up a pickable object looks like soon.  But let’s start to define what a holding object looks like.

The holding object is an invisible object that acts as a placeholder for the actual object being thrown.  This is the solution to the aforementioned problem in the original illustration.  See, by having an object act in the place of the object being thrown, we can fake a lot.  The holding object is always located at the hero’s x and y location, and we render the holding object above the hero’s head (or wherever).

Solution
Solution

We therefore have an illusion that the object is above the hero’s head, but in reality, it is located in the hero.  When we throw the object, it simply acts like a normal projectile being shot from the hero, and therefore, won’t immediately collide with the wall when thrown.

Holding Example
Holding Example

The holding object has a number of properties, and we’ll highlight a few now:

  • reference – a pointer to the object being thrown
  • holder – a pointer to who is holding the object.  If we set it to noone (null in other languages), that means the object is being thrown.
  • renderX and renderY – the location of where it is being drawn — the illusion
  • old_reference_mask_index – we use the hero’s mask for the holdable‘s collision so we ensure there is no way the object being thrown will hit the wall.  This keeps track of the original mask_index of the object to be thrown.

Now that we understand the basics of the holding object, let’s get back to picking up a pickable object:

/// @description pickup_pickable(conditionIn, inst) picks up a pickable item
/// @param conditionIn
/// @param inst
//assumes holding variable

var conditionIn = argument0;
var inst = argument1;

var success = false;

if (conditionIn)
{
  holdingState = "picking";
  holding = instance_create(inst.x, inst.y, obj_Holdable);

  //update some pointers
  holding.reference = inst;
  holding.holder = self;

  //we use the character mask here because the x and y location of holding is exactly the character
  //since we don't want the rock to collide with the wall when thrown, we want to make sure it uses the same mask
  holding.mask_index = spr_link_mask;

  //copy old mask index
  holding.old_reference_mask_index = inst.mask_index;

  //make the reference not have collisions
  inst.mask_index = spr_mask_none;

  //make the reference invisible
  inst.visible = false;

  success = true;
}

return success;

The biggest things to take away from this script are:

  1. We update holdingState to "picking" and create the holding pointer
  2. We set the holding‘s reference pointer to the pickable object, and the holder object to the hero (self, or this in other languages)
  3. We set the holding‘s mask_index to the hero so we ensure no collisions with the wall when thrown
  4. We keep a copy of the pickable‘s original mask, and give it no mask so while it is moving around inside the hero, it won’t receive collisions
  5. We hide the original pickable object, so we don’t see it inside the hero
Picking Up Example
Picking Up Example

Holdable

We can now talk in detail about the holding object.  If the hero is currently holding the holdable object, we want to set the render variables to a location where the hero is holding the object.  If we are currently in a picking up animation, we do some math to tween the object from its starting place on the ground into the final position above the hero.  We will always set its actual location (x and y values) to the hero’s (holder‘s) location.  Again, the rock is invisible, so we won’t actually see it in the hero.

We finally need to throw the object.  Throwing is actually pretty simple, other than the “maths” to calculate where it should go.  This again can be whatever feels right for your game, but we’re simply using some quadratic functions to tween the positions from the start of the throw to the where it should land.

When the player inputs the throw button, we should invoke the throw event of the holdable object, and set the hero’s holdingState to "throwing" and set the holding pointer to noone.

The throw event for the holdable object currently looks like this:

speed = 6;
direction = holder.animation_direction;

//the actual object (not the render, moves constantly)
var dist = predict_distance(throwTime, speed, speed, ease_linear);

//set final locations for actual and render
throwYEnd = y + lengthdir_y(dist, direction);

//set the starting location for the throw
throwYStart = renderY;

holder = noone; //the holder is deference since we are no longer holding

High level, this script sets the speed and the direction of the holdable object to be thrown (animation_direction is what direction the hero is facing, limited to 0, 90, 180, 270).  Since we’re dealing with illusion values, we need to calculate where the ending location will be.  We take the real location values and simply calculate linearly where the object will be in so many frames of game play (throwTime).

Then, in our step event, our renderX value will always be the real x position of the holdable object, but we can interpolate the y value to give it the illusion that it is being thrown.  Here’s an example of that:

if (direction_between(direction, 10, 170))
{
  renderY = ease_out_quad(thrownFramesCount, throwYStart, throwYEnd, throwTime);
}
else
{
  renderY = ease_in_quad(thrownFramesCount, throwYStart, throwYEnd, throwTime);
}

We should also point out that since the reference‘s visibility is set to false, we can’t see it.  In our drawing event of the holdable object, we draw two things — the shadow of the reference as well as the reference.

if (holder == noone)
{
  draw_shadow(x, renderY + shadow_yoffset + LINK_SHADOW_OFFSET);
}

draw_sprite_ext(reference.sprite_index, reference.image_index, renderX, renderY, reference.image_xscale, reference.image_yscale, reference.image_angle, reference.image_blend, reference.image_alpha);
Throwing Example
Throwing Example

When throwing is complete — whether the timer expired, or the holdable object hits a wall (legitimately), we need to “turn the reference back on”.  Each pickable object has a break event that we invoke at that time.  Currently with our rock, we simply call a shatter animation, but this could be whatever.  We also want to turn visible back on for the reference object as well as reset the original mask from the holdable‘s old_reference_mask_index.

Conclusion

Though this post covered a lot, there were still a lot of of details not covered in this blog post.  Therefore, we decided to host a simple example on Github.  This example is a very simple, stripped down version of what Violet is currently using.  You’re welcome to modify freely and use for your own projects.