[Release] Mathematically correct Recoil

So I’ve been working on this code for a while now, and I am overjoyed at how well it performed. I figured in the long time I have been in this community, I might as well contribute back to it.
I have come up with a mathematically correct formula for applying recoil to the player. This system uses real life data as its core functionality. Modeled after the real things, I take into account just about every aspect possible when calculating the recoil. In addition, I have also allowed this system to be allow the player to automatically “control” the weapon.
I am sure many of you have seen the RealCSSBase, some of you may even use it! Basically all it does is has a standard recoil variable that get applied to the eye angles. BORING! I made my mine more dynamic. Obviously, when you fire a gun, it will NEVER kick the same way it did when you fired the last round (especially in full auto). You have to take into account your weight distribution, the grip on the gun, angle, movement due to trigger pull, etc. Hell, Even the powder will burn at different rates! Obviously I cant take into account all that info, so I just added a few nice Math.Rand()'s for you guys to simulate it.
Of course, we all also know that in real life, the fire arms don’t accumulate recoil over, and over, and over until the gun is facing straight up! We have a instinctual reaction to pull down on the weapon in order to offset the force being applied to the rifle upwards. Therefore, I have taken this into account and thrown in some an exponential decay on the recoil in order to compensate for this. No more pulling down on your mouse over and over in one clip to keep your gun on target, I do it for you.
[HR][/HR]
TL:DR:
As realistic recoil as possible in a video game.

What this does:
Give a almost exact simulation of how a rifle would handle under real circumstances.
Compensates for muzzle climb (You can change how quick by changing “CompensateTime”)

What it does NOT do:
takes into account crouching, running, movement, etc. if you want that, I could always merge this with the base.

If you use this in your bases, I hope you at least have the decency to credit me for saving you about 2 day’s worth of work and research rather than just take my name off, and slap on your own like you would with your shitty gamemode edits.

Anyways, here it is.
[LUA]
–[[
Get yours loading info at http://data.hodgdon.com/cartridge_load.asp
Universal powder used for Grains on majority.
If you do not have Universal, use one that has a similar velocity

Case Max Capacities: http://kwk.us/cases.html
]]

local mathE = 2.71828 – the mathmatical constant e.
local CompensateTime = 5 – How many seconds does it take for the player to control the recoil

–[[
These are the physical properties required for the algorithms
BWeight = Weight of projectile in grains NOT GRAMS (This is JUST the projectile, not the casing and powder as well)
Velocity = The projectiles (average) velocity that it travels down the barrel (Not after exititng!)
CGrains = This the weight of powder inside the casing in grains
CaseCap = This is the cartridge’s capacity in grains
Diam = This is the diameter in inches of the projectile , not the casings.
]]
local Bullets = {}
Bullets[“pistol”] = {BWeight = 115, Velocity = 1300, CGrains = 5, CaseCap = 13.3, Diam = .354330} // 9MM
Bullets[“alyxgun”] = {BWeight = 45, Velocity = 2800, CGrains = 5.5, CaseCap = 14, Diam = .224} // 5.7x28 = 5.0
Bullets[“357”] = {BWeight = 125, Velocity = 1600, CGrains = 5.7, CaseCap = 27, Diam = .357} // .357
Bullets[“helicoptergun”] = {BWeight = 165, Velocity = 1060, CGrains = 6.4, CaseCap = 42, Diam = .452} // .45 ACP
Bullets[“combinecannon”] = {BWeight = 300, Velocity = 1550, CGrains = 70.5, CaseCap = 110, Diam = .5} // .50 S&W Magnum
Bullets[“airboatgun”] = {BWeight = 62, Velocity = 3100, CGrains = 62, CaseCap = 28.5, Diam = .354330} // 5.56x45 M4 M16
Bullets[“striderminigun”] = {BWeight = 123, Velocity = 2400, CGrains = 28.5, CaseCap = 35.6, Diam = .310}// 7.62x39 (AK)
Bullets[“sniperpenetratedround”] = {BWeight = 150, Velocity = 2800, CGrains = 50.5, CaseCap = 54, Diam = .308}// 7.62x51 (M249saw)

SWEP.GWeight = 0 – How many pounds does the gun weigh? This must be included in your SWEP!!!
– DO NOT SET THIS. It will get overwritten anyway…
SWEP.isFiring = false
SWEP.RecoilDelta = 0

– This is what actually generates our recoil.
function SWEP:UpdateRecoil()
– Written by: SeveredSkullz
– E = MC^2, mother fuckers.
local WAmmoType = Bullets[string.lower(self.Primary.Ammo)]

local BulletWeight = WAmmoType.BWeight
local MuzzleVelocity = WAmmoType.Velocity + math.Rand(-WAmmoType.Velocity * .15,WAmmoType.Velocity * .15) -- Simulated Variance in powder burn, resulting in varied velocity
local ChargeGrains = WAmmoType.CGrains
local BulletDiameter = WAmmoType.Diam
local CaseCapacity = WAmmoType.CaseCap        
local GassesChange = 4000

--[[
There is a factor directly related to the type of firearms.
BulletVelocityFPS = Velocity of projectile and Gas
Ve = Velocity of projectile
High powered rifles         BulletVelocityFPS = Ve x 1.75
Shotguns( averagele ngth)     BulletVelocityFPS = Ve x 1.50
Shotguns (long barrel)         BulletVelocityFPS = Ve x 1.25
Pistol & revolvers             BulletVelocityFPS = Ve x 1.50
]]

if ( self.HoldType == "pistol") then
    GassesChange = 1.50 * MuzzleVelocity
elseif ( self.HoldType == "shotgun") then
    GassesChange = 1.25 * MuzzleVelocity
elseif ( self.HoldType == "ar2" ) then
    GassesChange = 1.75 * MuzzleVelocity
end

--Recoil (Before the Barsness index formula) = ( BulletWeight * MuzzleVelocity + ChargeGrains * (GassesChange) ) / 7000 / self.GWeight
--KineticEnergy = self.GWeight / 32.2 * Recoil * Recoil / 2

--Barsness' index     
local rfx = 7854 * BulletDiameter * BulletDiameter / CaseCapacity    
local rf = 1.4
-- Barsness offered a look-up table
if ( rfx <= 7.5 ) then        
    rf = 2.4
elseif ( rfx <= 8.5 ) then
    rf = 2.2
elseif ( rfx <= 9.5 ) then
    rf = 2
elseif ( rfx <= 10.5 ) then
    rf = 1.9
elseif ( rfx <= 11.5 ) then
    rf = 1.8
elseif ( rfx <= 12.5 ) then
    rf = 1.7
elseif ( rfx <= 13.5 ) then
    rf = 1.6
elseif ( rfx <= 14.5 ) then
    rf = 1.5
end

-- This is the amount of Kinetic energy in LBS that is applied backwards from the muzzle
local GunRecoilLBS = (BulletWeight / 7000 / 32.2 / 2) * MuzzleVelocity * MuzzleVelocity  *  (BulletWeight + ChargeGrains) / (self.GWeight * 7000)  *  rf

-- This simulates the players controll of the weapon while firing fully automatic.
-- The longer the burst, the more the player is used to the recoil and can compensate for it.

-- Exponential Decay of recoil, where GunRecoilLBS is the recoil
local x = CurTime() - self.RecoilDelta
local RecoilMod = mathE^(-x*GunRecoilLBS / CompensateTime)
local result = GunRecoilLBS - math.Min(GunRecoilLBS * .75, ((1- RecoilMod) * GunRecoilLBS)) -- Stored in a var for testing purposes. You can delete and simply return
return result

end

–[[
This adds recoil to the players Eye position to simulate Muzzle climb and control over time.
In order to add my system to your bases, All you have to do is add this function somewhere
in your primary fire hook.
]]
function SWEP:AddRecoil()
local recoil = self:UpdateRecoil()
– Add our recoil to the player.
if ( (SinglePlayer() && SERVER) || ( !SinglePlayer() && CLIENT && IsFirstTimePredicted() ) ) then
local eyeang = self.Owner:EyeAngles()
eyeang.pitch = eyeang.pitch - (recoil * math.Rand(.5 , 1)) – Up
eyeang.yaw = eyeang.yaw - ((recoil/2) * math.Rand(-1,1)) – Go left and right a bit too
self.Owner:SetEyeAngles( eyeang )
end
end

–[[
We need to keep track on when the burst started in order to compensate for longer bursts
This is a very crude method, but it works. Pretty much, just set RecoilDelta when you press
the attack button, and set isFiring to true. When you stop, set isFiring to false. Its that
simple.
]]
function SWEP:Think()
if self.Owner:KeyPressed( IN_ATTACK ) and not self.isFiring then
–print(“Start Burst”)
self.isFiring = true
self.RecoilDelta = CurTime()
elseif self.Owner:KeyReleased( IN_ATTACK ) and self.isFiring then
self.isFiring = false
–print(“End Burst”)
end
end
[/LUA]

Credits / References:
SeveredSkullz (Me): Writing the code
Wikipedia: Information regarding recoil
hodgdon.com: Reloading tables
kwk.us: Cartridge information

Some people working on SWEPs and SWEP bases should definetly look into this. Silly recoil always turned me down when trying to code a weapon based on some SWEP base.

That is ***EXACTLY ***why I put the effort through to make it.

Also, not too sure why Lua tags don’t recognize /* */ and // comments :tinfoil:

because facepunch doesn’t use a glua interpreter, /* */ and // comments are things added by garry.

I guess it would also be worth noting that a cone of 0.02 seems to be a very good number for this system. The cone is meant to give a false sense of the system that I have implemented. With this system, we no longer really need the cone at all, but best keep it at 0.02 for any wind, or any other things that could alter the trajectory of the projectile.

How come GunRecoilLBS and RecoilMod are not local. And SWEP.GRecoil is never modified. And I think you forgot to add SWEP to AddRecoil. Or am I missing something…

Looks cool.

All I can see for constructive criticism (except what was mentioned above) is that you forgot to localize “rf” :slight_smile:

SWEP.GRecoil - This used to be set as the result of the UpdateRecoil while I was testing. I simply changed it to return the value instead. Forgot to take it out.
AddRecoil - Thanks for that. Used to just be stuck in the CSShootBullets, but I took it out for convienience.

Oops. I forgot a few locals apparently. Of course it still works fine, but it should be local. Fixing.

imo viewpunch already gives a fine result
making things absolutely realistic in games usually doesn’t work

If someone could record a video of this, that would be great. I’m not sure if I’ll ever use it, but it definitely sounds interesting.

This has nothing to do with ViewPunch. Generally You would give an angle to punch the players view a certain amount, Usually, this is the recoil.

What this does is gives you the recoil. The SetEyeAngle I have used is pretty much the exact same implementation of ViewPunch internally.

[editline]23rd June 2012[/editline]

Actually, looking at this,

According to this, the players aiming is never actually modified, and only the camera from the players eyes is offset. If this is the case, then using ViewPunch doesn’t affect the aiming at all. You could be looking straight up due to view punches and still hit on target on where you were originally aiming. I dont know… Never really used ViewPunch. Ill go run some tests real quick.

[editline]23rd June 2012[/editline]

Yep. ViewPunch does not affect your aiming in any way, shape, or form.
self.Owner:ViewPunch( Angle(-90,0,0) ) puts me on target every single time.

Basically this means that you are just firing the radius of the cone, and you don’t even have to move your mouse to keep firing where you were. Shittiy implementation IMO…

a video could be good

Ill go make one real quick for you guys. Bear in mind I don’t have very good video editing software… Behold the plague of Windows Movie Maker.

EDIT: Nevermind. Lost track of time. Gotta go off to work. Ill do it when I get back.

Here y’all go.
Turn down your volume a bit. It came out a little louder than intended

Edit: Also, it totally screwed over my quality. Recorded at 1600x900. I don’t know what the hell happened and why it isn’t in 1080p quality. :suicide:

Very neat.

Hope to see it implemented in some good gamemodes sometime in the future.

If I ever find myself making a gamemode again, I’ll be sure to use it, myself.

https://dl.dropbox.com/u/8416055/FacepunchEmots/Buddy.gif

What you calculate here

[lua]
local GunRecoilLBS = (BulletWeight / 7000 / 32.2 / 2) * MuzzleVelocity * MuzzleVelocity * (BulletWeight + ChargeGrains) / (self.GWeight * 7000) * rf
[/lua]

Is the energy applied in opposite direction of the barrel.

However this has very few to do with the actual recoil of the weapon. For example according to your code a handgun that would shoot the same bullet as a rifle would have the almost the same recoil(except for weapon weight). However the Center of mass and the way the rifle is held results in a completely different recoil.

Also in your code you assume that all energy is converted in to vertical energy and especially in modern weapons (with the help of springed stocks and springed barrels and floating gun mechanisms) almost no energy is converted in to recoil.

I personally believe that you will never even get close to accurate recoil simulation of a modern firearm using simple mathematics like this. And in a game you want to provide a fun experience not a realistic experience. However if you want to continue with this.

I suggest you at least implement angular momentum because the code/formulas in its current state don’t make any sense at all.

Also i suggest you interpolate the recoil over a few frames, for example with the deagle that will only fire a single shot every second its kinda wierd if your view just jumps up by 45* in 1 frame.

I am aware of this. It clearly says so on the Wiki page I listed in the credits.

I completely agree! It is near impossible to come up with actual recoil on any given fire arm. There are way too many variables to take into account, and the amount of math required would most likely (Not an expert on performance on computers) slow down performance in the game, as the math required is called each time you fire the gun. Variables I would actually need to take into account for this to be 100% realistic would be the following:
Stance, Grip on gun, How the muzzle break deals with the gasses, how much weight the slide is on the gun, type of buttstock, how the gun deals with the veloctiy of the blowback (Such as in the vector, see here:http://en.wikipedia.org/wiki/KRISS_Vector)… etc. It is simply not possible in a game without literally examining every aspect on every gun, and as with each gun being completely different… it will take a lot of time. On top of this, I certainly don’t have these types guns laying in my closet to take a look at them!

This is the closest I can get with the information at hand, and in my opinion gives a better feel than any other recoil system out there right now (Theres only like 3, so its not that big of a deal.)

I will certainly look into it.

[editline]25th June 2012[/editline]

Also,

[LUA]
–[[
There is a factor directly related to the type of firearms.
BulletVelocityFPS = Velocity of projectile and Gas
Ve = Velocity of projectile
High powered rifles BulletVelocityFPS = Ve x 1.75
Shotguns( averagele ngth) BulletVelocityFPS = Ve x 1.50
Shotguns (long barrel) BulletVelocityFPS = Ve x 1.25
Pistol & revolvers BulletVelocityFPS = Ve x 1.50
]]
[/LUA]

I mean that calculating the energy applied is only the firs step, you need to split the energy in to 2 vectors the one that pushes backwards and the one that pushes up.

http://cold.netburst.co.uk/file/Screenshot-2012-06-25_16.56.55.png

Aka so far you only calculated the red vector rather then the blue one. There are some example formulas on the wikipedia page for recoil that explain how to calculate the angular momentum.

Also when shooting a high caliber handgun the gun might fly skyhigh because of the recoil but you dont look up yourself after you shoot the thing.

I’ll say it again, since apparently you missed me the first time: I am aware.

Like I said before, I have a lack of information at the time in order to finish the complete equation, However I have attempted to simulate the general, more overall experience with the firearm.

On to of that, with my example about the KRISS, there have been developments to literally neutralize recoil on certain guns. Another would be the AA-12 Shotgun. If you are a fan of FPS Russia, go find his video. He fires it with one hand. I simply cannot make a formula that will hold for every single type of gun. Sorry, it does not exist with this much information missing.
With this taken into account, the entire system becomes even more complicated, almost to the point where it is not worth the effort to get just 1 gun working without about a few hours worth of research about that particular gun. The amount of manipulation needed would almost be overwhelming on the end-user’s part.

Therefore, I kept it simple. Calculate free-recoil, multiply by a factor related to the type of gun being fired, and give out the result. This way, it won’t take hours just to make a weapon. Give then weight of the gun, and the caliber it fired. Simple, and commonly found.

Also, regarding to the gun moving and your vision staying the same. The implementation would be that of the exact *opposite *of ViewPuch, which I hope you agree with me being stupid. It serves no point in making the player look straight and the gun rising. I would be doing the opposite with what I did in the beginning of the video. I would be looking straight down, and the gun would be firing on target. Generally, you want to keep your eyes down sights, am I right? So why move the sights away from the eyes of the player’s aim vector?

Regarding the game engine and real life physics? It simply isn’t possible in game without messing up game play with weapons entirely. In the HL2 engine, you cannot look one way, and aim another - it just does not make logical sense to do so. Thus I have simulated it instead, and locked it to the players aim vector.

If you do not like my implementation, simply don’t use it. OR, you could do the same research I had to do and go make your own little system. Simple as that. As far as I am aware, I am the only one to do something like this, I am happy with the results, and it is going to stay this way for gameplay’s sake. That is all.

1600x900 isn’t 1080p