Help with viewmodel swaying script

So I was working on a viewmodel swaying script for a game, but the script I tried wasn’t working properly, it just makes the viewmodel disappear. I have no idea as to why this is happening, and I haven’t found a solution to this problem yet, so if someone could show me how to fix the script, I’d be incredibly thankful!


Local script inside of a tool:

local plr = game.Players.LocalPlayer
local char = script.Parent.Parent
local cam = workspace.Camera
local run = game:GetService("RunService")
local viewModelCFrame = CFrame.new()
local currentCam = game.Workspace.CurrentCamera
local oldPos = CFrame.new(0,0,0)
local stopped=false


script.Parent.Equipped:Connect(function()
	local arms = game.ReplicatedStorage.ViewModels.Arms:Clone()
	
	local mult = 6
	local lastCameraCF = cam.CFrame
	local swayOffset = CFrame.new()
	coroutine.wrap(function()
		run:BindToRenderStep("CameraRender", Enum.RenderPriority.Camera.Value + 1, function()
			local rotation = cam.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
			arms.PartHumanoid.CFrame = arms.PartHumanoid.CFrame * swayOffset --apply the sway
			lastCameraCF = cam.CFrame --update the last cframe
		end)
	end)()
	
	local connection = run.RenderStepped:Connect(function()
		if game.Players.LocalPlayer.Character.Head.LocalTransparencyModifier == 1 then
			
			arms.Parent = cam
			script.Parent.Handle.LocalTransparencyModifier = 1		
						
			if game.Players.LocalPlayer.Character.Humanoid.MoveDirection.Magnitude > 0 then
				
				local iTime = os.clock()
				local bounce = math.sin(iTime*9)
				if bounce >= 0 then
					bounce = -bounce
				end
				
				viewModelCFrame = viewModelCFrame:Lerp(CFrame.new(math.cos(iTime*9),-1 + bounce, 0), 0.035)
				arms:SetPrimaryPartCFrame(cam.CFrame * viewModelCFrame)
			else
				viewModelCFrame = viewModelCFrame:Lerp((CFrame.new(0,-2,0)),.1)
				arms:SetPrimaryPartCFrame(cam.CFrame * viewModelCFrame)
			end
			
			if(cam.CFrame ~= oldPos) then
				print("MOVED")
				oldPos = cam.CFrame
				arms:SetPrimaryPartCFrame(
					cam.CFrame *
					lastCameraCF
				)
			else
				if(stopped==false) then
					stopped=true
					print("STOPPED")
				end
			end
			
		else
			arms:SetPrimaryPartCFrame(cam.CFrame * CFrame.new(0,-1000000,0))
			script.Parent.Handle.LocalTransparencyModifier = 0
		end
	end)
	
	script.Parent.Unequipped:Connect(function()
		connection:Disconnect()
		arms:Destroy()
	end)
	
end)



WARING: THIS SCRIPT IS PROBABLY REALLY HACKY AND IS TERRIBLE TO READ.

Any help is appreciated!

1 Like

Are you trying to make sway when the player looks around?
if you are, I have a solution

1 Like

Yes, I am trying to do that, I have already have a way that makes the arms bobble when the player walks, so the swaying system should be compatible with that.

Okay so make a new CFrame variable and call it whatever you want
I called mine SwingCF

SwingCF = CFrame.new()

I also made another CFrame variable called CameraCF and set it to the camera CFrame

CameraCF = cam.CFrame()

I made an integer for both x and y

local SwingX = 2
local SwingY = 4

These 2 variables control how much swing you want. the higher, the more swing.
I put these variables at the beginning of the script
in the render stepped function, I made a new variable called rotation and set it to the cameras toObjectSpace Cframe

local rotation = workspace.CurrentCamera.CFrame:toObjectSpace(CameraCF)

after this I made a new variable called x, y and set it to rotation:ToOrientation()

local x,y = rotation:ToOrientation()

This is the most complicated line in the script.
I set SwingCF to a lerp function and it’s tough to explain so I’m just going to post it.

SwingCF = SwingCF:Lerp(CFrame.new(math.sin(-y)*SwingX,math.sin(x)*SwingY,0), .2)

This is if you want it to move left right up and down
if you want it to turn

SwingCF = SwingCF:Lerp(CFrame.Angles(math.sin(x)*SwingX,math.sin(y)*SwingY,0), .2)

If they are backwords or one is not swinging the right direction, make x or y negitive or positive or swap them
and the last step is to put this line again

CameraCF = cam.CFrame

Sorry I missed a step. in the arms:SetPrimaryPartCFrame() multiply SwingCF by cam.CFrame()

2 Likes

Quick question, do I delete this part of the script, since it was the old way of making the gun sway?

coroutine.wrap(function()
		run:BindToRenderStep("CameraRender", Enum.RenderPriority.Camera.Value + 1, function()
			local rotation = cam.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
			arms.PartHumanoid.CFrame = arms.PartHumanoid.CFrame * swayOffset --apply the sway
			lastCameraCF = cam.CFrame --update the last cframe
		end)
	end)()

I would put that function in comments, and try it and if it doesn’t work, you still have that code
Hold up, place the code in the function into the render stepped function and I think you should be good.

1 Like

What do you mean?

(Extra characters yaaaaaa)]

EDIT: I figured out what you mean, I tried to do that, but the same thing happened.


Updated script:

local plr = game.Players.LocalPlayer
local char = script.Parent.Parent
local cam = workspace.Camera
local run = game:GetService("RunService")
local viewModelCFrame = CFrame.new()
local currentCam = game.Workspace.CurrentCamera
local oldPos = CFrame.new(0,0,0)
local stopped=false


script.Parent.Equipped:Connect(function()
	local arms = game.ReplicatedStorage.ViewModels.Arms:Clone()
		
	local connection = run.RenderStepped:Connect(function()
		
		local mult = 6
		local lastCameraCF = cam.CFrame
		local swayOffset = CFrame.new()
		coroutine.wrap(function()
			run:BindToRenderStep("CameraRender", Enum.RenderPriority.Camera.Value + 1, function()
				local rotation = cam.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
				arms.PartHumanoid.CFrame = arms.PartHumanoid.CFrame * swayOffset --apply the sway
				lastCameraCF = cam.CFrame --update the last cframe
			end)
		end)()

		
		if game.Players.LocalPlayer.Character.Head.LocalTransparencyModifier == 1 then
			
			arms.Parent = cam
			script.Parent.Handle.LocalTransparencyModifier = 1		
						
			if game.Players.LocalPlayer.Character.Humanoid.MoveDirection.Magnitude > 0 then
				
				local iTime = os.clock()
				local bounce = math.sin(iTime*9)
				if bounce >= 0 then
					bounce = -bounce
				end
				
				viewModelCFrame = viewModelCFrame:Lerp(CFrame.new(math.cos(iTime*9),-1 + bounce, 0), 0.035)
				arms:SetPrimaryPartCFrame(cam.CFrame * viewModelCFrame)
			else
				viewModelCFrame = viewModelCFrame:Lerp((CFrame.new(0,-2,0)),.1)
				arms:SetPrimaryPartCFrame(cam.CFrame * viewModelCFrame)
			end
			
			if(cam.CFrame ~= oldPos) then
				print("MOVED")
				oldPos = cam.CFrame
				arms:SetPrimaryPartCFrame(
					cam.CFrame *
					lastCameraCF
				)
			else
				if(stopped==false) then
					stopped=true
					print("STOPPED")
				end
			end
			
		else
			arms:SetPrimaryPartCFrame(cam.CFrame * CFrame.new(0,-1000000,0))
			script.Parent.Handle.LocalTransparencyModifier = 0
		end
	end)
	
	script.Parent.Unequipped:Connect(function()
		connection:Disconnect()
		arms:Destroy()
	end)
	
end)



local rotation = cam.CFrame:toObjectSpace(lastCameraCF) 
local x,y,z = rotation:ToOrientation()
swayOffset = swayOffset:Lerp(CFrame.Angles(math.sin(x)*mult,math.sin(y)*mult,0), 0.1) 
arms.PartHumanoid.CFrame = arms.PartHumanoid.CFrame * swayOffset 
lastCameraCF = cam.CFrame 

Put this code in this function
local connection = run.RenderStepped:Connect(function()

end)

1 Like

The same thing happens, the arms just disappear whenever you move, but whenever you unequip the tool, there are no errors this time, so that has fixed one thing. Should I just use your solution to said in post 4?

maybe because of this
arms:SetPrimaryPartCFrame(cam.CFrame * CFrame.new(0,-1000000,0))

1 Like

That didn’t fix it, if that was the issue, the tool would become visible for the player, because of this line of code: script.Parent.Handle.LocalTransparencyModifier = 0,
but the tool stays invisible even when I move the camera.

try and put a print(“sucess”) after that line and see if it returns

1 Like

I did a print functions around the script, I have concluded that the reason why the script isn’t working right, is the swaying part. I am pretty sure some of the setting aren’t compatible for my view model, so I will have to change the setting for the script. Any ideas on what settings I should change?

There’s also SetPrimaryPartCFrame() this function might get removed in the future so switch it out for :PivotTo() and it should stay the same

Do they function exactly the same, or will I have to change some parts of my script?

They do the exact same thing (30 funny characters )

1 Like

Do you have any ideas on what settings I should change to make the arms actually sway?

I’m not sure man, sorry. my last idea is to only set the PivotTo/SetPrimarypartCFrame once because you only need one in the renderStepped function other than in every if statement

1 Like

If this helps you, this is my render stepped function for my weapon framework

script.Parent.Equipped:Connect(function()
	model.Parent = camera
	IsEquipped = true
	unequipCF = CFrame.new()
	Run.RenderStepped:Connect(function()
		local rotation = workspace.CurrentCamera.CFrame:toObjectSpace(CameraCF)
		local x,y,z = rotation:ToOrientation()
		swayCF = swayCF:Lerp(CFrame.new(math.sin(-y)*SwayX,math.sin(x)*SwayY,0), .2)
		CameraCF = camera.CFrame
		model:PivotTo(camera.CFrame * IdleCF * shootCF * swayCF * equipCF * reloadCF * unequipCF * AimCF)
		if shooting then 
			shootCF = CFrame.new(0,0,math.sin(.5))
		else
			shootCF = shootCF:Lerp(CFrame.new(), .4)
		end
		
		if IsReloading then
			reloadCF = reloadCF:Lerp(CFrame.Angles(100,0,0),.2)
		else
			reloadCF = reloadCF:Lerp(CFrame.new(), .2)
		end
		
		if EquipStart then
			equipCF = CFrame.new()
			debounce = true
		else
			equipCF = equipCF:Lerp(CFrame.new(0,0,-2),.1)
			debounce = false
		end
		
		if IsAiming then
			AimCF = AimCF:Lerp(CFrame.new(-1,.5,0),.2)
		else
			AimCF = AimCF:Lerp(CFrame.new(),.2 )
		end
	end)
end)
1 Like

Hold up, I added a print that prints out lastCameraCF's CFrame, here is what the script printed out:

image

Do you have idea on what this means?

1 Like