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.
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.
Weapons have their own distinct patterns defining camera and projectile offsets. Weapon Spread is used to introduce randomness to impact a weapons effective range.
Weapon behaviors are defined by curves for quick and easy editing. Can be mixed and matched to create completely new behaviors and weapon types.
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
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.
Predictable camera recoil
Predictable projectile offset
Randomized Bullet Spread
Recoil automatically returns to original aimpoint
Camera sticks in place
Weapon control comes mainly from recoil management
Weapon Sway used as accuracy penalty
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.
Weapon behavior is defined by a set of curves and timers.
Vertical and Horizontal recoil curves make up the foundation of a recoil pattern.
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.
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.
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.
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.
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 adds significant depth to the gameplay system. There are many older shooter games that immediately reset the accuracy as soon as a player stopped shooting. This resulted in players using rapid fire macros to deliver extremely accurate shots at a high rate of fire.
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.
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.
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.
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.
CS:GO and CS2 do not rely on constant interpolation. Instead, the recoil pattern first starts interpolating once the player stops shooting. To make the weapons feel more powerful a layer of visual recoil is added to the camera rotation. This can be seen in the clips below.
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.
An additive bullet offset based on the pre-defined recoil pattern and the current camera deviation from the aim point origin.
UPDATE: CS2 now feature the follow crosshair option allowing the crosshair to accurately track this offset.
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
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.
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.
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 offset.
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 gunplay, and a key factor to the concept of "Resetting the spray".
Without this, the mechanics only require the player to learn the reset time of a given weapon.
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.
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.
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