Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Script not working properly with FilteringEnabled?

Alright so I have a feature that allows players to noclip in my game when they press V. I converted it to FilteringEnabled since it wasn't updating the position properly. Now it does update the position of the player properly but noclipping is very laggy and the screen seems like it's having a seizure. Here are the scripts that are involved in this. Any possible answers as to why this happens?

ServerScriptService:

local ev = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("GoGhost")
ev.OnServerEvent:connect(function(plr,mode,opt)
	if mode == 0 then
		plr.Character.HumanoidRootPart.Anchored = true
		plr.Character.Humanoid.PlatformStand = true
	elseif mode == 1 then
		plr.Character.HumanoidRootPart.Anchored = false
		plr.Character.HumanoidRootPart.Velocity = Vector3.new()
		plr.Character.Humanoid.PlatformStand = false
	elseif mode == 2 then
		plr.Character.HumanoidRootPart.CFrame = opt
	end
end)

StarterGui:

local player = game.Players.LocalPlayer
local selected = false
local XboxPos = Vector3.new(0,0,0)
local c = workspace.CurrentCamera
local userInput = game:GetService("UserInputService")
local rs = game:GetService("RunService")
local starterPlayer = game:GetService("StarterPlayer")
local speed = 60
local lastUpdate = 0 
local ev = game.ReplicatedStorage:WaitForChild("Remotes"):WaitForChild("GoGhost")

function getNextMovement(deltaTime)
	local nextMove = Vector3.new()
	-- Left/Right
		if userInput:IsKeyDown("A") or userInput:IsKeyDown("Left") then
			nextMove = Vector3.new(-1,0,0)
		elseif userInput:IsKeyDown("D") or userInput:IsKeyDown("Right") then
			nextMove = Vector3.new(1,0,0)
		end
	-- Forward/Back
		if userInput:IsKeyDown("W") or userInput:IsKeyDown("Up") then
			nextMove = nextMove + Vector3.new(0,0,-1)
		elseif userInput:IsKeyDown("S") or userInput:IsKeyDown("Down") then
			nextMove = nextMove + Vector3.new(0,0,1)
		end
	-- Up/Down
		if userInput:IsKeyDown("Space") then
			nextMove = nextMove + Vector3.new(0,1,0)
		elseif userInput:IsKeyDown("LeftControl") then
			nextMove = nextMove + Vector3.new(0,-1,0)
		end
		nextMove = nextMove + XboxPos
	return CFrame.new( nextMove * (speed * deltaTime) )
end

function onSelected()
local char = player.Character
	if char then
		local humanoid = char:WaitForChild("Humanoid")
		local root = char:WaitForChild("HumanoidRootPart")
		currentPos = root.Position
		selected = true
		ev:FireServer(0)
		lastUpdate = tick()
		while selected do
			wait()
			local delta = tick()-lastUpdate
			local look = (c.Focus.p-c.CoordinateFrame.p).unit
			local move = getNextMovement(delta)
			local pos = root.Position
			ev:FireServer(2,CFrame.new(pos,pos+look) * move)
			lastUpdate = tick()
		end
		ev:FireServer(1)
	end
end

game:GetService("UserInputService").InputBegan:connect(function(input,event)
	if event then return end
	if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
		if (selected == false) then
			selected = true
			onSelected()
		elseif (selected == true) then
			selected = false
		end
	end
end)

2 answers

✓ Accepted answer

Ok, after a lot of playing around i've come up with a workable solution. It seems to be the case that CFraming your character locally and even moving it locally with a BodyPosition replicate to the server just fine even with filtering enabled on. This seems weird to me and an easy vector for exploit, but it does make creating the functionality you want fairly easy. It isn't exactly like the code you had posted, as you can't look up or down to move up/down - you have to use space/left ctrl, but adding that functionality introduced other problems so I thought it was better this way. The character is also playing the falling animation when no clip is active, but you can always add to the code below to play a custom animation if it is important to you.

This should be in a local script in StarterPlayerScripts. It handles input, messaging the server to turn on/off collision, the BodyPosition that controls hovering, and I also rotate the character in a renderstep that runs after camera update to get smooth rotations. I have commented the two variables you can change here to control noclip speed.

local UserInputService = game:GetService("UserInputService")
local player = game.Players.LocalPlayer
local MasterControl = require(player:WaitForChild("PlayerScripts"):WaitForChild("ControlScript"):WaitForChild("MasterControl"))
local noClipEvent = game.ReplicatedStorage:WaitForChild("NoClipEvent")
local isNoClipActive = false
local isSpaceHeld = false
local isCtrlHeld = false
local hoverHeight
local lastUpdate

local bodyPosition = Instance.new("BodyPosition")
bodyPosition.Name = "NoClipBodyPosition"
bodyPosition.MaxForce = Vector3.new(500000000, 500000000, 500000000)
bodyPosition.D = 400

-- These two variables will change the noclip horizontal and vertical speeds respectively
local noClipSpeed = 40
local hoverIncrementSpeed = 1

UserInputService.InputBegan:connect(function(input, event)
    if not event then
		if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
			if player.Character and player.Character.Parent then
				lastUpdate = tick()
		        isNoClipActive = not isNoClipActive
		        noClipEvent:FireServer(isNoClipActive)
				MasterControl:SetNoClip(isNoClipActive, noClipSpeed)
		
				if isNoClipActive then
					local root = player.Character:FindFirstChild("HumanoidRootPart")
					if root then
						bodyPosition.Parent = player.Character.HumanoidRootPart
						bodyPosition.Position = root.Position
						hoverHeight = root.Position.Y
					end
				else
					bodyPosition.Parent = nil
				end
			end
		end
		if input.KeyCode == Enum.KeyCode.Space then
			isSpaceHeld = true
		end
		if input.KeyCode == Enum.KeyCode.LeftControl then
			isCtrlHeld = true
		end
    end
end)

UserInputService.InputEnded:connect(function(input, event)
	if not event then
		if input.KeyCode == Enum.KeyCode.Space then
			isSpaceHeld = false
		end
		if input.KeyCode == Enum.KeyCode.LeftControl then
			isCtrlHeld = false
		end
	end
end)

game:GetService("RunService"):BindToRenderStep("updateLoop", Enum.RenderPriority.Camera.Value + 1, function()
	if isNoClipActive and player.Character and player.Character.Parent then
		local root = player.Character:FindFirstChild("HumanoidRootPart")
		if root then
			local cam = workspace.CurrentCamera
			local camForward = cam.CFrame.lookVector
			camForward = Vector3.new(camForward.X, 0, camForward.Z).Unit
			root.CFrame = CFrame.new(root.CFrame.p, root.CFrame.p + camForward)
			
			if isSpaceHeld then
				hoverHeight = hoverHeight + hoverIncrementSpeed
			end
			if isCtrlHeld then
				hoverHeight = hoverHeight - hoverIncrementSpeed
			end
			if bodyPosition.Parent then
				bodyPosition.Position = Vector3.new(root.CFrame.p.X, hoverHeight, root.CFrame.p.Z)
			end
		end
	end
end)

This is a server script that should be in ServerScriptService. It's job is to toggle player collision on/off when it receives a message from the local script.

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

local noClipEvent = Instance.new("RemoteEvent")
noClipEvent.Name = "NoClipEvent"
noClipEvent.Parent = game.ReplicatedStorage

local noClipPlayers = "Players"
PhysicsService:CreateCollisionGroup(noClipPlayers)
PhysicsService:CollisionGroupSetCollidable("Default", noClipPlayers, false)

local function setCollisionGroupRecursive(object, groupName)
    if object:IsA("BasePart") then
        PhysicsService:SetPartCollisionGroup(object, groupName)
    end
    for _, child in ipairs(object:GetChildren()) do
        setCollisionGroupRecursive(child, groupName)
    end
end

noClipEvent.OnServerEvent:connect(function(player, isNoClipActive)
    local character = player.Character
    if character then
        if isNoClipActive then
            setCollisionGroupRecursive(character, noClipPlayers)
        else
            setCollisionGroupRecursive(character, "Default")
        end
    end
end)

Finally, we have the code that updates player movement, which I have put in a modified ControlScript. This same code can be run within the local script and still work, but having it in the control script speeds things up a lot. You will see i'm also rotating the character here before moving it. You can get away with only having the character rotation updated here, and not also in the local script, but as this is bound to the input render priority, only having it updated here gives you jittery rotations. To set this up, you will want to press play in studio, and in the explorer navigate to Players -> [your player name] -> PlayerScripts and copy the ControlScript you find in there (Ctrl+C). Then press stop to exit the game, and paste the ControlScript into StarterPlayer -> StarterPlayerScripts. Then expand the ControlScript in the explorer and you will find the MasterControl module. Open MasterControl up for editing.

On lines 82 to 99 is the code for the updateMovement function. You need to replace these 18 lines with the following

local getHumanoid = MasterControl.GetHumanoid
local moveFunc = LocalPlayer.Move
local shouldUpdate = false
local lastUpdate
local updateMovement = function()
	
	if not areControlsEnabled then return end
	
	local humanoid = getHumanoid()
	if not humanoid then return end
	
	if isJumpEnabled and isJumping and not humanoid.PlatformStand then
		local state = humanoid:GetState()
		if state ~= STATE_JUMPING and state ~= STATE_FREEFALL and state ~= STATE_LANDED then
			humanoid.Jump = isJumping
		end
	end
	
	if allowNoClip then
		if shouldUpdate then
			shouldUpdate = false
			moveFunc(LocalPlayer, Vector3.new(), true)
			lastUpdate = tick()
		end
		
		local root = LocalCharacter:FindFirstChild("HumanoidRootPart")
		if root then
			local cam = workspace.CurrentCamera
			local camForward = cam.CFrame.lookVector
			camForward = Vector3.new(camForward.X, 0, camForward.Z).Unit
			local currentTime = tick()
			local delta = currentTime - lastUpdate
			root.CFrame = CFrame.new(root.CFrame.p, root.CFrame.p + camForward) * CFrame.new(moveValue * delta * noClipSpeed)
			lastUpdate = currentTime
		end
	else
		moveFunc(LocalPlayer, moveValue, true)
		shouldUpdate = true
	end
end

Above what you just pasted, you want to insert this code

local allowNoClip = false
local noClipSpeed = 40
function MasterControl:SetNoClip(isNoClipActive, speed)
	allowNoClip = isNoClipActive
	noClipSpeed = speed
end

So the area you just modified should now look like this

if LocalCharacter then
	characterAdded(LocalCharacter)
end
LocalPlayer.CharacterAdded:connect(characterAdded)

-- The above was already there. Your code starts below
local allowNoClip = false
local noClipSpeed = 40
function MasterControl:SetNoClip(isNoClipActive, speed)
	allowNoClip = isNoClipActive
	noClipSpeed = speed
end

local getHumanoid = MasterControl.GetHumanoid
local moveFunc = LocalPlayer.Move
local shouldUpdate = false
local lastUpdate
local updateMovement = function()
	
	if not areControlsEnabled then return end
	
	local humanoid = getHumanoid()
	if not humanoid then return end
	
	if isJumpEnabled and isJumping and not humanoid.PlatformStand then
		local state = humanoid:GetState()
		if state ~= STATE_JUMPING and state ~= STATE_FREEFALL and state ~= STATE_LANDED then
			humanoid.Jump = isJumping
		end
	end
	
	if allowNoClip then
		if shouldUpdate then
			shouldUpdate = false
			moveFunc(LocalPlayer, Vector3.new(), true)
			lastUpdate = tick()
		end
		
		local root = LocalCharacter:FindFirstChild("HumanoidRootPart")
		if root then
			local cam = workspace.CurrentCamera
			local camForward = cam.CFrame.lookVector
			camForward = Vector3.new(camForward.X, 0, camForward.Z).Unit
			local currentTime = tick()
			local delta = currentTime - lastUpdate
			root.CFrame = CFrame.new(root.CFrame.p, root.CFrame.p + camForward) * CFrame.new(moveValue * delta * noClipSpeed)
			lastUpdate = currentTime
		end
	else
		moveFunc(LocalPlayer, moveValue, true)
		shouldUpdate = true
	end
end
-- Your edits end here

--[[ Public API ]]--

And that's it. I apologize for the long post, but I wanted to be as clear as possible with everything. If you have any questions feel free to ask.

6 comments

0

I haven’t had time to test your script, but I’m not sure if it functions the same. I would want players to freely go through any object in the game and be able to fly around. Is that possible when using Collision Groups? Do you mind testing the script I posted to see how it works and tell me if it’s possible to make it less laggy?

0

You are right, sorry. The script I posted only let's players go through objects. I didn't realize you wanted flight as well. I will have another look when I get some free time this afternoon

0

Looking at your scripts, you are calling the remote event 30 times a second when noclip is toggled on. That's bad for one client to be doing, but even worse if multiple clients are all doing it at once. Combined with that you will have the latency of handling movement on the server. There should be a way to modify the control script to make this workable, but i'll have to dig into it and see...

0

...what I can come up with. I will post here if I can find a workable solution

0

Ok, i've come up with a solution that I hope works for you. I have replaced my old answer above with the new code

0

That isn’t what I’m looking for though. I need the player to move when they look up/down while noclipping. What problems would it create if you did add it? I also tried to remove that falling animation but it’s just breaking the script.

Never mind, I've found a solution!

In a LocalScript

repeat wait() until game.Players.LocalPlayer and game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:findFirstChild("Torso") and game.Players.LocalPlayer.Character:findFirstChild("Humanoid") 
local mouse = game.Players.LocalPlayer:GetMouse() 
repeat wait() until mouse
local plr = game.Players.LocalPlayer 
local torso = plr.Character.Torso 
local flying = false
local deb = true 
local ctrl = {f = 0, b = 0, l = 0, r = 0} 
local lastctrl = {f = 0, b = 0, l = 0, r = 0} 
local maxspeed = 60 
local speed = 60 
function Fly()
	local char = plr.Character
	if char then
		local humanoid = char:WaitForChild("Humanoid")
		local root = char:WaitForChild("HumanoidRootPart")
		root.Anchored = true
		root.Anchored = false
		root.Velocity = Vector3.new()
		humanoid.PlatformStand = false
	end 
local bg = Instance.new("BodyGyro", torso) 
bg.P = 9e4 
bg.maxTorque = Vector3.new(9e9, 9e9, 9e9) 
bg.cframe = torso.CFrame 
local bv = Instance.new("BodyVelocity", torso) 
bv.velocity = Vector3.new(0,0.1,0) 
bv.maxForce = Vector3.new(9e9, 9e9, 9e9) 
repeat wait() 
plr.Character.Humanoid.PlatformStand = true 
if ctrl.l + ctrl.r ~= 0 or ctrl.f + ctrl.b ~= 0 then 
speed = speed+.5+(speed/maxspeed) 
if speed > maxspeed then 
speed = maxspeed 
end 
elseif not (ctrl.l + ctrl.r ~= 0 or ctrl.f + ctrl.b ~= 0) and speed ~= 0 then 
speed = speed-1 
if speed < 0 then 
speed = 0 
end 
end 
if (ctrl.l + ctrl.r) ~= 0 or (ctrl.f + ctrl.b) ~= 0 then 
bv.velocity = ((game.Workspace.CurrentCamera.CoordinateFrame.lookVector * (ctrl.f+ctrl.b)) + ((game.Workspace.CurrentCamera.CoordinateFrame * CFrame.new(ctrl.l+ctrl.r,(ctrl.f+ctrl.b)*.2,0).p) - game.Workspace.CurrentCamera.CoordinateFrame.p))*60
lastctrl = {f = ctrl.f, b = ctrl.b, l = ctrl.l, r = ctrl.r} 
elseif (ctrl.l + ctrl.r) == 0 and (ctrl.f + ctrl.b) == 0 and speed ~= 0 then 
bv.velocity = ((game.Workspace.CurrentCamera.CoordinateFrame.lookVector * (lastctrl.f+lastctrl.b)) + ((game.Workspace.CurrentCamera.CoordinateFrame * CFrame.new(lastctrl.l+lastctrl.r,(lastctrl.f+lastctrl.b)*.2,0).p) - game.Workspace.CurrentCamera.CoordinateFrame.p))*0 
else 
bv.velocity = Vector3.new(0,0,0) 
end 
bg.cframe = game.Workspace.CurrentCamera.CoordinateFrame 
until not flying 
ctrl = {f = 0, b = 0, l = 0, r = 0} 
lastctrl = {f = 0, b = 0, l = 0, r = 0} 
speed = 0 
bg:Destroy() 
bv:Destroy() 
plr.Character.Humanoid.PlatformStand = false 
end 
mouse.KeyDown:connect(function(key) 
if key:lower() == "" then 
if flying then flying = false
else 
flying = true
Fly() 
end 
elseif key:lower() == "w" then 
ctrl.f = 1 
elseif key:lower() == "s" then 
ctrl.b = -1 
elseif key:lower() == "a" then 
ctrl.l = -1 
elseif key:lower() == "d" then 
ctrl.r = 1 
end 
end) 
mouse.KeyUp:connect(function(key) 
if key:lower() == "w" then 
ctrl.f = 0 
elseif key:lower() == "s" then 
ctrl.b = 0 
elseif key:lower() == "a" then 
ctrl.l = 0 
elseif key:lower() == "d" then 
ctrl.r = 0 
end 
end)
Fly()

game:GetService("UserInputService").InputBegan:connect(function(input,event)
	if event then return end
if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
		if (flying == false) then
			flying = true
			Fly()
		elseif (flying == true) then
			flying = false
		end
	end
end)

local noClipEvent = game.ReplicatedStorage:WaitForChild("NoClipEvent")
local isNoClipActive = false
local hoverHeight
local lastUpdate

local bodyPosition = Instance.new("BodyPosition")

game:GetService("UserInputService").InputBegan:connect(function(input, event)
    if not event then
        if input.KeyCode == Enum.KeyCode.ButtonB or input.KeyCode == Enum.KeyCode.V then
            if plr.Character and plr.Character.Parent then
                lastUpdate = tick()
                isNoClipActive = not isNoClipActive
                noClipEvent:FireServer(isNoClipActive)

                if isNoClipActive then
                    local root = plr.Character:FindFirstChild("HumanoidRootPart")
                    if root then
                        bodyPosition.Parent = plr.Character.HumanoidRootPart
                        bodyPosition.Position = root.Position
                        hoverHeight = root.Position.Y
                    end
                else
                    bodyPosition.Parent = nil
                end
            end
        end
    end
end)

Then I used your server script which uses Collision Groups

local PhysicsService = game:GetService("PhysicsService")
local Players = game:GetService("Players")

local noClipEvent = Instance.new("RemoteEvent")
noClipEvent.Name = "NoClipEvent"
noClipEvent.Parent = game.ReplicatedStorage

local noClipPlayers = "Players"
PhysicsService:CreateCollisionGroup(noClipPlayers)
PhysicsService:CollisionGroupSetCollidable("Default", noClipPlayers, false)

local function setCollisionGroupRecursive(object, groupName)
    if object:IsA("BasePart") then
        PhysicsService:SetPartCollisionGroup(object, groupName)
    end
    for _, child in ipairs(object:GetChildren()) do
        setCollisionGroupRecursive(child, groupName)
    end
end

noClipEvent.OnServerEvent:connect(function(player, isNoClipActive)
    local character = player.Character
    if character then
        if isNoClipActive then
            setCollisionGroupRecursive(character, noClipPlayers)
        else
            setCollisionGroupRecursive(character, "Default")
        end
    end
end)

Anyways, thanks for your help. Your collision groups script was really helpful!

1 comment

0

Glad you got it working :)

This discussion is preserved as it was. New answers, comments, and votes are closed.