I’ve been struggling to get this issue to work for months now. Im trying to make my weapon sway in a realistic way to add some dynamic movements to my game. I don’t want to use animations because it doesn’t have the effect I want. Here are my scripts.
local Spring = {};
function Spring.New(Position, Velocity, Target, K, Damper)
local NewSpring = {
Position = Position;
Velocity = Velocity;
Target = Target;
K = K or 1;
Damper = Damper or 1;
};
function NewSpring:Update(Target, K, Damper)
NewSpring.Target = Target or NewSpring.Target;
NewSpring.K = K or NewSpring.K;
NewSpring.Damper = Damper or NewSpring.Damper;
local Distance = (NewSpring.Target - NewSpring.Position);
local Force = (Distance * NewSpring.K);
NewSpring.Velocity = ((NewSpring.Velocity * (1 - NewSpring.Damper)) + Force);
NewSpring.Position = (NewSpring.Position + NewSpring.Velocity);
return NewSpring.Position;
end;
return NewSpring;
end;
return Spring;
Local Script:----------------------------------------------
function runFramework()
CurrentEquipped = GunsFolder[Primary]:Clone()
CurrentEquipped.Parent = camera
local SpringModule = require(workspace.Spring)
local Spring = SpringModule.New( CurrentEquipped:GetPrimaryPartCFrame().p, Vector3.new(), (camera.CFrame * CFrame.new(1,-1,-2)).p, 0.5, 1)
RunService.RenderStepped:Connect(function()
local springPosition = (camera.CFrame * CFrame.new(1,-1,-2)).Position
local update = Spring:Update(springPosition)
local springCFrame = CFrame.new(update) * CFrame.Angles(camera.CFrame:ToEulerAnglesXYZ())
-- CurrentEquipped:SetPrimaryPartCFrame(CurrentEquipped:GetPrimaryPartCFrame():lerp(camera.CFrame * CFrame.new(1,-1,-2), 0.3) )
CurrentEquipped:SetPrimaryPartCFrame(springCFrame)
end)
end
runFramework()
Players.PlayerAdded:Connect(runFramework)
WHAT DOESN’T WORK:
-Bind to renderstepped (putting it above and below the camera value
-Lerping ( Still jitters or moves too slowly for my liking)
-Accounting for time missed (delta) heres a link to what I mean
So thats pretty much it. I would really love assistance on this because i have absolutely no idea what to do.
I’ve writen an method on how to get nice and smooth sway here.
It has nothing to do with springs tho so it might not be exactly what you need but if you’re interrested you can check it out.
Also does the gun without sway stutter too or does it only stutter when sway is applied? (Disable sway and movearound to test it)
Before i get into giving you some better spring code, I’d first recommend you do NOT use setprimarypartcframe for anything that’s going to be run on a frame to frame basis. It is not performant and has known floating point imprecision issues. You are much better off welding everything to a core part/primary part, and just setting the cframe of that object using .CFrame =
Now let me give you something from my fps.
Spring code
local spring = {}
function spring.new(position, velocity, target)
local self = setmetatable({}, {__index = spring})
self.position = position
self.velocity = velocity
self.target = target
self.k = 0.1
self.d = 0.4 -- friction constant
return self
end
function spring:update()
local x = self.target - self.position
local f = x * self.k
self.velocity = (self.velocity * (1 - self.d)) + f
self.position = self.position + self.velocity
end
Pseudo framework
local viewModel = {}
viewModel.SwayVector = Vector2.new(0,0)
viewModel.SwaySpring = spring.new(Vector3.new(0,0,0),Vector3.new(0,0,0),Vector3.new(0,0,0))
viewModel.NeckOffset = CFrame.new()
game:GetService('UserInputService').InputChanged:connect(function(inputObject)
if inputObject.UserInputType == Enum.UserInputType.MouseMovement then
local vec = Vector2.new(inputObject.Delta.X,inputObject.Delta.Y)
viewModel.SwayVector = viewModel.SwayVector + vec
end
end)
while game:GetService('RunService').RenderStepped:wait() do
local MaxSway = 150
if AIMING then
MaxSway = 5
end
local x = math.clamp(viewModel.SwayVector.X, -MaxSway, MaxSway)
local y = math.clamp(viewModel.SwayVector.Y, -MaxSway, MaxSway)
viewModel.SwaySpring.target = Vector3.new(x,y,0)
viewModel.SwaySpring:update()
viewModel.NeckSway = CFrame.new() * CFrame.Angles(-math.rad(viewModel.SwaySpring.position.Y/5),-math.rad(viewModel.SwaySpring.position.X/5),0)
viewModel.SwayVector = Vector2.new()
if not game.Players.LocalPlayer.Character then
break
end
end
I’ve noticed what I provided was actually sway for moving the gun when you move your mouse left to right, and you wanted something for walk direction velocity. I’m happy to provide that as well if you need it, it uses the same spring system.
hey man, im sorry for the super late reply. Could you also help me with the walk direction velocity? That would be great.
Also what am i supposed to do with the
local viewModel = {}
i get the error that SwayVector isnt a part of model (which it isnt)
Hey, sorry for the late reply. It doesn’t stutter when the sway isnt applied. I had a look at your code and i have no idea how to implement it. This is what i tried.
local mult = 1
local swayOffset = CFrame.new(1,-2,1)
function renderloop() --bind this camera render loop
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
hands.CFrame = hands.CFrame * swayOffset --apply the sway
lastCameraCF = workspace.CurrentCamera.CFrame --update the last cframe
end
i ended up teleporting under the map for some reason.
Are hands connected to the humanoid? You need to cframe the gun handle not the player hands. If you teleport the hands while they’re connected to the humanoid you’ll begin to teleport around.
Ah I see.
First off you’ll need to change swayOffset = CFrame.new(1,-2,1)
into swayOffset = hands.CFrame
Sorry my original code didn’t provide this for some reason.
Anyways the current code is teleporting the hands around and since the swayOffset was 1,-2,1 it teleported the humanoid inside of the baseplate.
I’ll tell you what my setup was so you’ll better understand the code:
I had a main part named gun. All of the gun parts were connected to this single part using motor6ds. This main part itself was constantly being cframed to the players head. Then I apply the sway onto the main part and because of the motor6ds all of the gun parts moved along.
You can weld your gun model and move the primarypart CFrame in relation to the UpperTorso (R15) or Torso (R6). I’ve heard of some people using the head as a relative point but, I don’t see a reason why the Torso wouldn’t work.