CAGD 470 Group 1, Sprint 5
- Els Fouche
- Apr 11
- 8 min read
Kill Everything As Fast As Possible
Kill Everything As Fast As Possible is a 3D first-person boomer-shooter where you take control of a killer AI hell-bent on destroying every human in sight.
Project Credits:
Daniel Bocanegra-Ramos: Lead Designer
Jack Bradford: Producer
Dylan Brown: 3D Artist
Els S. Fouché: Lead Programmer, Level Designer
Sean Gibson: Programmer
Sophia Villenueve: 2D Artist
Rayen Yousfi: 3D Artist
Feature Festival
I set a new personal best for number of completed features during this sprint despite falling ill with the new "cicada" variant of COVID-19. I don't recall some of the work I completed due to fever, however upon review the code is mostly stable (with one notable exception) and functional. Here is the list of completed features:
The 'chainsaw' melee attack,
The 'railgun' weapon (charging, discharging, and firing),
The 'minigun' weapon along with fire rate and accuracy ramp-over-time,
The fire grenade variant,
Hazard areas (to go along with the fire grenade, e.g. an area that's on fire),
The ammo system,
A slight update and bugfix to the countdown on level start,
A placeholder system for weapon upgrades,
One of each of the weapon's upgrades:
The minigun's 'build-up bomb,'
The railgun's 'no limiter' power-up,
The pistol's explosive rounds,
The shotgun's 'dragon's breath' rounds,
The no-self damage upgrade for the rocket launcher, and finally
Some basic changes to the rocket launcher.
In addition to the completed features, I spent some time working on the aim assist system. It was my final set of cards for the sprint but, unfortunately, I encountered a block that prevented me from completing it. As of this writing the aim assist system is live in build version 0.2.7, available on the game's itch.io page, found here.
State of the Game
This sprint brings the game to a state that's mostly feature-complete.
To summarize, we now have:
A pistol,
Shotgun,
Minigun,
Railgun,
Rocket launcher,
One upgrade for each gun that moderately or significantly changes its functionality,
A grappling hook,
A dash ability that can be used twice,
Each dash has an independent cool down,
The dash and grappling hook deal damage to enemies when the player passes by them,
A chainsaw that can be used twice,
The chainsaw only works on low-health enemies,
Each use recharges independently like the dash ability,
Successfully using the chainsaw spawns ammo,
Momentum-based movement with the ability to break the speed limit by timing your jumps,
The ability to double jump,
Timed play with the ability to earn time by beating enemies,
High score tracking,
A currency used to purchase upgrades that's earned by beating enemies,
And of course the usual FPS features: health, armor, ammo, and the ability to lose a fight.
Unfortunately, the overall game flow is not quite where I want it as we head into sprint 6. The features I've been tasked with completing have been fun to work on, but I'd have preferred to spend some more time working on what happens when the player loses and on evolving the battle arena over time.
As is life, so is game making; we don't always have control over the direction things take. I've discussed the elements I'd most like to see with the designer and producer and the hope is that we'll be able to add these during this coming sprint. Despite this, it's unlikely that the final product will be as finished as I wanted.
Guns!
A big goal for this sprint was to finish implementing the rest of the planned weaponry. Please pardon the re-use of the pistol model for other weapons - our art team is hard at work finalizing the weapon assets.
Minigun, Speed & Accuracy Over Time

When the minigun is initially fired there's a pre-main-loop that handles firing the weapon until the accuracy and fire rate have reached their main values. It then enters the main firing phase which is handled by a simple looping timer. Notably, this timer is not set to trigger at most once per frame. This can create sub-frame firing events that will decrement ammo but not damage enemies. This decreases the actual damage-per-second of the minigun which is intended. Unfortunately, it does mean that players with better machines will be able to deliver more damage with the minigun. In terms of raw FPS, players will see decreased damage below 50 frames-per-second. The ideal FPS for this game is 30 but it goes too strongly against player expectations to force such a low frame cap.

The railgun utilizes similar systems for charging, discharging, and firing the weapon. As one might expect if you've used similar weapons in other first-person shooter games, the railgun only fires upon releasing the trigger.
Railgun, Charging & Firing
An upcoming change to the railgun will be to modify it such that it can pierce through objects in addition to enemies. As of this writing, the railgun also now features visual feedback as it charges in the form of the weapon shaking though this did not make it into sprint 5. The railgun's charging and discharging mechanic introduced significant opportunities for bugs to creep in - the player may switch weapons while the railgun is charging which can result in unexpected behaviors. Ideally, future playtesting will reveal if these issues will crop up in spite the checks I've put in place to prevent them.
Dragon's Breath Shotgun Rounds
The 'dragon's breath' upgrade for the shotgun was fairly simple. By extending our other programmer Sean's status effect system I was able to apply a burning effect to enemies hit by the weapon. The fire grenade uses this effect as well, but was complicated by the fact that the designer requested that it leave a hazardous region in addition to the status effect.
Fire Grenade & Fire Hazard
The fire grenade creates a damaging region when it detonates. The base class of this hazardous area tracks the actors inside it and dispatches effects to them. It provides functionality to be implemented in its children for applying effects both while the actor is inside and when they leave the region.

As can be seen above, this is a very basic way to handle the hazard area -> child hazard relationship. In the case of the fire hazard, n damage is applied every m seconds while actors are in the region. Upon leaving, the 'burn' status effect is applied that continues to apply damage for several moments.
The hazard region was set up in an extensible way because our designer has frequently updated the game documentation to include new features and I wanted to future-proof this functionality.
Upgrades!
Though it hasn't been incorporated into the game yet, one of our main goals for this project is to allow the player to purchase weapon and ability upgrades from a shop in between waves of enemies. We're currently hard at work on adding this to the game; during sprint 5, however, I implemented a placeholder system that allows the player to buy upgrades mid-run. This allowed us to test the upgrades that I added for each of the weapons.
Minigun, Build-Up Bomb
The minigun's 'build-up bomb' ability causes an explosion after landing n hits on an opponent. This functionally increases the damage-per-second of the weapon significantly, though it is mostly only of use on the larger enemies due to their higher health pool.
For this feature I once again extended Sean's status effect system. This unfortunately meant having to navigate around the singleton-style implementation of that system which caused a very slight delay. Working within this paradigm wasn't challenging, to be clear, but it did cause the task to take a few more minutes than expected.

The parent status effect constantly ticks down and its interface only accepts a 'duration' and 'param' value. I could not modify the interface without interfering with Sean's progress. As such, I used the constantly ticking down duration to the advantage of the feature: by controlling when the parent calls occurred I was able to prevent the premature destruction of the actor component, instead causing the build-up value of the bomb status effect to decay.
Note the branch into the do once - the condition on that branch specifies the number of charges necessary to cause the explosion. The magic number '10' is used because, at the time of the feature's creation, the designer was still adding and changing information about the weapon upgrades. Thus, I didn't want to create a structure and data table without knowing which types of data were necessary. This is the main issue with the stampede of features we implemented this sprint - there's not enough time for things to stabilize before we need to move on to the next thing.
Pistol Explosive Rounds
The explosive rounds for the pistol were very easy to implement, as you might imagine. I had already created general explosion logic for the rocket launcher & grenades, so it was a simple matter to re-use that code. I haven't added the code to one of my function libraries yet due to wanting to clean it up a bit more first, but it's definitely proven useful enough to warrant inclusion.

In the above image there's a peek at how I implemented the data that tracks which weapon upgrade the player has. I'm using a map between E_WeaponTypes and a bitmasked integer who's valid values are defined by weapon-specific enumerations. From there it's a simple matter of retrieving the correct weapon and using a bitwise AND to check if the correct bit has been set. I'd like to give a huge shoutout to my partner Julie for teaching me about bitmasks in the first place - they've proven to be extremely useful in many different applications.
Bits & Bobs
There's a lot of smaller things that were either half-shown above or not shown, e.g. the ammo system, switching the models of weapons, updates to the how-to-play screen, changes to the rocket launcher to remove the initial arc and warhead explosion delay, etc. As I mentioned above, my memory of several days out of the past two weeks is very hazy due to a very high fever. I should mention the one big bug I found after I began to recover, though.
The timer code used to calculate how long the player has spent in the level has been my personal albatross during this project. It's never been clean, I added it extremely early on in the project and extremely fast because I wasn't even sure if it was going to be permanent or not. I'd like to say that I introduced the bug while trying to optimize the code during a feverish fugue state, but jumping back to an older branch of the project reveals it's been around for a while.

This execution line is part of a looping timer that's called every 0.01 seconds (max once per frame) - it's a simple alpha accumulator for use with animations. The bug is in that final sequence -> do once logic: the call to '0 to 1 timeline' is a self call! In other words, the event that starts this execution line is being double-called every frame, followed by a call to stop the timeline one frame later; the stop call is then immediately overwritten by the next event call from the looping timer logic! I have no idea what I was trying to accomplish with this ridiculous code but the game gained a couple FPS when I removed it.
Aim Assist
The aim assist feature was 95% complete at the end of sprint 5 but couldn't be implemented until I had access to a certain area of the code that Sean was working in. I'm actually quite proud of this feature but I'll save speaking more on it until my next blog post.
Summary
This was a whirlwind sprint. Frankly, I over-allocated time to this project. The upcoming Excellence in Computer Graphics Awards event and my impending graduation have both spurred me into working harder on this than was warranted. I'm hopeful that my team and I can bring this project to a satisfactory level of completion by its conclusion.

Comments