You can view this content for free after you Log In or Sign Up.
Devlog: New Sidearm + Some Revamps
Smaller Recent Additions:
Enhanced "Loot Detection / Pickup" logic
Updated "Item Memory": (remembers items picked up by player)
Reusable functions, resets at Game Over, Save / Load Game Data
8px High Water: allows water splash effect without speed decrease
Tweaked Axe properties (it can destroy blocks now) (experimental)
Tweaked Firebomb damage (now resembles CotM)
Wallhugger Enemy (it loops around solid walls)
Save / Load Game:
One of the biggest new features is the ability to save and load game data, like in Zelda.
I haven't designed a save point YET; just the functionality to save & load (which I access via in-game hotkeys). Before then, I'll have to solve some additional problems first.
The game itself isn't being saved; the game is just remembering specific data its told to, like: player position, health, ammo, items and upgrades collected, and so forth. So any time I add a new feature the game needs to save, I must manually add it to the save / load functions.
Shield Subweapon:
A new sidearm appears -- the shield! I experimented with this weapon in the old engine, but it has never been truly featured. It has since changed in the way it functions.
This weapon exists for two reasons:
1. Solves a game design problem: allowing the player to carry 2 sub-weapons out of a total 4 means they have constant access to half of the entire arsenal, and may never feel compelled to pick up any new sub-weapons. Thus, we need more diverse sidearms
2. Provides another way to deal with projectile-heavy rooms or medusa heads.
The shield is a defensive weapon that deals 1 damage to all enemies that touch it. So it is only effective against enemies with 1HP that die in a single hit.
When used, the shield will remain in front of the player until they run out of WP or perform any action that interrupts their "guard" (attacks, backflips, getting hurt, etc). The shield only costs 1 WP to activate, but will consume WP every time it hits an enemy (alternating 1 and 2 WP).
-
The old engine's shield constantly drained 3 WP per second and required actively holding the button to keep it up. Although this prevented the shield from invalidating any challenge, it also made the weapon too stressful to use. Hopefully this new design is a better compromise.
Implementing the shield in this engine was surprisingly complex. I ended up refactoring my enemy damage code and "weapon hitbox" feature. Weapons will no longer create a separate hitbox object (unless they are melee weapons), and will instead use their own collision masks to deal damage. Though in fairness, this is what I should've done to begin with.
Enemy Damage Scripts:
Enemies can now detect multiple sources of damage at the same time. Previously, they could only detect one source of damage at a time - which wasn't an issue unless the player wanted to attack an enemy that was already being burned by their firebombs.
This unfortunate quirk meant the firebomb would take longer to kill an enemy than it might in Curse of the Moon, as players could not expedite the process by attacking it while it burned. As a result, I ended up buffing the firebomb damage (but it still felt bad to wait).
However, now that this problem is solved, I've since restored the original damage values.
I am not entirely confident in this new system, as it uses DS Maps (Data Structures) to read a list of every weapon collision, loop through all of those weapons, check for various conditions per weapon, and finally add all of their damage together... It seems to work, but DS Maps are beyond my experience, and may result in memory leaks if handled improperly.
Water Variants:
We now have two variants of the o_zone_water object -- Poison and Hot Spring.
Players inside of a Poison Water Zone will take damage over time, and this damage does not trigger any iframes. As a result, players can still take damage from nearby enemies and can't exploit those iframes to avoid poison damage.
Players must instead carefully navigate these zones, use rations to heal through the damage, or use an item to negate the poison. So these poison zones CAN be quite dangerous.
Players inside of a Hot Spring Zone, however, will regain lost HP over time. Although the hot spring's healing powers are infinite, the process is quite slow. The player must wait within the zone for 2 whole seconds per tick of healing, requiring several seconds to reach Max HP.
These are a fun, flavorful, and diverse method of healing beyond simply hiding random wall chicken, and is a more unique secret to uncover. The waiting time also forces the player to slow down, providing them with respite from the potential stress of playing while they wait.
-
I've added so many things in the last two weeks, there's so many features that need clean up and sprites that need replacing.
You can view this content for free after you Log In or Sign Up.
Devlog: Enemy Updates
I've spent the last two weeks focusing on game development, having made a lot of progress. Very little of it is new content, per say, as I've primarily been recreating elements from the old engine -- particularly its roster of enemies.
Implementation has been much quicker, not only because I can reference my older code, but also because of the new tools I've created that improve my code's function & cleanliness. Of course, I can still streamline or re-translate it even further, but I'll save that for another time.
As of right now, only two enemies (excluding o_dracula, and the level 1 bat & zombie) are left, with every other enemy having been implemented in the new engine.
Recent Additions:
Enemy: Gargoyle Turret
Enemy: Nightcloud
Enemy: Fireball (variants: Base / Drop / Demon)
Enemy: Mudwoman
Enemy: Crawling Zombie
Enemy: Spike Trap
Enemy: Demon (now with a new previously cut attack animation variant)
Enemy: Ghost Orb
Enemy: Gillman (new functionality: custom jump height & leaves after attacking)
Enemy: Draugr Skeleton (Sword)
Enemy: Draugr Hunter (Axe)
Enemy: Skeleton Biker
Enemy: Hitbox Objects (used for melee attacks or extending an enemy's hitbox)
Streamlined Enemy Projectile functions
Additional Room Editor functions
Many of the enemies have been improved -- not only in how its code works, but in small ways that affect the gameplay. For instance, the Gillman and Demon now have more obvious attack telegraphing before shooting. I've also added a few new minor tools for extra dev power.
Function: Actor Create Projectile
I've created a new function that streamlines the process of making enemies that attack with projectiles. Enemies will call this function in their attack state, and the projectile created will depend on the information provided to this function.
For instance: I can create "o_fireball", and set it to use a sprite different from its default, so it looks like an entirely new attack, despite being the same object.
But there's more... I've created a set of projectile variables inside o_enemy, which can also be manually adjusted for every enemy instance inside the room editor. I can probably improve it even more, but this lets me customize the specific type of projectile created per enemy.
So two cannon enemies in the same room can shoot totally different types of projectiles. I don't expect to make constant use of it, but it's good that I CAN make use of it.
Function: Actor Create Hitbox
Similar to the previous function; an enemy may call this script to create a new hitbox object -- which can also be used for attacking, but its identity is much more generic. This hitbox can be used for two primary purposes:
A constant "body part" of an enemy, forming an irregular hitbox shape (like a T shape).
Generated during a state-exclusive enemy attack (like swinging a sword).
This hitbox can be destroyed after it has served its purpose, or it will simply follow its owner -- effectively acting like an extension of that owner (since an enemy's collision mask is typically only allowed to be a simple rectangle with four sides).
I can adjust its properties, like whether it will accept damage from the player. I can also apply a unique set of weakness values to the hitbox, so it can either serve as a weak point (like a big eyeball) or even block damage from hitting its owner (like a shield).
Now I can make it so that it dealing damage to an enemy requires hitting a specific part of its body or even reward players for hitting more vulnerable parts of the body. This was already an idea I had played with in the old demo, but the new weakness system lets me do even more.
It is worth noting that:
After implementing the remaining two enemies (since the rest are variants or a lazy boss), I'll only have a handful of gameplay features left to recreate:
Level: Crumbling Floor
Level: Mel Zones (updates the dialogue used by the Mel Button)
Level: Conveyor Belts
Mechanic: Show Portraits (previously used in game over)
Items: HP / MP Upgrades (And the Item Memory to ensure they can't respawn)
Dialogue System
While I may not recreate all of these systems immediately (or in the same way)... We've almost reached a point where the new engine is on par with the old engine in terms of development capabilities (that is, assuming I haven't missed anything and there aren't any hidden bugs). As a result, we might be able focus on creating new content & systems shortly after. Very cool.
You can view this content for free after you Log In or Sign Up.
Devlog: Backflip Adjustments & Weakness
A relatively small update, but with some notable changes. Mostly tweaks to older features.
Notice the brief pause & recovery period after landing.
Adjustments - Backflip:
I introduced Rondo of Blood-style backflips some time ago, but felt they were "too good."
Previously, it felt too effortless to perform a string of backflips in quick succession, providing way too much mobility for a game of this nature. Due to the lack of any recovery animation, a player could perform the action immediately after landing. As a result, backflips would quickly become a "meta" tool of traversal -- thus reducing the value of walking, sliding, and jumping.
Here's a showcase of the old backflip behavior:
Notice the lack of a recovery animation after landing... Too OP. Please Nerf!
So, I have since made two adjustments to how backflipping works:
Players can now backflip during the first frames of the Falling state (ONLY after jumping), essentially making the window for execution wider, and thus easier.
After landing, players enter a 25-frame recovery period during which they cannot regain control as their momentum pushes them across the floor.
As of right now, it's still a good tool for movement / skill expression that can be a "speedrun strat", since you don't lose much time -- but there's just enough friction in the recovery that I hope discourages frequent spamming. I'll continue to experiment to gauge my feelings.
Adjustments: Damage Calculation
I have finally implemented the "Plant" enemy, which hides in the grass until players approach. The enemy logic has also received several improvements:
Plant enemies can now function when placed on ceilings & walls.
Navigating around them is easier thanks to an updated hitbox and new player movement mechanics, such as backflips & sliding.
Plants extend more gradually, giving players extra frames to dodge.
However, I noticed an issue: Plant enemies required two whip hits to defeat, but three hits from the razor boomerang. This is because the Plant has 7 HP -- the whip deals 4 damage per hit, while the boomerang deals 3 damage per hit (since it can strike again on its return trip - thus an expected max of 6 total damage).
Although mathematically sound, this feels unintuitive because players may otherwise expect the razor boomerang to sever the stationary Plant's tentacles and instantly kill it.
There is also an unintended interaction where standing inside the enemy allows a single whip hit to kill it. These two behaviors feel wrong, both in terms of design and experience.
So I had to adjust how damage calculation worked, though I did so in very minor ways.
Damage Weaknesses:
Although I never intended to implement a resistance system, as that is a feature of the much more complex Igavania titles, such an inclusion felt appropriate here.
I DO NOT want to universally increase the boomerang's damage, since it is already strong. But, this really is an enemy I expected to kill quickly with this weapon (and firebombs too). The solution was to introduce a system that allows certain weapons to deal more (or less) damage against specific enemy types -- a simple weakness system.
Every enemy has two new variables:
weakness_
weakness_multiplier_
Both are arrays that function as a matching set and must contain the same number of values. The first array defines the specific weapon object, while the second defines the damage multiplier applied to that weapon in the matching "array slot."
Thus, the boomerang's base damage (3) can now be multiplied by 3 for this specific enemy, allowing it to deal 9 damage per hit and defeat the plant in a single hit. All other enemies will continue to receive the boomerang's base damage, unless they have their own multiplier. Pretty simple and clean!
Of course, I could also make the boomerang weaker on some enemies -- like an armored knight, who would instead take more damage from a piercing weapon... Like a dagger.
As a result of how the new engine handles weapon hit boxes, melee weapons create a new hit box every frame of their attack animation instead of updating a single hit box across the whole animation. For example, the whip's first frame creates a hit box behind the player, with each subsequent frame spawning a new hit box further along the swing.
This introduced an unintended issue: if the player is already overlapping an enemy, multiple hit boxes can connect during the same attack, causing damage to be dealt more than once. Which is conceptually cool, but not when it's unplanned.
To solve this, I added a "single hit" variable to player weapons. When enabled, the enemy will remember that this specific weapon instance last damaged it, and all subsequent hit boxes created by this instance (identified by its unique instance ID, not its object type), are ignored, requiring a new attack before that weapon can deal damage again.
It's a simple solution, but keeps changes to the older calculation code as minimal as possible.
You can view this content for free after you Log In or Sign Up.
Devlog: HIGHWAY TO THE DANGER ZONE
Small Changes:
Added the ability to jump during a slide (experimental, currently disabled).
Made it easier to execute backflips (experimental, backflips currently disabled).
Made it harder to land on stairs to reduce abrupt snapping when landing.
Added Life Doll (1-up collectible).
Added Harpy - Dropper Enemy (flies straight & drops a fleaman-style enemy).
Water Zones:
Added water zones. Entering water will reduce movement speed for players & enemies. The current implementation can be streamlined a bit when it comes to handling movement speed changes, but water splashes are now handled via a function that may be called in any object. Thus, now both players AND enemies can seamlessly make water splashes.
women when they see me
Enemy Spawn Zone:
This is the main feature of the latest update, and is among the most important objects in the old engine (so it's good we finally have it here -- and better than before). It's very complex.
The spawn zone is responsible for spawning enemies infinitely (this is how medusa heads tend to spawn), and there's a lot going on within the logic. It is more advanced than before, but also more streamlined too. I've been afraid to recreate this object, so I'm glad it went by so smoothly and that it's now (mostly) done.
me when women throw themselves at me
Starting with [ o_enemy_spawn_zone ]'s [ CREATE ] Event...
We initialize all of the relevant variables that control how the object functions. After placing it inside the room, I can access its Variable Definitions panel to change its properties: what to spawn, where to spawn, the length, trigger tag, etc.
Then we enter the [ STEP ] Event, which runs every computational frame.
Before any of the code, we check to see if the player is currently inside the zone (or a trigger zone with the same global trigger tag). We also begin counting down the spawn timer.
Once the Zone is activated by the previous player check, we count how many enemies have been spawned (so it ignores hand-placed enemies) in order to ensure we never spawn above the assigned max limit.
We can then determine the direction enemies spawn relative to the player, whether that's on the right, left, both sides, front, etc. That will return either a negative (left) or positive (right) 1 to use in an equation that selects a random X coordinate (within a range) for spawning. Then we move onto determining the Y coordinate (which is where it gets a bit more complicated).
For the Y coordinate, airborne enemies determine their own Y coordinate (for instance, the bat spawns at the player's Y while harpies spawn near the top of the screen) and some enemies spawn directly below the camera (like the gillman). Otherwise, we default our spawn to simply match the bottom of the Zone's bounding box (usually the floor).
New to this version of the engine; we now check if that Y coordinate is inside of a solid block. If so, the chosen Y coordinate will be moved up or down to ensure clearance. As a result, we can now spawn enemies at different elevations within the same spawn zone. The old engine required cheating by using Trigger Zones connected to a separate Spawn Zone.
After all that, we determine whether the spawn location is legal; which has 3 conditions:
Is the Target Point INSIDE the Spawn Zone?
Is the Target Space FREE (as in NOT within a solid)?
Is the Target Point DIRECTLY above the ground?
If the position is not legal, then it repeats - looking for a new X and Y position. If the position IS legal, spawn timer is finished, and we have yet to reach the Max Spawn count... We spawn!
When spawning an enemy, we toggle its internal [ can_despawn ] variable to true so that the spawn zone counts it and so the enemy knows to despawn off-camera.
I can probably streamline it a bit more, but it largely works as expected now. If any enemies require specific behavior, like spawning in the air, or counting its sub-spawns, I will need to plug them into the script (which is fairly simple now).
Let's take a look at two extra components. First a SWITCH in the [ ROOM START ] Event. Here, we can define whether an enemy MUST be spawned airborne, like the harpy. This makes it so that enemies are automatically spawned in the specific areas required of them.
We also have [ scr_spawn_count_get ], which is a function used to count all of the enemies spawned by the specific spawner. In it, we count the spawned enemy -- and its sub-spawns.
For instance, let's imagine a spawner has a max limit of 2 spawns. If a harpy is spawned, we have 1 Enemy. The harpy will also spawn a "fleaman", resulting in 2 Enemies. Of course, the harpy flies off screen, so we're back at 1 Enemy. Another harpy appears, back to 2 Enemies. This harpy spawns another fleaman, so now its 3 Enemies. The harpy then flies off, leaving 2 "sub-spawn" fleaman.
The Spawner counts those fleamen as part of the spawn limit, ensuring that no more harpies are spawned until one of the fleamen is removed, preventing the player from getting overrun by a hundred fleamen.
You can view this content for free after you Log In or Sign Up.
Devlog: Medusas, Food, and Extras
Enemy Behavior: Sine Wave
If you recall, I'm building enemy behaviors as separate, external functions that I can simply call inside an enemy, instead of hard-coding specific behavior for every individual enemy.
The classic Medusa Head flight pattern is now implemented. The arrangement is a bit more complicated than my old engine, but is technically easier to apply to enemies now. It also has functionality to scroll with the camera vertically.
So, for our Bat enemy, I can say: Run Horizontal Movement Behavior, then Run Sine Wave Movement Behavior. That's all that is needed for this enemy to perform its basic actions.
Another benefit of this system is that I can easily update the sine-wave pattern mid-flight. CV3 has a Flying Skeleton enemy that moves in a sine-wave pattern that increases in speed & length as it gets closer to the player, so this should allow me to do something similar.
The behavior needs some improvement, since it's too easy to avoid incoming bats.
Score -> Gold
The old demo features a bare-bones score system; collecting money & killing enemies raises the score and eventually results in a 1-UP. However, it was never balanced properly, and thus would almost never result in an extra life.
I've changed this into a proper currency system. Now, when players collect money, they are collecting an actual currency that can technically be spent in shops. I'm apprehensive about having to balance an economy -- but this may be more interesting.
As of current, it also behaves similarly to the currency in Dark Souls / Zelda 2. When players die, they'll drop 50% of their Gold. Players can recollect half of that if they manage to reach the spot of their death. So if you had 100G, you'll drop 50G, but can reclaim 25G.
Modifiers
I've begun implementing "Game Rule Modifiers" that can be toggled on / off. This allows me to test different interpretations of a mechanic, but some may also be accessed by players to modify the experience eventually.
One example of a modifier is: Cheap Sub-Weapons
The default cost for sub-weapon use depends on the item itself. For example, the dagger costs 1 WP but the axe costs 3 WP - the idea is that stronger weapons are more expensive to use. This follows the philosophy of modern Vania-likes.
The alternate cost (accessed via modifier) is closer to that of CV1; sub-weapons now cost much less to use. As a result, the dagger and axe both cost 1 WP.
Experiment: Rondo Backflips
Although it's currently only intended for developer use, I've added a Rondo-style backflip. At any point between the START of a jump and the point of DESCENT, pressing [ JUMP ] causes the player to jump AWAY from the direction they are facing. This can function as a tiny double jump that requires a bit of work or even "undo" a jump -- but a player needs to act fast, since they lose the opportunity to backflip the second gravity starts to pull them down.
I don't know if it's sticking around. It's not a very simple & clean maneuver and it will affect the balance of levels, and I don't have much experience with Rondo. But I'm willing to experiment.
Turning around mid-jump before a backflip is a bit like a double jump -- notice the increased distance.
Food Pouch
Another feature has been added -- Food Pouch, inspired by the Sub Tank in Megaman X. It serves as a tool to make the game a little easier.
Typically, acquiring food will heal players up to max HP -- and any excess food will be wasted. With the Food Pouch, any excess healing or food will now be stored as portable rations, which can be used at any point via the player's inventory. The pouch can hold 10 HP, which is approx. the entire length of Elayne's starting HP bar.
The red bar increases based on the amount of food inside the bag.
Small Changes:
Players now drop all sub-weapons on death (resets to dagger).
Players now lose all ammo on death.
Firebomb sub-weapon added. Its flame lasts 2 seconds and deals a possible max damage of 18. The values in the old demo is 14 max damage over 1 sec.
Concerns:
Let's talk about how enemies currently take damage.
The player's weapons create a hitbox that follow it. When enemies contact that hitbox, they take its assigned damage, then enter an invincibility state. That invincibility will last 15 frames (20 in old demo). This prevents enemies from taking constant damage -- otherwise an enemy that SHOULD take 4 hits will die in 1 hit.
But if I want to create a weapon like Bloodtained: CotM's Magic Charm (Holy Water), which does damage over time, we run into some issues -- let's look at some numbers...
The Firebomb in the old demo lasts 1 second and deals 2 damage on contact. When the bomb hits the ground, it creates a flame that does 4 damage. In the old demo (20 iframes), this will mean enemies would take a max of 14 damage altogether.
CotM2's Magic Charm lasts 2 seconds and deals 2 damage on contact. When the Charm hits the ground, it creates a flame that does 3 ticks of 4 damage per tick, so enemies would take a max of 14 damage altogether -- the same exact max damage.
... But if I make my Firebomb last 2 seconds, enemies will take MORE than 14 damage. This is because damage isn't delivered over ticks, but rather when the enemy's iframes run out. Thus, the flame now deals more total damage; a possible max of 18 (2 damage every 15 frames).
I don't want the flame to do less than 2 damage per hit in order to maintain 14 max damage, as that might feel too weak if the enemy only touches it for a brief second. But a damage value above 2 might feel TOO strong with the new iframes and Firebomb length.
That means I may need to re-evaluate my damage calculation in the future. Perhaps instead of giving enemies 15 iframes whenever they take damage, I may need to make it so that different weapon attacks will determine different iframes. For instance, the whip may give 15 frames of invincibility, but the firebomb gives 40 (40 goes into 120 frames three times -- three ticks). As a result, the firebomb will be able to deliver 14 max damage again -- but that will require quite a bit of rewriting.
You can view this content for free after you Log In or Sign Up.
Devlog: Hud Layouts / Inventory
Latest game development advancements.
HUD Control:
The HUD layout can now be changed to alternate layouts, to serve different tastes. While it would be nice to let players manually adjust every part of the layout themselves, that's a bit too much work right now.
So instead, players can simply alternate between different presets. Nothing too big, but we all have different preferences when it comes to HUD layouts. This is something I can expand on more in the future too.
Top Left Corner: Alternate HUD Presets
Inventory Manager:
This object is probably among the most complex systems I've ever had to program, having taken approx. 2 weeks to create (and it could still use more work).
The Inventory Manager does what its name suggests, though it's presence is atypical for an old-school Classicvania experience. It allows the player to store specific types of items that can be used at a later point without having to fit into the sub-weapon slots. As a result, they may not be lost upon death like sub-weapons are.
The Inventory Object has multiple states:
Closed
Transition
Open
With additional modes that layer on top once opened:
Browse
Action Select
Overflow Confirm
Inventory Basics Showcase
When Browsing, players can horizontally navigate the inventory. Attempting to use or discard an item enters Action Select mode, in which players can vertically navigate available choices. If the player acquires an item when their inventory is full, they enter Overflow Confirm mode, in which they can navigate all four directions -- allowing them to use the pending item on the spot or replace one of their older inventory items with it.
Every window is drawn to position & scale itself based on context in relation to the main box. The choice selection windows are a bit duct-taped together, however, so they won't always work reliable if the available options were scaled upwards. I may have to improve this system in the future - and also expand on the Overflow Confirmation system.
The inclusion of this feature provides us a few benefits I'll probably explore more in the future, like an expansion of the Mel Button feature (which has not yet been re-added).
I've also added extra skins for fun.
Customization!
Pitfall Recovery (Toggle):
A newly-added feature to the engine allows players to fall into instant-death pits without actually dying instantly. Although doing so is not free - there is a price for its activation.
Not only must the feature be toggled on, it also costs 1 HP and 10 Weapon Points. If these costs can not be paid, the player will not be rescued. Additionally, although not required to activate, each rescue will reduce the player's current Gold by 10.
This offers players a way to reduce frustration, but prevents it from being overpowered. You may only get 1 or 2 uses in a typical scenario and you may not want to lose more Gold.
This feature is why I created the Inventory manager object -- to allow players an easy way to toggle it on / off during gameplay.
Okay, give me a Beat! 1-2-3-4...
Early Save / Load:
Both of the previous GUI systems allow some degree of customization, but it would be pretty annoying to have to constantly change to your preferred layout & skin. So I decided to briefly explore the concept of saving & loading data.
While I don't have a dedicated save data manager system, I HAVE created a few small scripts that allow the game to save your preference and automatically load those preferences even if we close the game. This can probably be used for a proper system to save player progress in the future -- though it is unfortunately readable & editable by users, so there is a chance that other players COULD break something if they do so. Still, it's pretty cool.
Ability to support your Creator by pledging – one-time or recurring.
Means to reaching out to the Creator directly via Instant Messenger.
Subscribe
WE USE COOKIES
SubscribeStar and its trusted third parties collect browsing information as specified in the Privacy Policy and use cookies or similar technologies for analysis and technical purposes and, with your consent, for functionality, experience, and measurement as specified in the Cookies Policy.