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?
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)
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)
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.
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.