Devlog 4


Player Controller V3

Liam: From playtesting, people didn’t like the new movement. For someone who didn’t know the mechanics fully, it was not intuitive and felt clunky, leading to the redesigned enemies constantly flooding them, as the enemies were designed to match the pace of a player who knew the movement. A lot of the changes I made I reverted. Sliding was made substantially easier to do, now being possible from a jump again. Players could dash a lot more now, and overall movement speed, jump height, and air control were increased. To still limit the player from being able to infinitely gain speed through jump-sliding, velocity transfer from sliding mid-air to ground and slide-to-air was tweaked. Gravity was also reduced, so the amount of velocity gained mid-air was decreased. The result of these changes is easily my most favorite version of the movement. It is a lot more intuitive and easy to control but retains some advanced movement mechanics that aren’t required to beat the game but serve as flourish-type movements. Air control didn’t need much tweaking; the system I implemented last time was received well. All that was changed was to increase air control overall a little.

Enemy Design

Liam: Even with the last enemy tweaks, the game eventually evolved into melding all the enemies into a small train and just running in circles. The initial solution for this was the ranged enemies, but they weren’t enough. My solution was to add a lot more projectiles to throw at the player. The Ogre enemy now shoots slower projectiles but in an arc of five projectiles. This was intended not to be super hard to dodge but instead block off some escape routes. The goblin enemies in later rooms now have a slight change to throw rocks at the player. The projectile is easy to dodge, doesn’t deal that much damage, but if you start kiting 20+ of them, it starts to become a bit of a challenge moving in a straight line. The fly also was redesigned to be a ranged enemy, taking the old behavior of the Ogre instead, shooting fast projectiles at the player. With initial testing, I found that the enemies were a lot more interesting to face. My usual muscle memory of the game didn’t work anymore, and I had to think a lot more about my movements.

Shaders and Game Art

James: One of the ways I got around not drawing art for the game was by using shaders. A big issue with the overall art style is the clash between pixel art and hand-painted/flat textures. The way I tackled the issue was, rather than remaking or making more art assets, I used a shader to downscale images to any resolution I wanted (32-bit).

After some research, I found a formula that I can use to snap the UV coordinates of a texture to a grid, giving it a low-res/pixelated appearance.


With this simple formula, I'm able to pixelize my water shader, non-pixel-art textures, and even create more textures for the wood and rocks out of noise.



This results in everything looking much more unified.

Another thing I used shaders for was the enemy gore and "shocked" system. To provide the player with better feedback when damaging enemies, I designed the sprites to update dynamically as they took more damage. A significant hit would cause a noticeable change, while smaller hits would result in subtler updates.

I achieved this effect by creating a mask overlay for the enemy sprite that progressively revealed more as the enemy's HP percentage decreased. Each enemy sprite required corresponding assets, including a gore layer, a gore mask, and a skeleton sprite for when the enemy was shocked. The setup looked like this:

The varying brightness levels (value) indicate what will be displayed at each percentage of the enemy's HP. Darker brightness levels are set to 50, meaning some of the gore will be revealed when the enemy's HP drops to 50%. The brightest level is set to 90, fully revealing the gore when the enemy's HP reaches 10%.

A Really Silly Bug

Liam: For about six weeks, I have been aware of a bug with the enemy spawner. Sometimes a wave would end prematurely, with some enemies still around. This meant any end-of-wave events, like gaining a new weapon, would repeat or even cause a wave to repeat, even when the player had moved on to the next room. For the longest time, I couldn’t figure out why. Only after my 10th time looking at it did it finally jump out.

For some context, each wave has x enemies that will be spawned. Every time an enemy is spawned, it picks from a random array of enemies, spawns one of them, then decrements “enemiesSpawned.” When an enemy dies, it tells the wave spawner that it just died, so the wave spawner decrements the number of enemies killed that wave. When x enemies die, it starts a new wave. Multiple waves can be going on at the same time; if there are only three enemies left in a wave, you don’t want the arena to be completely empty while you finish, so there is a threshold where a new wave will spawn when you are close to finishing the last wave.

When adding the gremlin and fly enemies, they were intended to spawn in a pack, not just one at a time. So I added special logic to the wave spawner so that if an enemy is marked as a “groupSpawn,” it would choose between “minGroupSpawnCount” and “maxGroupSpawnCount” when spawning an enemy like this. I wanted them to count as only one enemy being spawned because of how weak they are. To not break the above logic, I simply added the amount of the group that just spawned minus one to the enemiesKilledToEndWave variable to offset the random amount of new enemies.

This logic is correct; I even manually calculated each step to see if I messed up the math. But for some reason, extra enemies would “leak,” and waves would end prematurely because of that. Only after the 10th time looking did I realize that I subtracted the amount of group enemies I spawned instead of adding the amount.

This led to a lot of enemies being spawned unaccounted for, making waves think they had ended when they had not yet, making the issue cascade. The fix was:

wave.enemiesToKillToEndWave += groupSpawnCount - 1;

Instead of:

wave.enemiesToKillToEndWave -= groupSpawnCount - 1;

I find it a bit funny that the problem was that stupid. I spent a lot of time debugging and double-checking the logic without first simply checking that I typed everything correctly.

Get Project Clockwork

Leave a comment

Log in with itch.io to leave a comment.