Create Your First Project
Start adding your projects to your portfolio. Click on "Manage Projects" to get started
Liquidate
Overview
Liquidate is a project I made in my second semester of my first year of university, which I later revisited to add some final touches.
It takes very heavy inspiration from the game ULTRAKILL.
Project type
Fast-paced shooter
Date
February/August 2025
What I Did
I created various weapons, each with primary and secondary fires. The starter weapon shoots singular projectiles for its primary fire and has a piercing railgun for the secondary. There is also a shotgun that fires a volley of small, weak projectiles as its primary fire, with a grenade that launches enemies and the player for its second. Next is a nail gun that shoots very weak individual projectiles that get stuck in enemies or the environment, which the secondary fire uses to create chains of lightning. Finally, there is a flamethrower which shoots a cone of flame that can bend around objects for its primary fire, shooting flammable oil with its secondary fire.
There are five different types of standard enemies: a melee unit, a shooter, a mini-boss (that later comes back weaker as a normal enemy) that can change between shooting and melee, a bomber that explodes when near the player, and an enemy that teleports around the area, firing attacks.
In addition, there is a boss with two unique phases. In the first, it moves around erratically, attempting to avoid the player’s attacks, while triggering the turrets in the boss room and occasionally summoning a beam to shoot at the player. In the second phase, it runs directly at the player, alternating between melee attacks (swinging at the player when close and leaping at them if they are far), summoning enemies, triggering the turrets and shooting beams.
The player can parry all enemy projectiles and melee attacks, except leaps, and gains a friendly AI during the game that helps them fight enemies. The game also includes a few cutscenes for the main boss and the mini-boss.
Throughout the game, VFX and sound are used to give feedback and improve how the game feels.
How I Did It
The primary fires for the starter weapon and shotgun damage enemies when colliding with them using an interface. The rail gun on the starter weapon uses a sphere trace, which returns everything it collided with. The shotgun’s grenade damages everything in a collision sphere surrounding it when it hits something. The nail gun’s nails attach to enemies by spawning a new object, which allows for chaining, attaching it to whatever surface the projectile hit, and copying the world transform of the projectile. Finally, the flamethrower uses a second, invisible, particle emitter that reports when a particle hits something, igniting any flammable objects around the impact location. The secondary fire shoots a projectile that spawns an oil spill wherever it lands.
Parrying enemy projectiles works by briefly activating a shield. Projectiles that hit the shield have their velocities changed so they move towards the mouse location, and their collisions are altered so they can hit enemies but not the player. If an enemy hits the player with a melee attack while the shield is up, the damage is multiplied and reflected back at them.
The melee enemy paths directly towards the player, tracking their distance to the player to check if it’s within melee range. The shooter attempts to stay within a distance range from the player using an EQS, firing at the player when they are at an acceptable range. The mini boss spawns between the shooter and melee behaviour based on a “random” chance that is weighted by how much health it has remaining. The bomber works identically to the melee unit, only exploding rather than attacking once it gets in range. The teleporter uses an EQS to generate random points in the room to teleport to, using a lock-on attack between teleports.
Each room has a manager that spawns enemies in waves and closes the room’s doors when combat starts. A room is triggered when a player overlaps with its trigger box.
In the boss’s first phase, an EQS is used to generate points that guide the random movement. It also calls in a wave of regular enemies when its health reaches 66% and 33% by manually triggering the room manager.
Both phases use event dispatchers to trigger the turrets around the arena, but spawn the beams they shoot at the player.
The leaping in the second phase uses the player’s current velocity, location and the duration of the leap to estimate where the player will be at the end of the leap (assuming no acceleration) and aims for that location.
The friendly AI targets a random enemy, then leaps at it to damage it. It targets the same enemy until the enemy dies.
The cutscenes use a level sequencer to animate the skeletal meshes and cameras, possessing the actual enemy in the case of the boss’s phase transition.
The project uses hitstop, Niagara systems, and a mix of sounds sourced from Soundly and made with Foley recordings.
What I Would Do Differently
While the weapons do share a parent class, the shared functionality is limited to an event triggered by player input. If I were doing this now, I would use the template pattern in the weapon parent, saving me from repeating code (e.g. hard-coding a shoot sound every time), making it more maintainable for myself and other developers in a potential group setting.
I would also look into other ways of igniting things with the flamethrower. I used the particle system to report collisions because it allowed things to be ignited when the fire bent around an object, which I couldn’t do with a sphere trace, for example. And while I didn’t experience frame drops from activating the flamethrower due to reducing the number of particles reporting collisions, I’m sure there must be a more performant way to achieve the same result.






















%20transparent%202.png)

