This is a weird glitch that is practically game ruining because it triggers all the time. The only time the character movement is fully smooth for other clients is when the character is moving forwards with no side movement (only holding W).
The video is very low quality, but you can still clearly see the character not moving smoothly backwards like it does on their client.
I don’t know what could cause this. The only thing I can think of is that the camera script is changing the HumanoidRootPart CFrame in a RenderStepped loop. This happens locally through a module script.
Weird thing is, I experienced something really similar with a Rain World Like game I am making where one of the characters would glitch like that when going backwards (Retreating, while when attaking or going forwards it was perfectly fine) while looking at the player. I think (I don’t remember very good) that I solved this issue by making the character walk like 5 studs in the direction it wants to go instead of just 1, but I guess this isn’t the solution for this since its a player.
My best bet is that some character script you coded is making this weird behaviour, or it is something with the Starter Character. So, could you share more information?
I have the characters parented to a folder that is inside of workspace, instead of directly parenting the character to the workspace.
Modifed the idle animation to not have the secondary animation play.
local player = game.Players.LocalPlayer
local character = player.Character
local animateScript = character:WaitForChild("Animate")
animateScript:WaitForChild("idle"):WaitForChild("Animation2").Weight.Value = 0
animateScript:WaitForChild("idle"):WaitForChild("Animation1").Weight.Value = 10
Well, the camerascript is actually what makes it possible to walk non-forwards, so yes disabling it does remove the bug. Although it also removes the camerascript of course.
I don’t have a primarypart.
The first one is indeed the camerascript. It sets the CFrame every frame (RenderStepped). I’m assuming it is not replicating to the other clients fast enough or something. Dunno.
Set the Starter Character primary part to its root since its just nicer and it avoids Roblox’s weird physics bugs. Also, how does moving the camera make the player be able to go backwards? I’m confused here, could you show more of the Camera code?
It’s a bit complicated due to having a raycast that creates a hitbox for the camera.
The core of the script is that it gets the player’s mouse movement and moves the humanoidRootPart (targetPart = humanoidrootpart) and camera based on it.
This is all in a RenderStepped loop, so I am assuming the issue is with runservice replication.
local delta = UserInputService:GetMouseDelta()
cameraRotationX = cameraRotationX - delta.Y * cameraSensitivity
cameraRotationY = cameraRotationY - delta.X * cameraSensitivity
cameraRotationX = math.clamp(cameraRotationX, -45, 45)
-- Calculate the new camera position and rotation
local desiredCameraCFrame = CFrame.new(targetPart.Position)
* CFrame.Angles(0, math.rad(cameraRotationY), 0)
* CFrame.Angles(math.rad(cameraRotationX), 0, 0)
* CFrame.new(cameraOffset)
--Setting humanoidrootpart cframe and camera cframe...
targetPart.CFrame = CFrame.new(targetPart.Position) * CFrame.Angles(0, math.rad(cameraRotationY), 0)
camera.CFrame = desiredCameraCFrame
Ohhh, so I guess you are doing this because you want them to turn around the camera, right? Well, I guess that’s probably why. Try setting the camera to fixed (Or what it is by default) and disabling the camera script, if it glitches that means that it isn’t the camera script fault
Maybe you can try Heart Beat instead or While task.wait()? I’m not really sure. Maybe try other CameraTypes? I dunno, though I think we’re on the right path
I’ve discovered something interesting.
Heartbeat changes nothing,. however changing the loop to a “Stepped” loop also makes it glitchy on the client that the loop fires from.
So the glitchyness happens because the other clients sees the CFrame change as stepped? Not sure what it means by “prior to physics simulation”, but it’s clearly bad for replication.
Honestly, I don’t really know, but maybe I can try to fix it if I know more about how the script works. So, what is the target part and what it does? Could you share more of the code, maybe?
I don’t think that the loop itself is the cause, but rather the method of looping and how changes inside the loop replicates to other clients. Granted I have no clue on how to fix this.
Here is the full script though (without the start variables and cameralock value changes);
-- Update the camera every frame
local function updateCamera()
--Get the player's mouse values
local delta = UserInputService:GetMouseDelta()
cameraRotationX = cameraRotationX - delta.Y * cameraSensitivity
cameraRotationY = cameraRotationY - delta.X * cameraSensitivity
--Clamp the vertical rotation to prevent flipping
cameraRotationX = math.clamp(cameraRotationX, -45, 45)
local targetPart = nil
if isFirstPerson.Value == false then
local plrParts = player.Character:GetDescendants()
local rod = player.Character:FindFirstChildWhichIsA("Tool")
for index, child in pairs(plrParts) do
if child:IsA("Part") and (rod == nil or not child:IsDescendantOf(rod)) then
child.LocalTransparencyModifier = 0
end
end
player.CameraMaxZoomDistance = 10
player.CameraMinZoomDistance = 10
cameraOffset = Vector3.new(1.3, 2, 10)
targetPart = player.Character:FindFirstChild("HumanoidRootPart")
elseif isFirstPerson.Value == true then
local plrParts = player.Character:GetDescendants()
local rod = player.Character:FindFirstChildWhichIsA("Tool")
for index, child in pairs(plrParts) do
if child:IsA("Part") and (rod == nil or not child:IsDescendantOf(rod)) then
child.LocalTransparencyModifier = 1
end
end
camera.CFrame = player.Character.Head.CFrame
player.CameraMaxZoomDistance = 0.5
player.CameraMinZoomDistance = 0.5
cameraOffset = Vector3.new(0, 0, 0)
targetPart = player.Character:FindFirstChild("Head")
end
if targetPart then
if cameraLocked then
targetPart.CFrame = CFrame.new(targetPart.Position) * CFrame.Angles(0, math.rad(cameraRotationY), 0)
end
-- Adjust the ray origin to be slightly above the character's head
local rayOrigin = targetPart.Position + Vector3.new(0, 2, 0)
-- Calculate the new camera position and rotation
local desiredCameraCFrame = CFrame.new(targetPart.Position)
* CFrame.Angles(0, math.rad(cameraRotationY), 0)
* CFrame.Angles(math.rad(cameraRotationX), 0, 0)
* CFrame.new(cameraOffset)
-- Raycast to detect if the camera would clip through objects or hit water
local raycastParams = RaycastParams.new()
local plrs = game.Players:GetPlayers()
local tableOfCharacters = {}
for index,plr in pairs(plrs) do
if plr.Character then
table.insert(tableOfCharacters,plr.Character)
end
end
raycastParams.FilterDescendantsInstances = tableOfCharacters
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local rayDirection = (desiredCameraCFrame.Position - rayOrigin).unit * (cameraOffset.Magnitude + 1)
local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams)
if raycastResult then
local hitPart = raycastResult.Instance
if hitPart:IsA("Part") and hitPart.Name:match("Water") then
local rayDirection = (desiredCameraCFrame.Position - rayOrigin).unit * (cameraOffset.Magnitude)
local newCameraPosition = raycastResult.Position - rayDirection.unit * 0.5
camera.CFrame = CFrame.new(newCameraPosition, targetPart.Position)
else
local rayDirection = (desiredCameraCFrame.Position - rayOrigin).unit * (cameraOffset.Magnitude + 1)
camera.CFrame = CFrame.new(raycastResult.Position - rayDirection.unit, targetPart.Position)
end
else
camera.CFrame = desiredCameraCFrame
end
end
end
-- Connect the updateCamera function to RunService's RenderStepped to run every frame
RunService.RenderStepped:Connect(updateCamera)
-- Function to handle character respawn
local function onCharacterAdded(newCharacter)
camera.CameraSubject = newCharacter:WaitForChild("Humanoid")
character = newCharacter
setCameraLock(true) -- Default to locked when character respawns
end
-- Connect to character respawn event
player.CharacterAdded:Connect(onCharacterAdded)
-- Expose the setCameraLock function
local module = {}
function module:SetCameraLock(locked)
setCameraLock(locked)
end
return module
I looked at this code for 9 minutes and I don’t think there’s anything wrong with it, so I guess its the loop. Maybe try alternating and if you can, you can maybe change the code so it works with while task.wait() do and etc. Another possible solution which is kinda a shot on the dark is that maybe you could try to make this partially server-sided so you could send to all clients the cframe of the player, since on their screen it doesn’t glitch?
Yeah I thought about moving the position/rotation of the targetPart to be set on the server, however I have a feeling it would be very laggy to play since you’d need to wait for the remote event.
I mean… It doesn’t hurt to try, I guess. Its the best solution I can think of now… Also, I think I may have another solution (And another shot on the dark): Have you tried to use pivot instead of setting the player by the root? If I remember right, I had a few problems back then with using the cframe of the root, but I’m not sure if it was because it was on the server or not, but you could try!
My conclusion is that it probably isn’t fault of the code itself but instead by some weird shenanigans with clients and methods. Also, if it is possible, did you try to see on the server if the glitch was also present in it?
With this setup I get the same issue now for my client as well. So it is clear that waiting for the server to process the information glitches it out for the client that recieves the information.