Hey, I’m working on a project where your character (which is basically a cube) tweens to move, and the camera is supposed to follow that tween. The problem is, it’s super jittery.
Is there any way to fix this?
The humanoidRootPart is anchored, and the tween is on the client (we had it tween on the server first but that comes with the obvious downside of it being laggy)
Any help is appreciated.
Some code would help us solve your problem
This is on the server
Sprite.Position = getSpriteImage.GetSpriteImage(SkinName, Direction, root:GetAttribute("WalkingCycle"))
spiritRoot.BillboardGui.SpiritSprite.Position = getSpriteImage.GetSpriteImage(profile.Data.Spirit, oldDirection, spiritRoot:GetAttribute("WalkingCycle"))
local Tween = tweenEvent:FireAllClients(root, root:GetAttribute("Speed"), NewPosition)
local spiritTween = tweenEvent:FireAllClients(spiritRoot, root:GetAttribute("Speed"), oldPosition)
task.wait(root:GetAttribute("Speed"))
print(root.CFrame)
profile.Data.SpiritPosition.X = profile.Data.PlayerPosition.X
profile.Data.SpiritPosition.Y = profile.Data.PlayerPosition.Y
profile.Data.SpiritPosition.Z = profile.Data.PlayerPosition.Z
profile.Data.SpiritPosition.Direction = Direction
oldPosition = {["CFrame"] = CFrame.new(profile.Data.SpiritPosition.X, profile.Data.SpiritPosition.Y, profile.Data.SpiritPosition.Z)}
root.CFrame = NewPosition.CFrame
Heres the tween handler on the client
-- TWEEN HANDLER (CLIENT) --
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local remoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")
local event = remoteEvents:WaitForChild("PlayTween")
event.OnClientEvent:Connect(function(instance, speed, goal)
local TweenI = TweenInfo.new(speed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out,0,false,0)
if not instance then
return
end
local tween = TweenService:Create(instance, TweenI, goal)
tween:Play()
end)
and the camera script is just setting the camera’s position to a part in the character model
local Char:Model = script.Parent
local root:BasePart = Char:WaitForChild("HumanoidRootPart")
local OCam = workspace.CurrentCamera
local NCam:BasePart = Char:WaitForChild("CameraPart")
RunService.Heartbeat:Connect(function()
OCam.CFrame = NCam.CFrame
end)
And the result is the camera follows the sprite but it jitters a lot.
Why dont you intercept the goal directly and Lerp the CurrentCamera based on the goal?:
OCam.CFrame = OCam.CFrame:Lerp(goalCFrame, a)
(where a
is the alpha. This is usually referred to as LerpSpeed.)
Tried this, there’s a weird endlag and the camera kinda lags behind i.e it’s not properly aligned to the sprite
did this,
RunService.RenderStepped:Connect(function(deltatime)
OCam.CFrame = OCam.CFrame:Lerp(NCam.CFrame, 1)
end)
it still jitters slightly, idk what the problem is
The tween would do the same. Since the time is effectively 0
, its direct. No smoothing. That means you are still tied to replication, which is where the stutters come from.
sorry i dont understand, could you explain more clearly
the whole thing is that i have a camerapart welded to my root, and im making the root tween when the player moves, and every frame the camera follows that camerapart.
Did you tried: OCam.CFrame = OCam.CFrame * NCam.CFrame
Directly setting OCam.CFrame = NCam.CFrame
can cause stutters because Roblox default camera system may interrupt it.
didnt work at all, the camera is like in the sky and moving back and forth really quickly
Just Answer @vvictoriaXD’s Question
Question before trying that method. Did you set the camera to scriptable? OCam.CameraType = Enum.CameraType.Scriptable
Just asking.
TweenService runs locally, but the RootPart is replicated from the server. There are small network delays between server and client. Even if the tween has zero time (i.e., “instant”), you are still dependent on the parts position coming from the server; small jumps = stutter. The camera follows directly, without smoothing; every small “jitter” in the parts position is immediately transmitted to the camera.
yes, it’s scriptable
characterlimit
the root is moving on every client, not on the server. the server only saves the position data to each players profile
What is this root? You said that script runs on the Server
Yes, this script does run on the server, it gets the players root from this at the beginning:
movementEvent.OnServerEvent:Connect(function(Player, MovingW, MovingS, MovingA, MovingD, NewVector)
So it runs only once? You said you welded the Camera to the root. The root gets tweented on the client with 0 timing, meaning directly to that sended goal. The goal is sended from the Server Side?
the goal is sent from the server to the client,
local rootTween = tweenEvent:FireAllClients(root, root:GetAttribute("Speed"), NewPosition)
and the camera is on a local script updating every frame to match the cameraPart that is welded to this root
Yea so the position is still on the Server Side? How often is that fired? All the time? It would be the same if you just move the whole thing on the Server because it still has no smoothing in the tween:
local TweenI = TweenInfo.new(speed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out,0,false,0)