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