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.

Bartering Part Three

About a year ago, we started building out the concept of bartering in Violet.  In the first post on the subject, we explained where the idea came from, how it could be an interesting mechanic, and the drawbacks associated with it.  In the second post on the subject, we described in a little more detail how the player would be able to choose what to barter and the system that was needing to be updated to make that happen.

When we started working on it again, we wanted to get closer to solving the problem of “making bartering less tedious”.  Before the improvements, the NPC randomly chooses from our inventory items to trade.  We added a way for rejected items in a trade to not reappear randomly.  However, by using random, we would rarely ever get those items right — adding to many rejections until we would give up and choose the items ourselves.  This resulted in many, many clicks, adding tedium to the game.  Buying goods and services in games with an established currency is as simple as choosing the item / service, and confirming the purchase (and assuming enough funds exist for the player to make the said purchase).  This is essentially two clicks.  We wanted to get as close to two clicks as possible.  How could we get closer to solving for this?

If you haven’t guessed, removing the random element for the NPC to choose items was the first step.  In order to get close to “two clicks” we need that initial trade to be what the player would want to trade.  If we can get it right on the first try, we get three clicks:

  1. Would you like to barter this burrito? <yes>
  2. Will you give me your two hot dogs? <yes>
  3. Thanks! <close>
Bartering Example
Bartering Example

So how do we make the game know that two hot dogs is what we want to trade?  Well, we’re glad you asked!

Coming Up With THE List

Every barterable item in the game has a weight associated with it.  We can think of this weight as “preference” — the bigger the weight, the more preferred the item is for the player.  The least preferred items are sorted at the top of the list while the most preferred items are at the bottom of the list. When the NPC starts determining whether they like the item or not, we start at the top of the list with the player’s least preferred items.  If the NPC likes an item, we add it to the list.  If they don’t like the item, or the combination of items, it doesn’t get pulled into the list.  Since we start at the least preferred items, we’re almost guaranteed that the player will be happy to trade the items.

Bartering Trade
Bartering Trade

Defining these weights gets a little bit trickier.  As the games continues to be built, we will add / update these values.  But here’s what we’ve come up with so far:

  • When the game boots up, all items start at a weight of 0.
  • When a player uses an item, the weight is globally incremented by a small value (weapons = 1, bows = 5, rods = 10, materials = dependent, but a smallish number).
    • Therefore, the more an item is used, the more preferred it is.
  • When bartering, if the player rejects a list, (and eventually the player DOES accept a trade), each item’s weight in the rejected list gets incremented by 100 globally.
    • This is because we assume the player rejected the item because they prefer it.
  • When bartering a weapon, if there is a difference in rank, we locally increment the weight by rankDifference * 250.
    • If we want a C ranked weapon and the NPC sees a D ranked weapon, the weight locally decrements by 250, making it less preferable.
  • When bartering, if the player rejects a list, for the session (locally), each item’s weight in the rejected list gets decremented by 500.
    • This is because when the NPC “searches again”, we don’t want the similar items to appear again.
Bartering Dialog
Bartering Dialog

Though the above isn’t perfect, it gets us much closer to a bartering system that is less tedious and closer to the “two click” dream.

Other Notable Features and Fixes in the Past Two Months

Like usual, I began to think there wasn’t as much accomplished in the game.  But as soon as we look at the commit history, we realize we’ve been busy with many awesome things.  Take a look:

  • Any object we want to have collisions with weapons can now do so:
    • For example, we can cut down a tree or break rocks with our weapons
    • Using an axe with a tree won’t level down the axe, or using a pick axe with a rock won’t level down the pick axe
    • However, other items with these said objects will level down them down
  • We added a (rough) tree falling animation, as well as stumps for each tree

    Cutting Down Tree
    Cutting Down Tree
  • Any object we want to take damage from temperature extremes can do so now:
    • We really wanted the special weapon “bomb” to explode when near fire, or in extremely hot places
  • Fire Transfer on Weapons is much more refined:
    • We currently had it working with arrows, but now we can fairly easily add to whatever
    • We added to the stick weapons, which can now act as a torch for the player

      Stick on Fire
      Stick on Fire
  • We added more placeholder sound effects:
    • As we started adding more collisions, it was getting jarring that the same effects would play
    • We also added looping sound effects, rain and fire, which ease in and out as there is more of it
  • We added slope tiles:
    • If we are moving up and the slope tile is down, our speed will decrease
    • If we are moving down and the slope tile is down, our speed will increase
    • These are currently near cliffs, but we can be added anywhere
  • Updated the collision of walls routine:
    • We noticed an anomaly with dodging in that huge amounts of speed were gained, even when colliding with a wall.  This has been patched so there is no clipping through walls this way (sorry speedrunners 😉 )
    • We also added a get unstuck routine, which basically finds the center of the hitbox of an object, and pushes the object that got stuck away from the center
  • Updated camera zoom functionality to be more robust
  • Fixed a memory leak on the pause screen

We also have two other big features that we’re going to make dedicated posts for:

  • Updated / fixed the throwing of objects
  • Added a disable rooms script to Game Maker Studio 2

Special Weapons Part Two

In our last post, we gave an overview of the special weapons in Violet.  We were still working out the names of these as well as the functionality.  Over the last couple months, we’ve experimented, polished, tested, and then refined each weapon where we feel we are in a good place.  These weapons are unique, but still feel balanced with the rest of the game.  The weapons also don’t cause major game breaking bugs anymore, and fit with the rest of the item system we’ve previously built.  So without further ado, let’s get into it.

GMS Tasks / Draw Container

In a more technical post, we created two open source repositories for others building games with Game Maker Studio to use.  One problem we were frequently running into the last couple months is build times.  With many experiments and polishing of special weapons, even the slightest change would take 45 seconds to test.  This is frustrating if, for example, we wanted to see how changing the a weapon’s speed of 3 to 4 felt.  For our current project, rooms take 15 seconds of the build time.  And for most cases (especially testing special weapons), we don’t need to compile all the rooms.  Thus, we wrote a script to disable / enable rooms in GMS.  This has dropped our build times from 45 seconds to 30 seconds.  As we add more and more rooms, the time saved is going to be exponential.  We added this script in GMS Tasks, which can be learned more about it here.

We also patched a few issues in the Draw Container repository, as well as added a property to flow called stack.  We can read more about it here.

Refactoring / Collision System

It was that time again — refactoring.  Our TODO list was getting quite large.  The majority of the items in the list were revolving around the collision system with items we’ve previously built and the hacky implementation of the new special items.  Since the high level ideas of our special weapons were working, it was time to refine the system we had in place.  After a couple weekends of white boarding and implementing, the collision system was better than ever!

New Collision System
New Collision System

The system should be robust to handle any situation we dream up of now — assuming it follows the flow above.  Each weapon has three distinct special case functions that are allowed to alter the behavior of a collision and the result from it (for example, the direction to move, how fast to move, how long to be stunned, etc.).

There was quite a bit of other refactoring done as well.  Much of it was around the special weapons and their intricacies — which is a great segue into the meats and potatoes of this post.

Bomb Gloves

Bomb Gloves are used to create bombs from the earth.  Though we haven’t built a concept of from the earth (which means bombs can be created anywhere currently), we have updated how bombs are created and how they work after they are created.

First, bombs use the same structure now when trying to create weapons.  This means once we’ve started to create a bomb, we can’t also try to swing a sword.

Second, we decided to refactor weight in our game.  Before, light weight things had a weight of 1, the hero and the soldier type enemies had a weight of 3, and heavy things had a weight of 4.  This worked fine initially, but proved to be a problem for many reasons, which we won’t get into as that would be “getting into the weeds“.

When picking up objects in the game, the heavier the object, the longer the animation plays out for the hero to pick up the animation.  Since we don’t have an actual animation for creating bombs from the earth, we decided to simply use the picking up animation for now, but set the bomb’s weight to 333.33 (for comparison, the hero and most soldier enemies have a weight of 100 (roughly equal to 180 pounds)).  The bomb would use this weight to delay the animation for a long period of time to “fake” the idea we are creating bombs from the earth.  Once we have created the bomb, we set the weight back down to 50.  The speed at which objects being carried, as well as the damage dealt by being hit by a thrown object are based on the object’s weight.  Thus, we didn’t want a bomb dealing more damage being thrown than exploding, and we wanted the hero to move when holding the bomb. 😉

Third, which was the biggest change, bombs now can explode in the hero’s hands.  This took a lot of restructuring, as before, the game would swap the real object with a holdable object that resembled the real object.  The problem in this case with the bomb, is we wanted to have the bomb explode in our hands, but the object we were holding was not the actual bomb.  Thus, the animation timers would only run when we threw the bomb.  We would also reset the animation of the bomb if it got picked up again.

Bomb Still Ticking
Bomb Still Ticking

We decided on this change because we want to have puzzles where there was a wall in an area that doesn’t have earth.  Thus, the key to the puzzle is creating a bomb in earth in one area and transporting the bomb to the wall needing to be blown up, without the bomb going off.  We would never have had the solution of transporting, since the bomb would never go off the way it was built before.

Now holdable objects contain the reference object, which is still active and allowed to perform timers.  But the position of the reference object (aka, the real object) is relative to the holdable object, which makes it look like the holder is carrying the reference object.

Boomerang

If you remember from the previous post, the boomerang was a working name.  We spent weeks trying to come up with a unique name / weapon that followed the conventions that we previously built.  Guess what we settled on?  A boomerang!

Updated Boomerang
Updated Boomerang

As we were brainstorming, we stumbled upon this youtube video and this site that gave us the inspiration we were looking for.  See, we didn’t want a traditional “C” shaped boomerang, because the boomerang’s flight in Violet’s could be controlled.  So as we were brainstorming, we wanted a weapon that made “game sense”.  When we discovered that boomerang’s didn’t have to be “C” shaped, a light bulb went off.  “What if it was still a boomerang, but the design of the boomerang was unique, which is why the boomerang is able to be thrown so precisely?”  And the rest was history.  You’ll have to excuse the art for now, as it is something I drew up.  But the idea is that it has a double “C” shape, that sort of resembles a Violet leaf.

The boomerang is now considered a weapon, which follows the collision system above, as well as the player not being able to use other weapons when the boomerang is pitched, drawn, thrown and caught.  We also added animations for throwing and catching the boomerang.

When drawing the path, we made it harder to draw lines that turn 180 degrees.  Essentially, there is always a bit of a curve when changing directions rapidly.  Boomerang’s at the end of their path will also not immediately turn back to the hero (unless the path drawn was turning towards the hero), but will arch around like a traditional boomerang would.  When collided with the boomerang, enemies will take 20 damage each time they get hit, as well as being stunned for some time.  If skilled, the boomerang can become a mighty weapon to keep enemies at bay, as well as a useful stun tool.

We refactored the camera as well for panning purposes.  We already had a hacky solution of the camera being able to follow the line, and then pan back to the hero.  But now, we’ve added the ability to easily pan to whatever object we want in the game, for however long we want the pan to take.

We believe the polishes we have added will make it a great weapon in combat, as well as serve as a great key in solving puzzles with non straight lined distant switches.

Grappling Hook

The grappling hook was among the first things to get refined after our last post.  Like the other two special weapons, the grappling hook follows the collision structure we refactored, as well as being used as weapon which follows the structure for other weapons (i.e. the player not being able to use other weapons during use of the grappling hook).

The main concepts have pretty much stayed the same for the grappling hook, with the exception of adding longer ending lag (cool down) when the grappling hook reaches the hero.  We also made it so the grappling hook can’t hook enemies at shorter distances — therefore, making it a little less overpowered to repeatedly and instantly stun the enemy.  We also increased the damage output to 30.  And finally, we made it so the player can’t hook an enemy holding a shield (but this might change to let certain kind of shields be hookable).

Grappling Hook Cool Down
Grappling Hook Cool Down

Otherwise, much of what we discussed earlier with the refactoring also applied to the grappling hook.  The biggest being the weight issue.  We wanted the hero to move towards heavy, hookable objects.  But there was no concept of weight for anything but living objects, and it was poorly implemented.  Now, all interactable objects have weight‘s, which let’s us seamlessly execute code for hooking to a interactable and hookable object.  For example, a tree is interactable and hookable with a weight of 6000, which is much greater than the hero’s weight of 100, thus, the hero will be projected towards the tree.

The grappling hook is a great offensive weapon with its ability to stun and bring enemies towards the player.  Its combo into melee weapons will make it a great utility for players.  But the grappling hook’s lag makes it not great against a group of enemies.

Orb Shooter

The Orb Shooter has caused us much pain in the month of September.  In fact, we were planning on writing a blog post much sooner in September, but we went back to the drawing board on the Orb Shooter, and we really wanted this post to be titled: Special Weapons Part Two and not Special Weapons Part Two Minus the Orb Shooter.  However, we finally feel like we have something that functions the way we imagined, as well as not being too overpowered or underpowered.

If you remember from the previous post, the Orb Shooter is very unique in that it doesn’t deal damage, but creates a force field of orbs that acts as a defensive mechanism for the hero.  Before, the orbs orbiting the hero that collided with enemies would also do something.  At one point the orbiting orbs would stun.  At another point the orbiting orbs would do damage.  Another point it did both.  At another point, the orbiting orbs would stun if so many hit an enemy in a row.  And on and on it went.  We finally made orbiting orbs simply do nothing.  Astonishing, I know!  The thing that we were getting hung up over was that these orbiting orbs needed to do something offensively.  However, in the state of orbiting, orbs should just be the force field around the hero that act defensively.  We also played around with the orbiting orbs pushing enemies, but that didn’t seem right either.  Orbs orbiting the player simply protect the player from damage.

Orbiting Orbs
Orbiting Orbs

However, the Orb Shooter does play some offense (well defense).  As before, if the Y button is pressed, an orb will be shot towards the target, or in the direction the hero is facing.  Each orb acts as 1 stun point towards an enemy.  Each enemy, NPC, and the hero have unique stun points (SP).  The more SP, the more hits that can be withstood before being stunned.  If we shoot 4 orbs at an enemy with 4 SP, they will be stunned.  Orbs still don’t deal any damage, but with it’s recharging capabilities, this makes the Orb Shooter a great utility to fire orbs at your enemy as a “stun gun” — stunning your enemy for a short period of time.

Most of the time though, we want to use the Orb Shooter as a protective utility.  Holding down the Y button will continue to spawn the orbs to orbit around the hero.  When the Y button is released, a blast of orbs will be shot in one of two ways:

  1. If the player is targeting an enemy, the orbs will be shot in the enemy’s general direction.
  2. If the player is not targeting an enemy, the orbs will be shot in a direction away from the player.
Orbs Scattering
Orbs Scattering

In either scenario, the number of orbs shot will be the number of SP they have.  So in the above picture, each orb as roughly 26 SP — enough to stun any enemy in the game currently.  Orbs will pierce, making orbs hit enemies behind enemies.  This makes the Orb Shooter a great utility to stun surrounding enemies all at once.  However, tougher enemies will not be stunned for very long.  And shields can block orbs.

The Orb Shooter may get more polishing as we see players use the weapon.  But for now, the high level attributes are bound to stay.  And we’re happy to say, it’s a ton of fun to play with — and will be interesting to see players master the Orb Shooter, as well as all the unique special weapons we’ve created!