Need help adding visual recoil (camera shake) - how?

I have a recoil system that currently just offsets your camera by a little bit, but the issue with it is that it can be completely nullified by just moving your mouse, resulting in practically no recoil

I came up with an idea to add ‘visual recoil’ on top of the gun recoil that cannot be controlled/nullified, but i’m not really sure how to implement it

What i want to do is;
Apply the normal gun recoil, but on top of that gun recoil, apply the camera shake
the camera should end up being the same as it was without any visual recoil (so basically what i have right now)


Since that explanation sucks absolute balls, i draw:


To make the ‘with’ section understandable, the gun recoil shouldn’t just make the camera bounce like that, the visual recoil is responsible for that.

The gun recoil should remain the same (Straight line A → B), while the visual recoil just shakes the camera.

I do not want the camera to ‘overflow’, i do not want it to go downwards when travelling, like this:


i think that explanation is very understandable, and i hope i get help :pray:

local function ApplyDeltaRotation(currentX, currentY, currentZ, lastX, lastY, lastZ)
	local deltaX = currentX - lastX
	local deltaY = currentY - lastY
	local deltaZ = currentZ - lastZ

	local deltaRotation = CFrame.Angles(deltaX, deltaY, deltaZ)
	camera.CFrame *= deltaRotation

	return currentX, currentY, currentZ
end

local function ApplyRecoil(gunData: {})
	local recoilTweak: NumberValue = utility.GetGameplayValue('recoilTweak')
	local elapsed = 0
	local applying = true
	local renderStepped: RBXScriptConnection = nil
	
	local lastX, lastY, lastZ = 0, 0, 0
	local recoilStrength = gunData.recoilStrength
	local kickTime = gunData.kickTime
	local recoveryTime = gunData.recoveryTime
	
	if renderStepped then
		renderStepped:Disconnect()
	end
	
	local x, y, z = recoilStrength:ToEulerAnglesXYZ()
	x /= recoilTweak.Value
	y /= recoilTweak.Value
	z /= recoilTweak.Value
	
	renderStepped = rService.PreRender:Connect(function(deltaTime)
		local alpha
		if applying then
			alpha = math.clamp(elapsed / kickTime, 0, 1)
			if alpha >= 1 then
				applying = false
				elapsed = 0
			end
		else
			alpha = 1 - math.clamp(elapsed / recoveryTime, 0, 1)
			if alpha <= 0 then
				local removeX = -lastX
				local removeY = -lastY
				local removeZ = -lastZ
				local removeRotation = CFrame.Angles(removeX, removeY, removeZ)
				
				camera.CFrame *= removeRotation renderStepped:Disconnect()
				return
			end
		end
		
		local currentX = x * alpha
		local currentY = y * alpha
		local currentZ = z * alpha
		
		lastX, lastY, lastZ = ApplyDeltaRotation(currentX, currentY, currentZ, lastX, lastY, lastZ)
		elapsed += deltaTime
	end)
end
1 Like

to somewhat elaborate;
i want each gun to have different visual recoil values, i already have this setup
i just don’t really know how to apply them:
image

are you fine with using the screenshake module by sleitnick? i used his module and i was able to get pretty good camera recoil with it

i can use anything, i just want to make something like this :sob::pray:

Okay so i got my hands on that ShakeModule from sleitnick’s rbx utils, and while most of the time it works really well, sometimes it does this really weird ‘strong upwards’ kick that i’m not really sure why happens

considering you’ve used the module before, i’ll just ask you for help

local function ApplyRecoil(gunData: {})
	local recoilTweak: NumberValue = utility.GetGameplayValue('recoilTweak')
	local elapsed = 0
	local applying = true
	local renderStepped: RBXScriptConnection = nil
	
	local lastX, lastY, lastZ = 0, 0, 0
	local visualLastX, visualLastY, visualLastZ = 0, 0, 0
	
	local recoilStrength = gunData.recoilStrength
	local kickTime = gunData.kickTime
	local recoveryTime = gunData.recoveryTime
	
	local visualRecoilIntensity = gunData.visualRecoilIntensity / recoilTweak.Value
	local visualRecoilDecay = gunData.visualRecoilDecay
	local visualRecoilSpeed = gunData.visualRecoilSpeed
	local maxVisualRecoil = gunData.maxVisualRecoil
	
	local visualRecoil = shakeModule.new()
	
	visualRecoil.Amplitude = visualRecoilIntensity
	visualRecoil.Frequency = visualRecoilSpeed
	visualRecoil.FadeInTime = 0
	visualRecoil.FadeOutTime = visualRecoilDecay
	visualRecoil.SustainTime = kickTime
	visualRecoil.Sustain = false
	visualRecoil.RotationInfluence = Vector3.new(maxVisualRecoil, 0.2, 0.2)
	visualRecoil.PositionInfluence = Vector3.zero
	visualRecoil:Start()
	
	if renderStepped then
		renderStepped:Disconnect()
	end
	
	local x, y, z = recoilStrength:ToEulerAnglesXYZ()
	
	x /= recoilTweak.Value
	y /= recoilTweak.Value
	z /= recoilTweak.Value
	
	renderStepped = rService.PreRender:Connect(function(deltaTime)
		local alpha
		if applying then
			alpha = math.clamp(elapsed / kickTime, 0, 1)
			if alpha >= 1 then
				applying = false
				elapsed = 0
			end
		else
			alpha = 1 - math.clamp(elapsed / recoveryTime, 0, 1)
			if alpha <= 0 then
				local removeX = -lastX
				local removeY = -lastY
				local removeZ = -lastZ
				local removeRotation = CFrame.Angles(removeX, removeY, removeZ)
				
				camera.CFrame *= removeRotation			
				renderStepped:Disconnect()
				return
			end
		end
		
		local currentX = x * alpha
		local currentY = y * alpha
		local currentZ = z * alpha				
		lastX, lastY, lastZ = ApplyDeltaRotation(currentX, currentY, currentZ, lastX, lastY, lastZ)
		
		local _, rot, done = visualRecoil:Update(deltaTime)
		if rot then
			local visualX = math.max(0, rot.X)
			local recoilRotation = CFrame.Angles(visualX, 0, rot.Z)
			camera.CFrame *= recoilRotation
		end
		
		if done then
			visualRecoil:Stop()
		end
		
		elapsed += deltaTime
	end)
end

if i did anything wrong (which i probably did), please let me know

try using shakeonce

30charaaaarrrrrrrrrssssssssss

i forgot to reply

i ended up clamping visualX since that was causing those random spikes
thank you very much aeonyx0 very appreicated

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.