Recoil depends on the FPS

I’m currently working on a recoil system, and in the process, I found a spring module that I plan to use. However, I’ve encountered an issue: the intensity of the recoil varies based on the player’s frames per second (FPS). How can I address this problem? Is there a formula I could implement within the update(DeltaTime) function to standardize the recoil regardless of FPS fluctuations?

Module:
SpringModule.rbxm (1.3 KB)

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local camera = game.Workspace.Camera

local RecoilSpring = require(script.SpringModule).new()

local function FireRecoil()
	local Amount = Vector3.new(4, 0, 4) -- X = Vertical, Y = Horizontal, Z = Shake.
	RecoilSpring:shove(Amount)
end

RunService.RenderStepped:Connect(function(DeltaTime)
	local UpdatedRecoilSpring = RecoilSpring:update(DeltaTime) --<<-- Problem
	camera.CFrame *= CFrame.Angles(math.rad(UpdatedRecoilSpring.X), math.rad(UpdatedRecoilSpring.Y), math.rad(UpdatedRecoilSpring.Z))
end)

UserInputService.InputBegan:Connect(function(Input)
	if Input.UserInputType == Enum.UserInputType.MouseButton1 then
		FireRecoil()
	end
end)

Recreation of the problem (Full Game)
FPSdependent.rbxl (51.1 KB)

Thanks!

2 Likes

If I understand correctly, in your game bullets come out of the gun instead of the face (as many games do) so where the gun is pointed matters a lot?

What I would do is instead adjust the script that points the gun toward where the player is looking to have a offset upwards. my opinion though.

The problem actually happens on the line that comes after the one you marked as “Problem”. Since you’re updating camera.CFrame each frame, that means the more FPS you have, the more times you update the camera position.
A possible fix would be to run an update every X amount of seconds:

local totalTime = 0
local stepTime = 1/120
RunService.RenderStepped:Connect(function(DeltaTime)
	totalTime = math.min(totalTime + DeltaTime, 1) -- Limit maximum amount of steps to avoid freezes
	while totalTime > stepTime do
		UpdateCamera(stepTime) -- Move your spring and camera updates into that function
		totalTime -= stepTime
	end
end)

This is not an optimal solution however, and might have problems.

P.S.:
After looking at the SpringModule that you provided, it looks like the update function returns the Position of the spring. The problem is that you need the difference between current and previous position.
So here is another solution that might work (replace the current RenderStepped event with this):

local OldPosition = RecoilSpring.Position
RunService.RenderStepped:Connect(function(DeltaTime)
	local NewPosition = RecoilSpring:update(DeltaTime)
	local diff = NewPosition - OldPosition
	OldPosition = NewPosition
	camera.CFrame *= CFrame.Angles(math.rad(diff.X), math.rad(diff.Y), math.rad(diff.Z))
end)
4 Likes

It works excellent, the bad thing is that it makes the recoil work totally different.

Before

After


The recoil moves faster and for some reason at the end of the recoil movement the camera returns to the original position

2 Likes

The recoil moves faster and for some reason at the end of the recoil movement the camera returns to the original position

Because that’s how the spring actually works. When you call shove, you apply instant velocity, but the target position stays at 0,0,0, so the sum of all position differences that are applied to the camera will be 0.

P.S.: “After” looks much better than “Before”, and much more like a recoil.

1 Like

You know what? You’re right. After making several adjustments, the recoil looks better. The downside is that controlling the recoil becomes much more difficult.

1 Like

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