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)
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.
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!