My recoil recovery system ALMOST works but there is a bug!

I’m making a recoil recovery system for my game, and it almost works (the camera goes down after I fire) but the problem is when its recovering, sometimes it will recover TOO much making it go past my original camera position which is not what I want. (There is also other weird bugs that happen with the camera sometimes)

Recovery:

RunService.PreRender:Connect(function()
    if recoil > 0 then
        currentCamera.CFrame *= CFrame.Angles(math.clamp(math.rad(-recoilTraveled), cameraRecoilStart.X, math.huge), 0, 0)
        
        recoil = math.clamp(recoil - 0.01, 0, math.huge)
    elseif recoil <= 0 then
        local x, y, z = currentCamera.CFrame:ToEulerAnglesXYZ()
        cameraRecoilStart = Vector3.new(x, y, z)
    end
end)

Function triggering recoil:

function recoilShove()
    currentCamera.CFrame = currentCamera.CFrame * CFrame.Angles(math.rad(recoil), 0, 0)
    recoilTraveled = math.rad(recoil)
end
1 Like

The issue is this line (I think):

currentCamera.CFrame *= CFrame.Angles(math.clamp(math.rad(-recoilTraveled), cameraRecoilStart.X, math.huge), 0, 0)

It keeps rotating the camera every single frame and it doesn’t track how much it has already recovered and so it overshoots.

I would start by creating a variable called “recovered” to track how much it has recovered so far and stop.

Here’s the final script:

local recovered = 0

RunService.PreRender:Connect(function()
    if recoil > 0 then
        local step = math.min(0.01, recoil)
        local angle = math.rad(step)

        currentCamera.CFrame *= CFrame.Angles(-angle, 0, 0)

        recovered += angle
        recoil -= step
    elseif recoil <= 0 then
        local x, y, z = currentCamera.CFrame:ToEulerAnglesXYZ()
        cameraRecoilStart = Vector3.new(x, y, z)
        recoil = 0
        recoilTraveled = 0
        recovered = 0
    end
end)

And then you can also change your recoilShove function to reset in-case it is mid recovery:

function recoilShove()
    local angle = math.rad(recoil) 
    currentCamera.CFrame *= CFrame.Angles(angle, 0, 0)
    recoilTraveled = angle
    recoil = recoil 
    recovered = 0 
end

I’m assuming recoil is a degree value.

1 Like

Thanks but I got this same answer from AI and it just makes it go back to the camera position from the most recent shot

Sorry to hear it didn’t work, yeah I guess adding a recovered variable is the simple way to think about it.

Have you tried storing the cameraRecoilStart CFrame before the recoil so it can position back?

Like this:

local recovered = 0
local recoilTraveled = 0
local cameraStartRecoil = nil 

RunService.PreRender:Connect(function()
	if recoil > 0 and cameraRecoilStart then
		local step = math.min(0.01, recoil)
		local angle = math.rad(step)

		currentCamera.CFrame *= CFrame.Angles(-angle, 0, 0)

		recovered += angle
		recoil -= step

		if recovered >= recoilTraveled then
			currentCamera.CFrame = cameraRecoilStart
			recoil = 0
			recovered = 0
			recoilTraveled = 0
			cameraStartRecoil = nil
		end
	end
end)

And then this for the recoilShove function:

function recoilShove()
	cameraRecoilStart = currentCamera.CFrame

	local angle = math.rad(recoil)
	currentCamera.CFrame *= CFrame.Angles(angle, 0, 0)

	recoilTraveled = angle
	recovered = 0
end