Viewmodel Suddenly Disappearing

Hello fellas,

What do i want to achieve?
I’m currently scripting a FPS Framework with viewmodels, Recently finished the main viewmodelhandler.
But the viewmodel keeps oddly disappearing, Not by meaning it’s completely destroyed, the CFrame was set to a math.huge amount.

Heres the clip:

Viewmodel Culling

Here’s my client code that is used to handle the viewmodel. The springmodule i use is made by Quenty.

local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local RepStorage = game:GetService("ReplicatedStorage")

local Modules = RepStorage:WaitForChild("Modules")

local plr = game:GetService("Players").LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local humanoid = char:WaitForChild("Humanoid")
local cam = workspace.CurrentCamera
local VFXFolder = RepStorage.VFX
local currentcamCF = cam.CFrame
local mouse = plr:GetMouse()

local deltaSensitivity = 2 -- increases force from mouse delta
--if negative force goes in opposite direction, viewmodel is lagging behind
local maxAngle = 5 --degrees

local previousGoalCFrame = CFrame.new()
local SwingCF = CFrame.new()
local WalkCFrame = CFrame.new()

local shot = false --// so if firerate time has passed it is allowed to shoot again

local Aiming  = false
local Equipped = false
local Firing = false
local CanCurrentlyAim = false
local Sprinting = false

local FireModeSwitch = 1

local lerpValues = {
	aim = Instance.new("NumberValue"),
	sprint = Instance.new("NumberValue")
}

local spring = require(Modules:WaitForChild("QuentySpring"))
local Keybinds = require(Modules:WaitForChild("Keybinds"))

local ZEROVECTOR        = Vector3.new()
local viewmodelSpring   = spring.new(ZEROVECTOR)
viewmodelSpring.Speed   = 20
viewmodelSpring.Damper  = 0.5 --1 is perfect dampening

local function clampMagnitude(vector, maxMagnitude)
	return (vector.Magnitude > maxMagnitude and (vector.Unit * maxMagnitude) or vector)
end

function angleBetween(vector1, vector2)
	return math.acos(math.clamp(vector1.Unit:Dot(vector2.Unit), -1, 1))
end

local Framework = {
	Inventory = {
		["One"] = "M16",
		["Two"] = "X16",	
		["Three"] = "Machete",
		["Four"] = "Frag"
	},

	Module = nil,
	CurrentSlot = 1,
	CurrentViewmodel = nil
}

local Magazine = Instance.new("NumberValue")
Magazine.Parent = Framework.CurrentViewmodel
Magazine.Name = "Rounds"

local fireAnim = nil

function EquipWeapon(Slot)
	local VMFolder = RepStorage.Viewmodels
	local Modules = RepStorage.Settings
	
	if Framework.CurrentViewmodel then
		Framework.CurrentViewmodel:Destroy()
	end

	if Modules:FindFirstChild(Slot) then
		Framework.Module = require(Modules:FindFirstChild(Slot))

		if VMFolder:FindFirstChild(Slot) then
			Equipped = true
			Framework.CurrentViewmodel = VMFolder:FindFirstChild(Slot):Clone()
			Framework.CurrentViewmodel.Parent = cam
			Framework.CurrentViewmodel.Name = "Viewmodel"
			Framework.CurrentViewmodel.PrimaryPart.Anchored = true
			
			humanoid.WalkSpeed = Framework.Module.DefaultSpeed
			Magazine.Value = Framework.Module["Magazine_Rounds"]

			local Weld = Instance.new("WeldConstraint")
			Weld.Parent = Framework.CurrentViewmodel
			Weld.Name = "AimPoint_Weld"
			Weld.Part0 = Framework.CurrentViewmodel.Handle
			Weld.Part1 = Framework.CurrentViewmodel.AimPoint

			fireAnim = Instance.new("Animation")
			fireAnim.Parent = Framework.CurrentViewmodel.VM_Animations
			fireAnim.Name = "VM_FireAnim"
			fireAnim.AnimationId = Framework.Module["VM_Animations"]["Fire"]
			fireAnim = Framework.CurrentViewmodel.Controller:LoadAnimation(fireAnim)
		end
	end
end

function OnAiming(stance)
	if not Framework.Module["CanAim"] then return end -- wont aim
	if not Sprinting then
		Aiming = stance
		Framework.CurrentViewmodel:FindFirstChild("Aiming").Value = stance
		TweenService:Create(lerpValues.aim,Framework.Module["AimInfo"][stance],{Value = stance and 1 or 0}):Play()
	end
end

function OnSprinting(stance)
	if not Framework.Module["CanSprint"] then return end
	if not Aiming then
		Sprinting = stance
		TweenService:Create(lerpValues.sprint,Framework.Module["SprintInfo"][stance],{Value = stance and 1 or 0}):Play()
		TweenService:Create(humanoid,Framework.Module["SprintInfo"][stance],{WalkSpeed = Framework.Module[stance and "SprintSpeed" or "DefaultSpeed"]}):Play()
	end
end

function onFiring(stance)
	if stance and shot then
		return
	end
	
	Firing = stance
	if not stance then
		return
	end
	
	local function pew()
		local FireSFX = Framework.CurrentViewmodel.Sounds:WaitForChild("FireSFX"):Clone()
		FireSFX.Parent = Framework.CurrentViewmodel.Handle:WaitForChild("FiringPoint")
		FireSFX:Play()
		
		RepStorage.Events:WaitForChild("FireWeapon"):FireServer(mouse.Hit.Position, Framework.CurrentViewmodel, Framework.CurrentViewmodel.Handle:WaitForChild("FiringPoint").WorldPosition, Framework.Module["Bullet_Speed"], Framework.Module["Bullet_Distance"])
		fireAnim:Play()

		game.Debris:AddItem(FireSFX,FireSFX.TimeLength)
		task.wait(Framework.Module["Fire_Rate"])
	end
	
	local firemode = Framework.Module["FireMode"]
	local BulletPerShot = 3
	if firemode == "2Burst" then
		BulletPerShot = 2
	end
	
	if firemode == "2Burst" or firemode == "3Burst" then
		for i=1,BulletPerShot do
			shot = true	
			pew()
			shot = false
		end
		return
	end	
	
	repeat
		shot = true	
		pew()
		shot = false
		if firemode == "Semi" then
			break
		end
	until Firing == false
end

function SwitchFireModes()
	local Max = #Framework.Module["FireModes"]
	if FireModeSwitch == Max then
		FireModeSwitch = 1
	else
		FireModeSwitch += 1
	end
	
	Framework.Module["FireMode"] = Framework.Module["FireModes"][FireModeSwitch]
	print("CurrentFireMode",Framework.Module["FireMode"])
end

UserInputService.InputBegan:Connect(function(i, v)
	if not v and Framework.Inventory[i.Name] and i.KeyCode == Enum.KeyCode[Framework.Inventory[i.Name]] then if Framework.CurrentSlot ~= i.Name then
			EquipWeapon(Framework.Inventory[i.Name])
			Framework.CurrentSlot = i.Name
		end
	end
	
	if not v and i.KeyCode == Keybinds["KeyBinds"]["Sprint"] then
		OnSprinting(true)
	end

	if not v and i.UserInputType == Keybinds["KeyBinds"]["AimDownSights"] then
		OnAiming(true)
	end
	
	if not v and i.UserInputType == Keybinds["KeyBinds"]["Fire"] then
		onFiring(true)
	end
	
	if not v and i.KeyCode == Keybinds["KeyBinds"]["SwitchFireMode"] then
		SwitchFireModes()
	end
end)

UserInputService.InputEnded:Connect(function(i, v) 
	if not v and i.UserInputType == Keybinds["KeyBinds"]["AimDownSights"] then
		OnAiming(false)
	end	
	if not v and i.KeyCode == Keybinds["KeyBinds"]["Sprint"] then
		OnSprinting(false)
	end
	if not v and i.UserInputType == Keybinds["KeyBinds"]["Fire"] then
		onFiring(false)
	end
	
end)

local Amp = Instance.new("NumberValue")
Amp.Value = 1

EquipWeapon(Framework.Inventory["One"])

RunService.RenderStepped:Connect(function(dt)    
	local idleOffset = Framework.Module["IdleCFrame"]
	local AimOffset = idleOffset:Lerp(Framework.CurrentViewmodel:WaitForChild("AimPoint").CFrame:ToObjectSpace(Framework.CurrentViewmodel.PrimaryPart.CFrame),lerpValues.aim.Value)
	local SprintOffset = AimOffset:Lerp(Framework.Module["SprintCFrame"],lerpValues.sprint.Value)
	local randomOffset = idleOffset:Lerp(CFrame.new(math.random() * Amp.Value/10, math.random() * Amp.Value/10, 0), .01)

	local finalOffset = SprintOffset * randomOffset
	
	--Spring stuff
	local differenceCF = previousGoalCFrame:ToObjectSpace(cam.CFrame)
	local axis, angle = differenceCF:ToAxisAngle()
	local angularDisplacement = axis * angle

	previousGoalCFrame =  cam.CFrame

	local springForce = angularDisplacement * deltaSensitivity
	viewmodelSpring:Impulse(springForce)
	
	local WalkBobble_X,WalkBobble_Y = Framework.Module["WalkBobble_X"],Framework.Module["WalkBobble_Y"]
	local WalkRotation_X,WalkRotation_Y = Framework.Module["WalkRotation_X"],Framework.Module["WalkRotation_Y"] 
	local AlphaWalkBobble = Framework.Module["AlphaWalkBobble"]
	
	if Sprinting then
		WalkBobble_X,WalkBobble_Y = Framework.Module["SprintBobble_X"],Framework.Module["SprintBobble_Y"]
		WalkRotation_X,WalkRotation_Y = Framework.Module["SprintRotation_X"],Framework.Module["SprintRotation_Y"] 
		AlphaWalkBobble = Framework.Module["AlphaSprintBobble"]
		--//elseif Crouching then 
	end
	
	local partSpringOffset = viewmodelSpring.Position
	local axis = partSpringOffset.Unit
	local angle = partSpringOffset.Magnitude
	local CurrentTime = tick()
	local x = math.cos(CurrentTime*10)*.06;
	local y = math.abs(math.sin(CurrentTime*10))*.06;

	angle = math.deg(angle)
	if angle > maxAngle then
		local currentViewModelVelocity = viewmodelSpring.Velocity
		local collision = math.sign(currentViewModelVelocity:Dot(axis))
		if collision > 0 then
			local reactionAngle = angleBetween(currentViewModelVelocity.Unit,axis)
			local resolve = math.cos(reactionAngle)
			local reactionForce = -axis*currentViewModelVelocity.Magnitude*resolve
			viewmodelSpring:Impulse(reactionForce)
		end
	end
	
	
	angle = math.rad(math.clamp(angle,0,maxAngle))

	local VelocityClamped = math.clamp(char.HumanoidRootPart.Velocity.Magnitude * .25, 0, 10)
	WalkCFrame = WalkCFrame:Lerp(CFrame.new(x * WalkBobble_X * VelocityClamped, y * WalkBobble_Y * VelocityClamped, 0) * CFrame.Angles(y *WalkRotation_X * VelocityClamped, y * WalkRotation_Y * (VelocityClamped), 0),AlphaWalkBobble)
	
	Framework.CurrentViewmodel.PrimaryPart.CFrame = cam.CFrame:ToWorldSpace(finalOffset)
	Framework.CurrentViewmodel:PivotTo(Framework.CurrentViewmodel:GetPivot()  * WalkCFrame * CFrame.fromAxisAngle(axis,angle))
end)```

Any help is appreicated!

I’m not that smart with viewport frames but, I’d say check your scripts that move the models in the viewport frames.

1 Like

Oh hey I was the one who implemented the viewmodel spring sway script.

The issue is a nan check with 0 rotational velocity with the rotation spring and caused by this line.

That .fromAxisAngle has the potential to become nan which is why in the original script there was an if statement to avoid applying this rotation in that case.

1 Like

Is there anyway i can fix it without ruining the swaying script? it was really cool.
the swaying script requires to pivot it to the middle of the viewmodel, so it gives a cool swaying mechanic.

1 Like

Yeah, thats why the original code had this if statement and commented:

1 Like

Thank you so much for reaching out to me!
I had tried that before but, I didn’t know i had to put it in-between the PivotTo function and the camera CFrame. :heart:

No problem also suffered extensively with NaN errors in the past, you should not have to as well.

For more information the spring position does not represent .Position like a normal spring (typically it represents displacement from spring resting position), I modified it to represents angular displacement (0,0,0) = resting no sway angular displacement–> (0,1,0) anticlockwise angular displacement around y axis.

If it’s (0,0,0) then there is no sway rotation axis and hence will become NAN and disappear.

Edit: Whoops typo the spring position represents angular displacement not angular velocity.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.