Weapon Recoil, Spread & Spray Patterns
Key Components
Recoil
Reset Time
Spread
Additive Camera Recoil Spread
Loop Points
What is weapon recoil
Weapon recoil is a great way to give firearms their own personality. In essence, this means to recreate the jerking motion from the forces generated when firing a projectile in real life. In gaming, weapon recoil serves as a means to enhance immersion by mimicking the motions associated with firing a real firearm. This implementation of recoil is can introduce more intricate gunplay and greatly affect combat mechanics.
Typically, recoil is implemented as predictable and recognizable bullet hit pattern, often called a Spray Pattern. These patterns give weapons their own distinctive behaviors and traits, directly influencing their effectiveness in the game. Additionally, they allow players the to discover and specialize in weapons that align with their playstyle of choice.
Static recoil
In a game featuring static recoil. When the player fires their weapon, the camera is tilted back to simulate the weapon punch. The player has to compensate by counteracting the movement. This type of recoil has become less prevalent in favor of dynamic recoil systems.
They still see some use in tactical shooters but have been replaced by dynamic recoil systems in large.
Dynamic Recoil
Dynamic recoil, for lack of a better term, displaces the aim point while shooting and subsequently returns it back to its origin when you stop shooting.
This means players can still counteract recoil by moving their aim in the opposite direction. But they don't require the same level of mechanical control to maintain accuracy.
Dynamic recoil has several benefits, for gamepads, less micro adjustments and for keyboard and mouse players less vertical space required for mouse movement. Without sacrificing the mastering ability that comes from learning recoil patterns.
Creating a dynamic recoil system
Defining Recoil Patterns
The system in this article is heavily inspired by the recoil system found in Counter-Strike: Global Offensive. But can easily be adapted to suit any kind of modern FPS.
This is not a step by step code example, rather it's a guide to the general concepts of implementing a recoil model. Your approach should be based on your needs. Different classes and data structures might be better suited when working with networked gameplay. The same concepts should still apply.
What makes up recoil
A typical weapon recoil system consists of two parts:
Camera Recoil
A rotation offset applied to the player camera to simulate the forces of the weapon kick absorbed by the characters body.
Projectile Offset
An offset we apply when spawning or tracing our projectile relative to the player camera. These simulate the weapon moving in the characters hands.
Combining these two makes up the foundation of the recoil pattern.
Creating a predictable spray pattern
To create a basic spray pattern, a weapon needs a data set to define movement.
Vertical recoil
This defines how much the barrel climbs when fired.
Horizontal Recoil
This defines how much the weapon jumps side to side when firing.
Using float curves
In UE5 we can manage this easily by storing both the horizontal and vertical curves as separate Float Curve objects.
We can get the current recoil value by tracking how many bullets we have fired in sequence.
We can do this by creating a separate variable called BulletsInSequence that we increment whenever we fire a bullet, we use this as our getter value for our float curves.
The large benefit of storing these patterns as curves is how easy they are to read and edit. Especially when dealing with a larger weapon base or handing over behavior to the design team.
Vector curves
An alternative to separate float curves is to instead use Vector curves. Vector curves have 3 axes by default. X,Y, & Z. Storing the recoil values on the X and Y axis for example allows you to edit and keep both curves inside the same asset.
The final Z axis can then be used when implementing weapon spread. Another important mechanic which is covered later in this article.
Resetting the recoil
Whenever we want to reset our recoil pattern we just have to set our tracked BulletsInSequence variable back to zero.
To avoid players spamming the fire button to avoid weapon recoil, we add a slight delay between when we stop shooting and resetting the spray pattern.
As a game mechanic this is known as "Resetting the spray" and prevalent in many first person shooters.
Reset Timer
Any time we fire a bullet we also set a timer. This timer has one purpose, to reset the bullet sequence when we stop shooting.
I find that resetting the counter to zero after elapsing makes for the most consistent feeling gunplay.
A range of 0.2 - 0.35 is a good starting point, as most weapons have a higher rate of fire.
You could do some sort of interpolation though I would strongly advise against it.
Accumulating and applying recoil
Tracking accumulated recoil is as simple as adding and storing these values in a separate variable. In the following example note that "Add Control Pitch" is additive and takes the current curve value and not the accumulated value.
The Accumulated recoil value is used to restore the camera to it's original location by subtracting the accumulated recoil over time.
Accumulated recoil can also be used as input for our animation controller to give us better visual feedback on our current recoil state. As seen in my article about Procedural Weapon Animation
This example is set up inside of the Player Character which is a subclass of the Pawn. It's always good to consider where your code will be used/re-used. And if the class context is suitable for networked gameplay. Consider maybe housing parts of this logic within the Player Controller.
Re-Centering the aim
We use the accumulated recoil values to track and subtract vertical and horizontal offset, until both are back to 0.0. How much we subtract is a defining aspect of the gun feel. The example below uses a hard set interp speed when calculating the recovery value. This works as long as your weapons don't overshoot the view angles of your character controller.
When using an additive recoil system, you must also account for a weapons rate of fire when scaling the vertical recoil. otherwise you risk recoil climbing outside player view. Increasing the interpolation speed the further you get from the center can be an efficient way to soft clamp the recoil while at the same time avoiding the feeling of "hitting a hard ceiling"
Just like when we added the recoil, we take the subtracted value and apply it to our camera or controller.
Weapon Spread
If you have played Counter-Strike you might have noticed that no matter how much you practice recoil control there is always a small deviation to where the bullet lands.
This happens due to weapon spread. Weapon spread is a random offset applied when shooting a weapon.
Just like recoil, weapon spread is often a scaling variable. Each shot fired in sequence often deviates more from the defined spray pattern than the last. This often makes burst firing a more reliable option than shooting full auto.
Spread is also a means to define the speed of gameplay. Firing while on the move is often penalized by an additional layer of random spread. This is to avoid players flying through the map to land fast kills.
This is known as movement spread or movement accuracy. Movement speed and accuracy are often a major balancing point. In some cases spread is a constant. Instead, movement speed penalties are introduced when aiming down sights to take more accurate shots.
There is usually some degree of weapon spread present even when aiming down sights, as this is an important part of a weapons identity.
Implementing spread
Just like the recoil curves. Spread can also benefit being implemented as Curves.
As opposed to the recoil curves. Spread doesn't have to be additive.
And just like the recoil curves, we can use the same BulletInSequence variable to fetc our spread values.
First shot accuracy
In most competitive shooters there is a very slight amount of spread applied even to the first bullet on all weapons. This is known as first shot accuracy. It has big impact on a weapons effective range. Making sure you can't efficiently play sniper with pistols or rifles even if you are considered to have great aim.
Movement Spread
In Counter-Strike movement spread penalties applies as soon as a character exceeds a set threshold (about 150 source units). Players moving below this threshold won't suffer any accuracy penalty based on movement.
This is why stopping before you shoot is such an important mechanic in counter strike. It even has it's own name "Counter Stepping"
Counter Stepping is an advanced mechanic where a player quickly taps their movement keys in the opposite direction of their current velocity. Doing so let's you cancel out your current movement velocity, putting you below the movement accuracy threshold. Players who master this can shoot accurately while moving at seemingly high speeds.
Additive Camera Recoil Spread
A less talked about mechanic that is probably one of the defining parts of the counter strike spray pattern model is something I call additive camera recoil spread.
Not only do bullets follow a pre-defined spray pattern, they also maintain an offset between our camera and our aim point origin.
This is also one of the more advanced dynamics of Counter Strikes gunplay, and a key element when resetting the spray.
Loop Points
Lastly. Let's talk about loop points.
Loop points wont directly impact your weapon behavior. Rather, they make sure you don't have to manually create infinite data points for your recoil and spread values. This is especially useful when dealing with weapons that have large magazines or in the case a game features infinite ammo.
Counter Strike features a weapon called Negev. A belt fed light machine gun that has 150 bullets. The Negev is has a rapid rate of fire. What's unique about the Negev is that it's first 10 bullets have significant recoil. After sustained fire, the weapon concentrates to a tight beam of bullets making it great for suppressive fire.
To avoid modeling 150 unique data points. We can instead define a pattern where the first 1-10 bullets have a significant recoil offset and spread. Then instead of modeling another 140 data points, we give bullet 11-20 a tighter recoil concentration and reduced bullet spread. Now all we need is a Loop start and Loop End.
Not only does it make your weapons handle large ammo counts, it also simplifies the process of defining a weapons identity.
In this case the rifles Loop start is set to 15 and its Loop end set to 30.
After shooting 30 bullets in sequence, the recoil curves start looping between bullet 15-30.
Continue Reading
This article features pointers on how I recommend setting up a first person character. Includes the topics of True First Person setups, Field Of View and setting up a blender scene to create base poses for weapon animations.
This next article is about combining the recoil model
with the player character and game input to create
responsive and dynamic weapon animations