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
Predictable camera recoil
Predictable projectile offset
Randomized Bullet Spread
Recoil automatically returns to original aimpoint
Static Recoil
Camera sticks in place
Weapon control comes mainly from recoil management
Weapon Sway used as accuracy penalty
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.
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.
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.
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.
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.
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
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.
Blueprint Examples
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.
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