Issues with Recoil using Physics Based Spring Module V2.0

I’m having issues with the recoil of my guns, using Physics Based Spring Module V2.0, being consistent across different framerates.

I’ve tried applying DeltaTime to many different values , none of which made the recoil consistent (should only need be where it is applied to camera). Let me go ahead and share some relevant code samples.

local RecoilSpring = RecoilModule.fromFrequency(1, 0, 3)
RecoilSpring:SnapToCriticalDamping() --Gives less of a "springy" effect

function Activate_Weapon()
	if inventory.viewmodel and not Shoot_Debounce then
		Shoot_Debounce = true

		--// Actions
		task.spawn(function()
			local result = Remotes.Functions.ActivateWeapon:InvokeServer(inventory.viewmodel.AimPart.CFrame, inventory.viewmodel.FrontSidePart.CFrame.Position)
		end)

		RecoilSpring:AddVelocity(1)

		--// Cooldown
		task.wait(60 / inventory.data.Weapon_Settings.FireRate)
		Shoot_Debounce = false
	end
end

RunService.RenderStepped:Connect(function(DeltaTime)
    if isShooting then
        Activate_Weapon()
    end

    camera.CFrame *= CFrame.Angles(RecoilSpring.Velocity * DeltaTime, 0, 0)
end)

I’m not sure exactly what the issue is, but there is a difference with how many times the Activate_Weapon() function is being called. I’m afraid that between the cooldown and the fact that it is executed/checked less on a lower refresh rate experience, that it isn’t applying the Velocity to the RecoilSpring as often as it is on a higher fps experience. This is also true to the amount of server requests that are received.

Here is some footage of the comparison between 60 fps and 240 fps:
robloxapp-20250202-1607348.wmv (1.8 MB)

I’ve tried changing the frequency each frame to match the DeltaTime, but that didn’t make it consistent. Updating the amount of velocity added each time it to compensate for DeltaTime also didn’t do anything. I slowed down the firerate to about 300 RPM and it appeared to make the server side consistent, but the recoil is wildly different.

Try adding in the acceleration component of the spring as well:

camera.CFrame *= CFrame.Angles(RecoilSpring.Velocity* DeltaTime + 0.5 * RecoilSpring.Acceleration * DeltaTime^2, 0, 0)

this should more accurately reflect the current offset of the spring since it more accurately follows the integration of the velocity over the time dt.

Also, using the classic kinematic equations:

x = x0 + vt + 0.5at^2

2 Likes

That worked perfectly! I was also having issues with it returning to the exact point that it started at, and it fixed that problem. Thank you for putting together this module!

1 Like

No problem, glad I could help!

1 Like

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