Improvements on Gun Sway?

I recently made this gun sway for my viewmodel, it works great but there are a few things that need improving.

Firstly, when you stop moving, the gun goes back to its original position, and it would be nicer if it would like stay at that position (or smoothly tween back to the original position not just instantly go back idk)

How would I make this more smooth? I’d also like to use this spring module to kinda make it bounce when the camera moves left right up down etc. I just don’t know how I would implement that, here’s what I’ve got atm.

function gunSway()
	local currentCFrame = camera.CFrame
	
	local t = tick() * (3/4)
	local x = math.cos(t * 5) * 0.05
	local y = math.abs(math.sin(t * 5)) * 0.05
	
	local cFrame = currentCFrame * CFrame.new(x, y, 0)
	viewModelHumRoot.CFrame = cFrame
end


local function updateViewModel() -- runs on renderStepped
	viewModel:SetPrimaryPartCFrame(camera.CFrame) -- update viewmodel to camera
			
	if humanoid.MoveDirection.Magnitude > 0 then
		gunSway() 
	end
end
3 Likes

(bumping lol still looking for help)

You could use this article Humanoid | Roblox Creator Documentation as a point of reference.
Something along the lines of this:

	if humanoid.MoveDirection.Magnitude > 0 then
		gunSway() 
    else  -- otherwise, not moving
        humanoid.CameraOffset = humanoid.CameraOffset * 0.75
	end
1 Like

Make sure you aren’t calling updateViewModel every 2 frames via wait(), since that’d obviously give you choppy gun sway. Instead call it every Heartbeat since it fires every frame and will be far smoother since it isn’t locked to 30hz like wait().

1 Like

I’m using RenderStepped and it works fine

Then there is no improvement needed on the gun sway.

Yeah but in the video, you can see how to arms reset to the original position when the sway finishes and it doesn’t look that good, any ideas on that?

Firstly, the gun is at a weird angle, I’d change that.

Secondly, for my gun sway in my game I use a renderstepped function with CFrame lerping paired with a variable that is set to true when you’re running. It goes something like this:

local running = false
local gunbobcf = CFrame.new()  -- CFrame to lerp

game:GetService("RunService").RenderStepped:Connect(function()

gun:SetPrimaryPartCFrame(
workspace.CurrentCamera.CFrame
* cframeToPositionGunOnCamera
* gunbobcf -- CRUCIAL - THIS MULTIPLIES THE CURRENT GUN CFRAME BY THE GUN BOB CFRAME

if running then
    gunbobcf = gunbobcf:Lerp(CFrame.new(
	0.14 * math.sin(tick() * 6), -- Intensity left/right * speed
	0.07 * math.sin(tick() * 12), -- Intensity up/down * speed
	-0.3 * math.sin(tick() * 6) -- Intensity back/forward * speed
				
	),	0.1)
else
    gunbobcf = gunbobcf:Lerp(CFrame.new(),0.1) -- returns gun to original CFrame once not running
end
end)

game.Players.LocalPlayer.Character.Running:Connect(function(speed)
    if speed < 0.1 then
        running = true
    end
end)
1 Like

This is BlackShibe’s implementation of gun sway using the awesome Spring Module

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

function handler:update(deltaTime)
        local finalOffset = equipOffset

		-- Let's get some mouse movement!
		local mouseDelta = game:GetService("UserInputService"):GetMouseDelta()
		if self.aiming then mouseDelta *= 0.1 end
		self.springs.sway:shove(Vector3.new(mouseDelta.X / 200, mouseDelta.Y / 200)
        local speed = 1
		-- modifier can be dependent on a value changed when you're aiming, or standing still, etc.
		-- this makes the bobble do more. or something.
		local modifier = 0.1

		if self.aiming then modifier = 0.01 end

		-- See? Bobbing! contruct a vector3 with getBobbing.
		local movementSway = Vector3.new(getBobbing(10, speed, modifier), getBobbing(5, speed, modifier),getBobbing(5, speed, modifier))

		-- if velocity is 0, then so will the walk cycle
		self.springs.walkCycle:shove((movementSway / 25) * deltaTime * 60 * velocity.Magnitude)

		-- Sway! Yay!
		local sway = self.springs.sway:update(deltaTime)
		local walkCycle = self.springs.walkCycle:update(deltaTime)
		self.viewmodel.rootPart.CFrame = self.camera.CFrame:ToWorldSpace(finalOffset)
		self.viewmodel.rootPart.CFrame = self.viewmodel.rootPart.CFrame:ToWorldSpace(CFrame.new(walkCycle.x / 4, walkCycle.y / 2, 0))

		-- Rotate our rootpart based on sway
		self.viewmodel.rootPart.CFrame = self.viewmodel.rootPart.CFrame * CFrame.Angles(0, -sway.x, sway.y)
		self.viewmodel.rootPart.CFrame = self.viewmodel.rootPart.CFrame * CFrame.Angles(0, walkCycle.y / 2, walkCycle.x / 5)

		
		
end

RenderStepped:Connect(update(dt))

1 Like

Yeah I’m tryna use that just don’t know how to put it in

1 Like

Haven’t read that sorry, you have to add this line at the very top of the script:

local spring = require(ReplicatedStorage.spring)
self.springs.walkCycle = spring.create();
self.springs.sway = spring.create()

Or maybe you wanted a de-OOP-ed version of the sway implementation

local camera=workspace.CurrentCamera
local viewmodel_camera=  --Enter camera part of your viewmodel
local rootPart= --Enter the primary part of your viewmodel
local spring = require(ReplicatedStorage.spring)
springs_walkCycle = spring.create()
springs_sway = spring.create()
local function getBobbing(addition, speed, modifier)
	return math.sin(tick()*addition*speed)*modifier
end

function update(deltaTime)
        local animatorCFrameDifference = lastReceiverRelativity or CFrame.new() *viewmodel_camera.CFrame:ToObjectSpace(rootPart.CFrame):Inverse()
		local x,y,z = animatorCFrameDifference:ToOrientation()
		workspace.Camera.CFrame = workspace.Camera.CFrame * CFrame.Angles(x, y, z)
		lastReceiverRelativity = viewmodel_camera.CFrame:ToObjectSpace(rootPart.CFrame)
        local velocity = character.HumanoidRootPart.Velocity
        local finalOffset = equipOffset

		-- Let's get some mouse movement!
		local mouseDelta = game:GetService("UserInputService"):GetMouseDelta()
		--if aiming then mouseDelta *= 0.1 end
		springs_sway:shove(Vector3.new(mouseDelta.X / 200, mouseDelta.Y / 200)
        local speed = 1
		-- modifier can be dependent on a value changed when you're aiming, or standing still, etc.
		-- this makes the bobble do more. or something.
		local modifier = 0.1

		if aiming then modifier = 0.01 end

		-- See? Bobbing! contruct a vector3 with getBobbing.
		local movementSway = Vector3.new(getBobbing(10, speed, modifier), getBobbing(5, speed, modifier),getBobbing(5, speed, modifier))

		-- if velocity is 0, then so will the walk cycle
		springs_walkCycle:shove((movementSway / 25) * deltaTime * 60 * velocity.Magnitude)

		-- Sway! Yay!
		local sway = springs_sway:update(deltaTime)
		local walkCycle = springs_walkCycle:update(deltaTime)
		rootPart.CFrame = camera.CFrame:ToWorldSpace(finalOffset)
		rootPart.CFrame = rootPart.CFrame:ToWorldSpace(CFrame.new(walkCycle.x / 4, walkCycle.y / 2, 0))

		-- Rotate our rootpart based on sway
		rootPart.CFrame = rootPart.CFrame * CFrame.Angles(0, -sway.x, sway.y)
		rootPart.CFrame = rootPart.CFrame * CFrame.Angles(0, walkCycle.y / 2, walkCycle.x / 5)

		
		
end

game:GetService("RunService").RenderStepped:Connect(update(dt))
2 Likes