I am working on a knife system, and to spoof it up a bit, I’ve added a first person arms for players who prefer first to third person gameplay. Currently it follows the knife animations, though it is static in that it sticks with the camera. Which is fine on its own, but I would like to go one step further to make it prettier.
So, my goal is to have smooth, fluid motion in the arms whenever the player turns his or her camera to the left or the right.
The game KAT has a good demonstration of what I am aiming for:
I have tried using TweenService and linear interpolation (though may have been incorrectly, I’m not sure). Each method I have tried results in sorta what I want, but it’s not smooth. It is very choppy and visibly hard to watch.
If you have any suggestions or have any tips on ways to achieve this, I would be very grateful. Thank you.
What you are looking for is commonly called “weapon sway”
This is how I would implement it:
Find how much the camera has moved compared with the last frame
Interpolate arms accordingly
local oldCamraCFrame = CFrame.new()
local swayCFrame = CFrame.new()
local x,y,_ = OldCameraCFrame:ToObjectSpace(workspace.CurrentCamera.CFrame):ToEulerAnglesXYZ()
SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(x,y,0), 0.1)
OldCameraCFrame = workspace.CurrentCamera.CFrame
--However you set the arms model cframe, just * the SwayCFrame to it
armsModel.CFrame = workspace.CurrentCamera.CFrame * SwayCFrame
It might look choppy because I used Gyazo (A .gif maker) to record the clip.
If it’s still too choppy after implementation, you could always play around with the second parameter on the :Lerp() function.
Yep the tutorial also does that. Though the tutorial uses mouse delta which also coincidentally correlates with the camera movement.
-- Let's get some mouse movement!
local mouseDelta = game:GetService("UserInputService"):GetMouseDelta()
self.springs.sway:shove(Vector3.new(mouseDelta.x / 200,mouseDelta.y / 200)) --not sure if this needs deltaTime filtering
--vs my wut CFrame approach
local differenceCF = previousGoalCFrame:ToObjectSpace(goalCFrame)
local axis, angle = differenceCF:ToAxisAngle()
local angularDisplacement = axis*angle
previousGoalCFrame = goalCFrame
local springForce = angularDisplacement*deltaSensitivity