Whats the best way to make gun sway?

So the question is pretty straight to the point,
What’s the best way to make gun sway?

Should I use an animation?
I saw someone mention using sine waves.

What’s the best way?

Thanks in advance :slight_smile:

14 Likes

Animations would work on loop. You could also generate random numbers and tween / cframe stuff in the respective direction.

2 Likes

Ill try animations. I’ll loop it and use easing in and such. Thanks!

1 Like

Usually gun sways are done using damped harmonic oscillators (springs) or spring constraints. Animations wouldn’t really accomplish what you need since they’re concrete and tweening would require custom easing implementations and overrides.

2 Likes

What I did is use sin waves to generate smooth recoil.

local mult = 1
local swayOffset = CFrame.new()
local lastCameraCF = workspace.CurrentCamera.CFrame

function renderloop() --bind this camera render loop
    local rotation = workspace.CurrentCamera.CFrame:toObjectSpace(lastCameraCF) --get cframe delta.
    local x,y,z = rotation:ToOrientation() --I'm sure there are better ways to get rotation but this will work for now.
    swayOffset = swayOffset:Lerp(CFrame.Angles(math.sin(x)*mult,math.sin(y)*mult,0), 0.1) --calculate the sway using SIN
    gun.CFrame = gun.CFrame * swayOffset --apply the sway
    lastCameraCF = workspace.CurrentCamera.CFrame --update the last cframe
end

This should get you nice and smooth recoil to any object you apply it to. Here is a video of it being applied in my framework (mult = 6):

(Sorry for not having tabs in the code example, when I pressed tab it didn’t want to place it.)

76 Likes

Hey there!
I’m a little new to scripting. I’ve binded your curve function, but I’m not sure how to get the lastCameraCF. Help?
Thanks!

1 Like

I think just before the loop, you can write this line:

lastCameraCF = workspace.CurrentCamera.CFrame --update the last cframe

Then you should have the initial camera CFrame. I don’t remember exactly what I did anymore, I remember changing a lot and adding to it a little.

4 Likes

I am going to get my toes cut off for bumping this topic but, I’m not exactly sure how to implement this into my existing framework, if I multiply the gun CFrame by swayoffset it does nothing.

My code:

			local mult = 6
			local swayOffset = CFrame.new()
			local lastCameraCF = workspace.CurrentCamera.CFrame
			local rotation = workspace.CurrentCamera.CFrame:toObjectSpace(lastCameraCF) --get cframe delta.
			local x,y,z = rotation:ToOrientation() --I'm sure there are better ways to get rotation but this will work for now.
			swayOffset = swayOffset:Lerp(CFrame.Angles(math.sin(x)*mult,math.sin(y)*mult,0), 0.1) --calculate the sway using SIN
			lastCameraCF = workspace.CurrentCamera.CFrame --update the last cframe
			
			local guncf = (
				lastCameraCF*swayOffset*
				gunset.camcoord* -- General gun offset
				script.Walk.Value* -- Walk animation offset
				script.Aim.Value* -- Aim offset
				roffset* -- Reload offset
				recoil -- And the reload offset
			)
			
			loadout.current:SetPrimaryPartCFrame(guncf) -- Loadout.current is the players current gun, for context

Removing every other offset applied doesn’t make a change either. I can’t tell what I messed up?

Also this is put in a renderstepped function, and the swayoffset is changing, since it will print the cframe if I print it

2 Likes

just use

local function getBobbing(addition, speed, modifier)
	return math.sin(tick() * addition * speed) * modifier
end