Last time I posted here, there was a small part about an Enemy Spawner rework that occurred during development. But did you know that there were a few more iterations of the system? At the time of writing, the enemy spawner got it's (hopefully) final iteration (though bugs are still possible), so I would like to go back and explain what happened to this system. I hope this could shed some light on the changes that can occur during game development. Please note that the gifs used don't reflect the final game, they are old gifs I had of the game.
Long ago, in the first few months of the game's development, my main inspiration for the enemy spawners was something very similar to Paper Mario. This was very, very early in development, back when there was no real direction to the game, but the game was mostly trying to be a shameless "Paper Mario" type of game (it steered away from that since). Thus, enemies would always all spawn on room load. Each enemy had a specific location, and there were few spawners, to make sure levels are not flooded by enemies.
This early build had no way to get a first strike, or an ambush: the attack functions were not implemented yet. Heck, the battle scene was just place-holder states, testing out the three methods of exiting battle: victory, retreat and defeat.
Despite the rough system, this served as a basis for upcoming versions:
- Spawn locations are defined on the map through a map editor.
- Spawn locations have an ID that refers to on of the many lists of possible encounters (with odds).
- The battle starts when you touch the foe.
But this system was pretty much untouched for a while, even after a real battle scene was created.
Version 1.5, Attacks Available
The attack on field wasn't implemented until quite a while, after significant work had been done on the battle engine. Each playable party member (Yvonne, Ethan and Emilie) had their field attack use the same animation as their in-battle attack animation. During this time, it was the still same enemy spawners: all enemies are spawned at once. The AI for the enemies was coded differently, and now, they could be exhausted and stop chasing you. Emotes were created to distinguish chase and abandoning pursuit.
Since I had no idea how to implement first strike/ambushes at the time, I experimented with two ideas at that time.
Method 1: Compare the position of the player and foe, and where they are looking at.
This is the most basic implementation: based on where the player touched the foe, it would be a first strike if you touched behind the enemy, or an ambush if you were touched behind. However, there were two problems with this method for this game:
- It poorly utilized the attacking system in place.
- In a 2D side-scrolling world, level design would often be an obstacle for the player if they sought after a first strike or tried to avoid an ambush.
Because of those two points, level design would either have to be much more basic, or the system would need to be changed. So I changed it.
Method 2: Make each character's attack have specific properties
Now, touching a foe would always start the battle normally. In order to get either a first strike or ambush, you would need to be a specific leader, and meet certain conditions:
- Yvonne: Being the slowest character (at the time), Yvonne had a very slow attack, with a long time after the attack where you couldn't do anything. Yvonne therefore had a risk/reward system: hitting a foe with the axe would always guarantee first strike. However, if Yvonne even touched a foe, it would always lead to an ambush.
- Ethan: Ethan used a similar idea to the first method I implemented to get a first strike, but this time it required you to attack the enemy. Unlike the original method, you could cancel out an ambush by attacking the enemy if they see you.
- Emilie: Emilie... wasn't actually implemented. I was actually struggling to figure out what to do for her, so her system worked exactly the same as Ethan's.
Because of the gimmicky methods of entering first strike/ambush, a description was added during in the screen transition between field and battle. However, the descriptions were very long, and not easy to read due to how short the animation was before the battle.
The system was left as is for a while...
Version 1.75, Enemy Properties, New Vision System
(Pictured above: Another very old, out-of-date picture, just showcasing the new emotions enemies have and their vision capabilities)
One thing I did not mention was how enemies could detect you: it was a very poor system that, when multiple enemies where in a level, would cause lag. This caused me to changed how they detect the player. Now, a vision hitbox was created, attached to the enemy, and collision with the player would activate the enemy's pursuit mode. However, to compensate for walls and obstacles that would block vision, there is also a raycast check to see if the enemy can truly see the player when inside the vision hitbox.
This led me to create some other properties for the enemies: at first to adjust the size of the vision, then the sprite it would use for the enemy, and later the patrol (no player in sight) and pursuit modes. Two exist so far: a grounded patrol, and a flying patrol. There is for pursuit three modes: a grounded pursuit, a chase through the airs, and a dive from the skies.
After this last change, the system remained intact for a while, as I focused on other things. However, during the creation of the first mission in the game, I've realised that the system as a whole was restrictive and easily manipulated. One could easily bypass all enemies, or the level design would take a hit. The gimmicky nature of attacking foes was troublesome and not intuitive. After a while, there was a massive rework done over time.
Version 2, Random Enemy Spawners
I took inspiration from Tokyo Mirage Sessions #FE for how they handled enemies on the field. In that game, an enemy would appear somewhere near the player after a certain amount of steps, the player could attack it to stun it. If the stunned enemy isn't touched by the player, it will disappear after a while. Touching an enemy after they were stunned does not guarantee a first strike, just as being attacked by an enemy without hitting them does not guarantee an ambush, but both cases increase or enable the odds. Ambushes in that game were very rare, in fact.
A similar system was implemented. The first major change done was to the enemy spawners: now, no spawner had a foe on the field, each one on a cool-down. A global timer would loop for a random amount of seconds between 2-8 seconds, and on every loop, the game would inquire all on-screen spawners, to tell them to spawn enemies. In addition, a final, "aggression" system was in place: the longer the player had not entered a battle, the more enemies would be allowed to spawn at once.
The player could stun a foe with their attack, but it would not send the game into a battle. Instead, it will remove the enemy after a while stunned. But, if you touch a foe while stunned, depending on how quickly you've touched the enemy from it's stun start, the odds of entering first strike increase! Ambushes are a random chance now if you touch the foe without stunning it, but they are low (1/4th of the time).
A enemy removal system was also in place: if the player distances himself more than a screen and a half distance, the enemy will be despawned, it's original spawner going back on cool-down, waiting for the global timer to grant it permission.
Another change that remains from this version is enemy elimination after entering a battle. Previously, entering a battle would not despawn all enemies on the field, so you would be chaining battles if you got surrounded. From this version, all enemies on the field are eliminated, so after a battle, there is a grace period.
Spawners are still hand placed, so tricky platforming areas, or large puzzle rooms, would not have spawners there. With this version, areas where there were spawners have more spawners than ever before, but the enemies spawn from only a few at a time, and at less predictable positions.
This version was used as base for the current version of the enemy spawners...
And now we come to today's version of the spawners, which will remain, although it will be tweaked a bit and I still need to fix a few minor bugs.
The first major change done was how the game calculates the time until it should spawn enemies: actually, it wasn't a timer anymore. Now, a "step" counter was in place: for every frame the player would move on the x-axis (left/right), it would add the distance to a step counter. A random value is calculated to determine the maximum value the step counter can have before it would spawn foes. The game spawns more foes as the counter goes up and the player doesn't initiate battle.
One major problem with the older version was that enemies would spawn seemingly out of nowhere and surprise the player. Now, a portal animation plays for a second just before spawning the enemy, and emits a sound. In addition to this, as the step counter would go higher, the odds of spawning a yellow portal would increase, up to 10%. These portals spawn a faster moving version of the field enemy.
To make the player be prepared for enemies to spawn, a color radar system was put in place. Similar to the one in Etrian Odyssey, it will go from green (OK), yellow and red (enemies will appear). A fourth colour, crimson red, was added, which signifies that the maximum amount of enemies are spawning and yellow portalshave a higher chance of appearing.
The step counter persists between rooms, making it hard to run away from all battles. However, after winning a battle, the counter resets to the approximately same amount of steps required before the next wave of spawns. However, there is now a low chance of having more extreme steps required until next wave: either a drought (triples the amount required) or a flood (halves the amount of steps required). In every case, all step requirements have some randomization to it, even the droughts and flood step counters.
The last change done was based on the step counter, the odds of having the enemy facing towards you increase, as before, all enemies would spawn facing the same direction. Very recently, I've also sorted the spawn order, so that the game attempts to prioritize enemy spawners near you and in front of your current destination, rather than behind you, although it is still possible.
Also during this time, the main properties of Yvonne, Ethan and Emilie's weapon were finalized, and as a result, some specifics for each character were implemented regarding stun:
- Yvonne's stun has the most odds for a first strike, due to her slowness.
- Emilie, because of her wave attack that's produced when attacking, can stun multiple enemies in a single direction, which is great for crowd control. But the odds of a first strike are much lower than the rest of the crew as a result, since she's also the fastest runner in the game.
- Ethan has the quickest attack animation, and has a balanced odds of first strike.
- The odds of an ambush do not change based on character.
In other news...
There are new button icons for keyboard and joypad! The best part is, now, the icons change on the fly, based on which device you used last! For example, if you press a joypad button while keyboard controls are on-screen, they will automatically change to the assigned buttons of the joypad!
This was also followed up by a full fix of the keybind/joypad rebind screen, which had issue with recognizing certain buttons. Not to mention, it now only changes the keybinds after you confirm the changes, so no more softlock if you bound the accept button to something unusable. Also, it will unbind any duplicate keys registered (ex: B button on a function will be unbound automatically if B is bound somewhere else).
Additionally, the top text in battle now shows the attack's icon, very useful for enemy-exclusive moves or for new moves that the player hasn't seen yet.
That's all for today! Right now, I'm going back on working on the mission content and cutscenes prototypes of the first mission.
Thank you for reading!