DEBASER | Devlog 2

As you can see, much has changed.

Item Drop System

I’ve implemented a weapon system, which allows the player and enemies to interact through item drops. Here’s some interesting features of the drop system:

  • You can throw any weapon. If you hit an enemy, they will be stunned.
  • When you pick up a weapon, you throw whatever is currently in your hand.
  • Stunned enemies will throw their own weapon as a projectile, potentially hitting other enemies.
  • Enemies can pick up weapons in an effort to kill you.
  • Enemies have self-preservation: if an enemy has no weapon, they independently make the choice of whether to go for a nearby gun and shoot you, or run away from you to survive.

The item drop system creates interesting scenarios in gameplay, because it gives the enemies many of the same advantages that the player enjoys.

Weapon Property System

Each weapon has its own attributes that affect how the player can use it. For example, the shotgun is high damage / spread, but can’t fire in rapid succession, whereas the pistol is low damage, but very precise and can be fired quickly. This allows me to fine-tune tradeoffs between the weapons that make decisions between them more meaningful to each individual situation.

New Enemy Accuracy System

In the previous version, enemies were able to kill you in one shot, as long as they could see you. Now, they have a chance to “graze” you (indicated by a red flash on the screen). This chance is determined as a function of your angular velocity and your distance from the enemy. I did a write-up on the specifics, which you can read here.

New Enemy Type!

To spice up the gameplay, I added a new enemy type: the heavy. Here are some of his features:

  • Moves slower.
  • Requires many shots to kill.
  • Can’t use guns, but he can kill you with his bare hands.

The Heavy will have his own model in the future, but for now I lazily made him a scaled up version of the regular enemy.

Door Busting

Using an incredible asset called Exploder I was able to create a door-busting mechanic. In the future I plan to let this stun enemies on the other side.

New 3D Models

You may notice the addition of some new weapon models. These were made by an excellent team of 3D artists that I found on the Blender discord. They will be assisting me with new character models, weapons, and animations to match. The weapons above are being animated as I write this.

The Soundtrack

I believe it is essential that DEBASER has an excellent soundtrack. For this reason, I’ve spent a lot of time and effort in the past 2 months finding musicians willing to license or compose music for the game. The soundtrack is inspired largely by the incredible synthwave soundtrack of Hotline Miami.

I am going to keep the details confidential for now as negotiations are ongoing, but rest assured some amazing tracks are being added to the game as I type this.


In the past month I started play-testing. Even though the game is in a rough state visually, nearly all testers have thoroughly enjoyed its mechanics. The testing has shown me that this game’s core concept has wings, which is incredibly satisfying to me after almost a year of developing the concept essentially “in the dark.”

Main Menu

To satiate the UX designer inside me, I added a title screen to the game. I modeled everything in blender, and created a TV static shader in Unity for the screen. I also implemented a dolly-zoom to make this as needlessly intense as possible.

Goals for next time

I will be working 2 jobs this summer and doing summer classes, so I might not be able to work quite as much on the game as I did since the last log. Still, by the next devlog, I would like to have everything from the tutorial to the first level completed, including a small introduction to the story of the game. If I can create this “vertical slice” of gameplay I might be able to start looking for a publisher.

My most beautiful bug

While working on DEBASER‘s enemy AI, I found a bug that is so miraculous that I almost want it to be a feature. Due to a series of coincidences, I have unintentionally programmed my enemies to become contact jugglers.

Beautiful, isn’t it? They can even do it with longer items:

There’s no animation or trickery here, this phenomenon is completely physics based. The enemy’s collider is juggling the item.

The Cause

This juggling is the result of an enemy trying to pick up a gun that is on his head.

To perform any action, the enemy starts by moving to the target (the gun) and performing the action (picking up the gun). However, for the performance stage to begin, the enemy must be within a certain range of the item. This distance is measured from the root transform of the enemy, located at his feet (after all, items usually fall to the ground). The problem with this scenario is that this range happens to be slightly shorter than the height of the enemy. So the enemy can’t pick up the item until he arrives, but he can’t get there if the item is on his head: it’s a catch-22.

You may ask, “but why doesn’t the gun fall off the enemy? Surely it’s not being balanced on its exact center of mass?

That’s a perfectly reasonable, yet incorrect assumption: the enemy is balancing the item exactly on its center of mass. Does this mean my enemy AI has become self aware? No. The reason for this goes back to my system for picking up items. Most gun / swords models have their origin located in the handle:

The object origin is on the right.

This means that if we were standing close to the tip of this gun, we can’t pick it up because the distance is being evaluated all the way from the handle. To solve this problem, I needed to evaluate distances from some kind of center. Since all item drops have a Rigidbody component and approximately accurate colliders, I figured I would just use the center of mass if it was available.


The enemy is juggling items almost perfectly because he’s in a negative feedback loop: by trying to pick up the item he is always moving towards the center of mass, canceling any movement in the item. This is kind of how control systems for rockets and planes work.

Who said rocket science is hard? I just did it by accident.

A Probabilistic Shot Accuracy Model for FPS Enemy AI

I’m currently working on an FPS called DEBASER. In this game, until very recently in development, the enemies had 100% accuracy when shooting, so long as you were visible by the time they pulled the trigger. Obviously, this is both unrealistic and makes the game unreasonably hard. After some playtesters complained, I began searching for a solution. For simplicity, I decided that I would use a probabilistic model to determine if the enemy misses or hits to player according to RNG.

The Variables

As a starting point, I figured that a good model for shot accuracy should take two variables into account: distance and speed of the target. If you were trying to shoot something, you would much rather it be close to you and not moving, than far away and zig-zagging.

An immediate problem with this model is that speed can be misleading. It’s difficult to hit a target running around you in a circle, but it’s easy if they’re running directly towards you. This is because you only have to account for movement that changes the angle you must shoot at. It follows that we would be better suited to consider the angular velocity of the target relative to the shooter.

Above is a basic diagram showing how we get the angular velocity of the player relative to the enemy. Note that v is the tangential velocity, which is found by projecting the velocity vector of the player onto the plane whose normal is the facing vector of the enemy:

Vp = player’s velocity vector, Fe = face vector of the enemy
Angular velocity as a function of tangential velocity v and radius r

The Difficulty Model

As an intermediate to the Accuracy model, let’s first model “difficulty.” Difficulty (D) will be a number from 0 to infinity, where 0 means it is 100% likely that the enemy will hit the player and infinity means it is 0% likely that the enemy will succeed. Difficulty should increase as range and angular velocity increase, like so:

To get an intuition for how this function behaves, let’s graph it with D on the y axis and r on the x axis. v will raise and lower.

Notice that the difficulty starts at 0 when the distance is zero. Intuitively, this makes sense. However, the function is asymptotic: it converges to a number, not infinity. This makes no sense, as difficulty should always be rising as distance increases. The reason for this convergence is that, as you get farther away, angular velocity shrinks so fast that it cancels out the growth of r. The solution to this is to add a “helper” constant (c) to the angular velocity at all times. This will ensure that it always approaches infinity.

Above, you can see the effect that increasing the helper constant has on the limits of the Difficulty model.

With that, our Difficulty model is complete:

The Accuracy Model

Our final accuracy model should represent the probability from 0 to 1 that the shot will be accurate. Because Difficulty can be anywhere from 0 to infinity, we should start by establishing two more constants to confine our results: L = the difficulty below which accuracy is 100%. U is the difficulty above which accuracy is 0%.

Above we see L and U in the context of the current difficulty model. To create an accuracy model, we need to form a piecewise function. The behavior when D is above and below L and U has already been specified above, but what about in-between? We don’t want this function to have any gaps in it, so what we can do is interpolate from 1 to 0 based on how far D has traveled throughout the region between U and L. The math behind this interpolation gets a bit messy but the overall concept is simple. The resulting Accuracy model is as follows:

Accounting for Human Stupidity

Humans are bad at probability (well, maybe it’s just me…); as I play-tested this model, I noticed that the AI was still very accurate. At 50% accuracy they were still very often taking me out on the first try. In a deliberate departure from realism, I added another constant, h, which I’ve affectionately named the Constant of Human Stupidity. The final model simply applies h as an exponent to A. Along with making it easier to avoid getting shot, this constant has the effect of making the model look more exponential for higher values of h. Below is the result of raising and lowering h.

The Full Model

Tangential velocity of player relative to enemy
Angular velocity as a function of tangential velocity and radius
Difficulty score, from 0 to infinity
Accuracy, as a probability from 0 to 1

Click below to play with the model on Desmos.

The Ping Pong Modulo Function

Ping Pong Paddle On Table Vector Art & Graphics |

Earlier today I had to spend a whole 20 minutes coming up with this function. It’s like a modulo function, but instead of looping back to zero every cycle, it transitions back down to zero. It cycles every 2(n-1) elements. There’s probably a proper name for it, but I can’t figure it out.

In case anyone else would rather google it than spend time figuring it out, here it is:

def ping_pong_mod(i, n):
    cycle = 2 * (n - 1)
    i = i % cycle
    if i >= n:
        return cycle - i
    return i

I hope this is helpful to a fellow lazy person in the future.

DEBASER | Devlog 1

In this entry, I’ll be going over what my new project is, how it started, and how development has progressed in recent memory (screwups included).

The Elevator Pitch

A video of DEBASER.

The game is called DEBASER. It is my attempt at creating a first-person version of Hotline Miami, one of my favorite games of all time. I want to make a brutal FPS with a unique focus on precision and speed. The goal of the game is less to beat the level, but to get the fastest and most stylish play-through.


Camera Comrade in its full glory.

DEBASER’s development started with a 2019 game jam submission called Camera Comrade. In it, you play as a soviet operative in the cold war, tasked with infiltrating the CIA and destroying their coffee machine. It featured a primitive stealth / hiding system, combat, parkour mechanics, throwable cameras, and a cute aesthetic. It was a lot of fun to work on, and a great way to learn my way around Unity. DEBASER is the result of many iterations on Camera Comrade over the past year.

Artificial Intelligence

The pathing system of my AI.

Camera Comrade’s enemy AI was based on a three-state Finite State Machine: Patrol, Search, Attack. It was simple enough for a throwaway game jam submission, but for DEBASER I needed a system that scaled better. I’ve moved to Goal Oriented Action Planning (GOAP). With GOAP, instead of spending exponential time on writing the transition function, I can simply specify the prioritized goals and possible actions of the agent and have it automatically generate a plan. There’s a great paper on this system by the developers of F.E.A.R. that is definitely worth checking out. Suffice it to say that if you need an agile way to create game AI, GOAP is the way to go.

Inverse Kinematics

Image result for inverse kinematics animation gif IK rig
The FABRIK system I failed to replicate on my own.

Often during game development I find myself sidetracked by cool technologies. Last month, that sidetrack was Inverse Kinematics. It all started with this GDC talk by Ubisoft showing their full body procedural animation using “IK rigs.” The system was so mindblowing to me that I spent weeks of precious development time diving into talks, papers, videos, and interviewing experts. It took me weeks of prototyping to finally realize that the system I was building was just thinly veiled procrastination, a fool’s errand. In my haze, I had forgotten the real goal: making the damn game. So, with sadness, I scrapped my IK prototype and just downloaded FinalIK by Root Motion. For $90 I now never have to worry about IK again. Thank god.


Honestly, at this point I have no idea where the graphics are going. I wanted a simple aesthetic like Super Hot, but instead I got sucked into substance abuse. Or rather, Substance Designer, a great piece of software for node-based 3D material creation. Even as a relative noob, I’d say I’ve managed to create some damn-good visuals so far. However, this comes with a problem: the current subway level featured in the video took me FOREVER to create. I feel that while I like the look of it, I won’t be able to make materials fast enough if the fidelity is this high. In the future I must move towards minimalism, so I don’t find myself stuck doing digital art all day instead of making the game.

The biggest change I’ve made to Camera Comrade is that the enemies are no longer capsules, but real men! It took many painful iterations to get to my current system of animation. First I manually rigged / animated the enemies with Unity’s builtin animator, which fell apart quickly as I realized I’m not an animator. Then I used slightly-incompatible unity assets that did not play nice with my modifications. I then heard about Mixamo, a tool that takes in arbitrary humanoid meshes, and returns a consistent set of royalty free animations! I was blown away by the quality and quantity of animations on the site. It took a little bit of finagling to get Mixamo to work with Unity, but once it did the efforts were well worth it.

Another notable change is that I’m using blender to create levels. It was tricky at first, but now that I’ve gotten the hang of it I see the advantages. It’s definitely easier to design levels with an established modelling tool, rather than with ProBuilder. Blender allows me to create pipes, fix UV maps, and add procedural modifiers like Bevels, which make the scene more finessed while keeping editing simple. On top of that, the materials work the same as in Unity, so importing is a breeze. Switching to blender has been the best change I’ve made so far.

Moving Forward?

My goal for the next devlog is to have refined combat mechanics, and a working level. Given the COVID-19 situation, college will be online for me for the remainder of the semester. The silver lining is that, pandemic willing, I should be able to make serious progress on DEBASER. Stay tuned.