Help me improve my Noclip Script

I made a noclip script that works but feels terribly unoptimized here are the main things that annoy me:

  • I have a serverscript
  • How input detection is handled
  • How moving diagonal and stuff is handled
  • Using coroutine

Things to note:

  • I have a server script so that the command to toggle noclip can delete it
  • The values in NoclipC are not important
  • I am not very experienced with CFrame a lot of the CFrame stuff was done via the help of a tutorial

Things to note for the Rbxl File.rbxl (116.9 KB):

  • Noclip is engaged by using cmdr with F8
  • Default toggle keybind is LeftAlt if not specified

Hierarchy:
Screenshot 2024-02-25 191115

--Noclip Toggler (simplified due to a bunch of code specifically for cmdr)
if player.Character:FindFirstChild("Noclip") then
	local HRP = player.Character.HumanoidRootPart
	HRP.Parent.Animate.Enabled = true
	if HRP:FindFirstChild("AlignPosition") then
		HRP:FindFirstChild("AlignPosition"):Destroy()
	end
	if HRP:FindFirstChild("AlignOrientation") then
		HRP:FindFirstChild("AlignOrientation"):Destroy()
	end
	game:GetService("RunService"):UnbindFromRenderStep("noclip")
	HRP.Parent.NoclipS:Destroy()
	HRP.Parent.NoclipC:Destroy()
else
	local NoclipScript = script.NoclipC:Clone()
	NoclipScript.ToggleKeybind.Value = if togglekeybind then togglekeybind.Name else "LeftAlt"
	NoclipScript.Speed.Value = if speed then speed else 5
	Instance.new("AlignPosition", player.Character.HumanoidRootPart).Enabled = false
	Instance.new("AlignOrientation", player.Character.HumanoidRootPart).Enabled = false
	NoclipScript.Parent = player.Character
	script.NoclipS:Clone().Parent = player.Character
end
--Noclip Character Local Script (used to actually position the player)
local s, eM = pcall(function()
	--[[ Services ]]--
	local UIS = game:GetService("UserInputService")
	local RunService = game:GetService("RunService")
	
	--[[ Parts ]]--
	local Camera = workspace.CurrentCamera
	local HRP = script.Parent.HumanoidRootPart
	
	--[[ Variables ]]--
	local Speed = script.Speed.Value
	local Keybind = Enum.KeyCode[script.ToggleKeybind.Value]
	local Noclipping = false
	local Thread	--Global so the thread can be closed
	local WalkSpeed = 16
	local R6 = if HRP.Parent.Humanoid.RigType == Enum.HumanoidRigType.R6 then true else false
	
	--[[ Configure Align Objects ]]--
	HRP.AlignPosition.Responsiveness = 50
	HRP.AlignPosition.MaxForce = (99^99)^99
	HRP.AlignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
	HRP.AlignPosition.Attachment0 = HRP.RootAttachment
	HRP.AlignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
	HRP.AlignOrientation.Attachment0 = HRP.RootAttachment
	HRP.AlignOrientation.Responsiveness = 50
	HRP.AlignOrientation.MaxTorque = (99^99)^99
	
	--[[ Noclip toggler ]]--
	UIS.InputBegan:Connect(function(Input, Busy)
		if Input.KeyCode == Keybind and not Busy then
			if not Noclipping then
				Noclipping = true
				
				--[[ Configure AlignPosition for updating Player Pos ]]--
				local AP = HRP.AlignPosition
				AP.Position = HRP.CFrame.Position
				AP.Enabled = true
				
				--[[ Configure AlignOrientation for updating Player Ori ]]--
				local AO = HRP.AlignOrientation
				AO.Enabled = true
				
				--[[ Table to store key inputs ]]--
				local Move = "____"
				
				--[[ Prevent animations and sounds from playing ]]--
				WalkSpeed = script.Config:InvokeServer(1)
				
				--[[ Disable Collision ]]--
				for _, v in pairs(script.Parent:GetChildren()) do
					if v:IsA("Part") or v:IsA("MeshPart") then
						v.CollisionGroup = "NoCollide"
					end
				end
				
				--[[ Bind function to rendering for smooth noclipping ]]--
				RunService:BindToRenderStep("noclip", 300, function()
					
					--[[ Orient the player ]]--
					AO.CFrame = CFrame.new(Camera.CFrame.Position, HRP.Position)
					
					--[[ Position the player ]]--
					if Move == "W___" or Move == "WA_D" then
						AP.Position = CFrame.new(HRP.CFrame.Position + (HRP.CFrame.LookVector * Speed)).Position
					elseif Move == "_A__" or Move == "WAS_" then
						AP.Position = CFrame.new(HRP.CFrame.Position + (HRP.CFrame.RightVector * -Speed)).Position
					elseif Move == "__S_" or Move == "_ASD" then
						AP.Position = CFrame.new(HRP.CFrame.Position + (HRP.CFrame.LookVector * -Speed)).Position
					elseif Move == "___D" or Move == "W_SD" then
						AP.Position = CFrame.new(HRP.CFrame.Position + (HRP.CFrame.RightVector * Speed)).Position
					elseif Move == "WA__" then
						AP.Position = CFrame.new((HRP.CFrame.Position + (HRP.CFrame.LookVector * Speed)) + (HRP.CFrame.RightVector * -Speed)).Position
					elseif Move == "W__D" then
						AP.Position = CFrame.new((HRP.CFrame.Position + (HRP.CFrame.LookVector * Speed)) + (HRP.CFrame.RightVector * Speed)).Position
					elseif Move == "_AS_" then
						AP.Position = CFrame.new((HRP.CFrame.Position + (HRP.CFrame.LookVector * -Speed)) + (HRP.CFrame.RightVector * -Speed)).Position
					elseif Move == "__SD" then
						AP.Position = CFrame.new((HRP.CFrame.Position + (HRP.CFrame.LookVector * -Speed)) + (HRP.CFrame.RightVector * Speed)).Position
					end
					
				end)
				
				--[[ Thread for detecting player input ]]--
				Thread = coroutine.create(function()
					UIS.InputBegan:Connect(function(Input, Busy)
						if not Busy then
							if Input.KeyCode == Enum.KeyCode.W then
								Move = "W"..Move:sub(2)
							elseif Input.KeyCode == Enum.KeyCode.A then
								Move = Move:sub(1,1).."A"..Move:sub(3)
							elseif Input.KeyCode == Enum.KeyCode.S then
								Move = Move:sub(1,2).."S"..Move:sub(4)
							elseif Input.KeyCode == Enum.KeyCode.D then
								Move = Move:sub(1,3).."D"
							end
						end
					end)

					UIS.InputEnded:Connect(function(Input, Busy)
						if Move then
							if Input.KeyCode == Enum.KeyCode.W then
								Move = "_"..Move:sub(2)
							elseif Input.KeyCode == Enum.KeyCode.A then
								Move = Move:sub(1,1).."_"..Move:sub(3)
							elseif Input.KeyCode == Enum.KeyCode.S then
								Move = Move:sub(1,2).."_"..Move:sub(4)
							elseif Input.KeyCode == Enum.KeyCode.D then
								Move = Move:sub(1,3).."_"
							end
						end
					end)
				end)
				
				--[[ Start thread ]]--
				coroutine.resume(Thread)
				
			else
				--[[ Unbind and close threads ]]--
				Noclipping = false
				RunService:UnbindFromRenderStep("noclip")
				coroutine.close(Thread)
				
				--[[ Disable Align objects ]]--
				HRP.AlignPosition.Enabled = false
				HRP.AlignOrientation.Enabled = false

				--[[ Enable collision ]]--
				for _, v in pairs(script.Parent:GetChildren()) do
					if v:IsA("Part") or v:IsA("MeshPart") then
						v.CollisionGroup = "Default"
					end
				end

				--[[ Restore animations and sounds ]]--
				script.Config:InvokeServer(2, WalkSpeed)
			end
		end
	end)
end)

if not s then
	script.Config:InvokeServer(3)
	game:GetService("RunService"):UnbindFromRenderStep("noclip")
	warn("Error occured during noclip : "..eM)
	script:Destroy()
end
--Noclip Character Server Script (used for things that should be done on the server, lots of issues came from changing things back like walkspeed on the server when it was changed on the client)
script.Parent.NoclipC.Config.OnServerInvoke = function(Player: Player, Id: number, WalkSpeed: number)
	if Player == game:GetService("Players"):GetPlayerFromCharacter(script.Parent) then
		if Id == 1 then
			local HRP = script.Parent.HumanoidRootPart
			local WalkSpeed = HRP.Parent.Humanoid.WalkSpeed
			HRP.Parent.Humanoid.WalkSpeed = 0
			wait(0.1)
			HRP.Parent.Animate.Enabled = false
			return WalkSpeed
		elseif Id == 2 then
			local HRP = script.Parent.HumanoidRootPart
			HRP.Parent.Humanoid.WalkSpeed = WalkSpeed
			HRP.Parent.Animate.Enabled = true
		elseif Id == 3 then
			local HRP = script.Parent:FindFirstChild("HumanoidRootPart")
			if HRP then
				HRP.Parent.Humanoid.WalkSpeed = 16
				HRP.Parent.Animate.Enabled = true
				if HRP:FindFirstChild("AlignPosition") then
					HRP:FindFirstChild("AlignPosition"):Destroy()
				end
				if HRP:FindFirstChild("AlignOrientation") then
					HRP:FindFirstChild("AlignOrientation"):Destroy()
				end
			end
			script.Parent.NoclipC:Destroy()
			script:Destroy()
		end
	else
		pcall(function()Player:Destroy()end)
	end
end
1 Like