Weapon Recoil, Spread & Spray Patterns

Camera Based Dynamic Recoil System

This weapon recoil system aims to replicate the functionality of the Counter Strike weapon recoil system. This type of system can be easily adapted to replicate other types of modern shooters with a heavier focus on ADS type gameplay.

I built this weapon recoil system to get a better grasp on the mechanics and components that create nice feeling gunplay.

This system was originally built to create a tight feeling hip-fire centered gunplay model similar to Counter-Strike or Valorant. It could easily be modified to better mimic that of other modern shooters that feature ADS centered gunplay.

More gunplay related articles:

Handling is just one part of gunplay. Weapon feedback and animations are just as important. The following article is about how I use this system create dynamic and responsive first person animations.

Features

Predictable Recoil and Spray patterns

Weapons have their own distinct patterns defining camera and projectile offsets. Weapon Spread is used to introduce randomness to impact a weapons effective range.

Easy to modify, mix & match

Weapon behaviors are defined by curves for quick and easy editing. Can be mixed and matched to create completely new behaviors and weapon types.

Data drives animation controller

The data generated by the recoil system is used to drive the first person animation system. Read more about it in my article on Procedural First Person Animations

Types of recoil systems

Dynamic recoil is most commonly found in modern shooters, which this article is based on. Static recoil systems used to be a thing of the past until recently where physical recoil systems have started popping up. Something which I intend to explore more in the future.

Dynamic Recoil

Static Recoil

Creating a dynamic recoil system

Defining a fundamental pattern

A recoil pattern is made up of many different variables:

Vertical Recoil and Horizontal recoil define how the weapon moves when fired, these are the most fundamental components of a predictable recoil system.

Spread is used to introduce randomness that can greatly alter the effective range of a weapon.

Reset Time this is how long it takes for your weapon to become accurate once you've stopped shooting.

Rate of fire the weapons fire rate also defines the rate at which recoil is applied. Rate of fire can greatly affect all components of a recoil system.

Recoil System Components

Weapon Parameters

Weapon behavior is defined by a set of curves and timers

Vertical and Horizontal recoil curves make up the foundation of a recoil pattern.

Camera Recoil

A rotation offset applied to the player camera as we shoot. Interpolating back to it's origin as we shoot. 

This simulates the weapon forces absorbed by a characters body.

Projectile Offset

An offset we apply when spawning or tracing our projectile relative to the player camera.

Adding random spread to the projectile offset affects a weapons effective range.

These simulate the weapon moving in the characters hands.

Visualization of bullet traces. The offset is also used inside the animation controller to follow the spray pattern and frame the bullets even in ADS mode.
Horizontal and Vertical spread sequence.The crosshair represents the 0 value on each track.

Defining a weapon pattern in the engine

Using Curves

Float curves are used to define the vertical and horizontal recoil. Getting the recoil values is as easy as tracking how many bullets have been fired in sequence sometimes referred to as "heat". I think Bullets In Sequence or simply bullet sequence is more descriptive when also describing concepts like loop points later on.

Alternative:

Vector curves is another nice way to pack curves, using the X,Y,Z channels to store vertical recoil, horizontal recoil and spread. These curve values are all fetched using the bullet sequence

How getting the recoil value could look in blueprints

Reset Timer

Any time we fire a bullet we also set a timer. This timer has one purpose to be a buffer between when you stop shooting and the bullet sequence is reset. This value is often fractions of a second, but still serves an important role, this also helps remove exploits related to trigger spamming seen in some games.

Resetting the recoil

Whenever we want to reset our recoil pattern we just have to set our tracked Bullets In Sequence variable back to zero.

Mechanics wise this is often called "Resetting the recoil". An important aspect of mastering the game.


Timers aren't frame perfect. Meaning that they may not be the best suited for hyper competitive games where milliseconds can make a big difference.

Accumulating and applying recoil

Recoil is applied to the camera after we do the bullet trace.

Accumulated recoil is tracked separately to be used for interpolating the camera back to it's original aimpoint.

Exposing recoil for animation

The values from the recoil system come in handy when animating. Declaring an OnWeaponRecoil(float v, float h) delegate passing the vertical and horizontal recoil values generated by our recoil model creates a handy subscription method for the animation controller to create responsive animations.

the "Add Controller Pitch/Yaw Input" routs input parameters to the Player Controller.

This blueprint 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.

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 gunplay feel in your recoil system. The example below uses a hard set interp speed. This works as long as your weapons don't overshoot the view angles of your character controller, this could happen if you have high rate of fire weapons.

Scaling the recovery delta value based on recoil distance can provide a "soft bounds" for weapon recoil while also avoiding extreme angles.

Simplified version of the reset structure for vertical offset. This should be done on per frame basis because it interacts with player input.

Weapon Spread

If you have played Counter-Strike you might have noticed that no matter how much you practice recoil control there are always small deviations in where the bullets land. This can be described in two parts.

Predictable spread

An additive bullet offset based on the pre-defined recoil pattern and the current camera deviation from the aim point origin.

Random spread scattering

A random bullet offset is applied on top of the predictable recoil pattern. This random spread is done in two parts.

Spread scaling similar to the recoil curves, a separate curve is used to define how recoil increases according to the bullets sequence, this value is not additive.

Movement spread is applied based on current player velocity. Either as total velocity or by separating the planar velocity and vertical velocity to create jump accuracy. Movement spread is applied additively to the base spread scaling


This pistol is barely affected by recoil due to a low rate of fire. Instead most of the bullet offset comes from the spread scaling. 

Random Spread

First shot accuracy - Spread over time

In most competitive shooters there is a very slight amount of spread applied even to the first bullet fired from a weapon. This is known as first shot accuracy. It has big impact on a weapons effective range. Making sure you can't use a pistol as efficiently as a sniper even if you have great aim.

I implemented this using float curves, just like the recoil values. Each time we fire the weapon we get the next value from the spread curve. The big difference is our spread curve is applied when we do our projectile offset calculation.

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.

Advanced players know this as Counter Stepping. A player can quickly reduce their movement velocity by giving input opposite to their current movement direction, forcing their current velocity below the pre-defined movement threshold. 

As an example, the inner circle is the spread applied to the first bullet in a series, the first bullet will never deviate more than this. Subsequent shots with applied spread scaling can land anywhere within the larger circle.
Spread projected on to the previous pattern example. Where circles overlap are the easiest places to land hits when spraying.

Blueprint Examples

Unreal comes with this nifty node that can apply a random offset to a pre defined directional vector. In case you don't want to do the calculation on your own.

Additive Camera Recoil Spread

A less talked about mechanic that is probably one the most important aspects of the Counter Strike spray pattern model is something I call additive camera recoil spread.

When applying recoil, not only do we apply the recoil pattern offset, we also apply an additional offset which is the difference between our current recoil and our aim point origin.

This is also one of the more advanced dynamics of Counter Strikes gun play, and a key factor in the topic of "Resetting the spray".

Without this, the mechanics only requires the player to learn the reset time of a given weapon.





This pistol is assigned exaggerated recoil values. There is no spread applied in this gif. Only vertical and horizontal recoil.
In the above model. The bullet trace offset from the crosshair is the same as the distance between the current camera rotation offset from the aimpoint origin.
The dotted blue lines mark the bullet trace offset which is where the bullets will land based on the camera offset(red) from the aimpoint origin(black). After which spread is applied.

Loop Points

Loop points wont directly impact your weapon behavior. Rather, they make the defining weapons a whole lot easier, to make sure you don't have to manually create infinite data points for your recoil and spread. This is especially useful when dealing with weapons that have large magazines or instances where a game features infinite ammo.

In the case of Counter Strike. You might be familiar with the Negev. A belt fed light machine gun that shoots 150 bullets at a high rate of fire. The Negev also features a unique spray pattern that becomes more accurate after sustained fire.

Not only does the concept of editing 150 unique data points seem daunting. Any revisions, like re-defining the weapons use case or altering the ammo count becomes a huge time investment.

Instead, by defining behavior of the first 30 bullets. We can utilize loop points to greatly reduce the required data set. If the weapon becomes accurate after the first 10 bullets. We can define a loop start the data point after which the weapon becomes accurate, and and a loop end when in our bullet sequence we wrap back to the loop start

Not only does it make the data set easier to maintain. Weapon recoil is also more resilient to the rebalancing of other weapon parameters like ammo count.

Use case: Unlimited Ammo

In this example the rifles unlimited ammo and its Loop Start is set to 15 and Loop End to 30.

After firing 30 bullets, the bullet sequence wraps back to 15 and keeps looping through for as long as the weapon can sustain fire.

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