The camera seems to not follow the character properly, which is a bit odd. Using RenderStepped should makes it run before the camera updates. Maybe BindToRenderStepped can lead to better results, it does seem to make things very smooth for me, while using RenderStepped seems to have small jitters
local RunService = game:GetService("RunService")
local LastTarget = nil
local LastCFrame = nil
RunService:BindToRenderStep("CharacterOnMovingParts",Enum.RenderPriority.Camera.Value - 100,function()
local Character = script.Parent
if not Character then LastTarget = nil return end
local Humanoid = Character:FindFirstChild("Humanoid")
if not Humanoid then LastTarget = nil return end
local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
if not HumanoidRootPart then LastTarget = nil return end
local Height
if Humanoid.RigType == Enum.HumanoidRigType.R6 then
Height = HumanoidRootPart.Parent["Left Leg"].Size.Y + (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
else
Height = (0.5 * HumanoidRootPart.Size.Y) + Humanoid.HipHeight
end
local RaycastParam = RaycastParams.new()
RaycastParam.FilterType = Enum.RaycastFilterType.Exclude
RaycastParam.FilterDescendantsInstances = {Character}
local RaycastResults = workspace:Raycast(HumanoidRootPart.Position,Vector3.new(0,-Height -8,0),RaycastParam)
local Target = RaycastResults and RaycastResults.Instance
if not Target then LastTarget = nil return end
if LastTarget == Target then
local Offset = LastCFrame:Inverse() * HumanoidRootPart.CFrame
HumanoidRootPart.CFrame = Target.CFrame * Offset
end
LastTarget = Target
LastCFrame = LastTarget.CFrame
end)
As for how you move the train, it doesn’t actually move 1.5 studs every 0.001 seconds. The smallest amount of time task.wait()
can wait is one frame, or 0.0166 seconds, if the client is running at 60fps. A wait time of 0.001 seconds would require a fps of 1000, and if the train was actually moving 1.5 studs every 0,001 seconds, it would move 1500 studs every second, which it clearly isn’t. This also presents another issue with moving an object by a fixed distance every frame, the speed changes with the fps. Here is how you can fix this issue
local RunService = game:GetService("RunService")
local Speed = 90 -- 90 studs per second, which should be about the same speed you have currently
local StartPosition = Vector3.new(-512,0,0)
local StartTime = os.clock()
-- RunService.Hearbeat is used to make this function run every frame
RunService.Heartbeat:Connect(function()
local TimeDifference = os.clock() - StartTime -- How many seconds have passed since the start
Part.Position = StartPosition + Speed*TimeDifference -- 90 studs/s * 0.5s = 45 studs, etc ...
end)
If you want the train to repeat this path many times, you can do something like this
local RunService = game:GetService("RunService")
local StartPosition = Vector3.new(-512,0,0)
local EndPosition = Vector3.new(512,0,0)
local Duration = 20 -- How much time it takes for the train to go from StartPosition to EndPosition
local WaitTime = 10 -- How much time there is between passing trains
RunService.Heartbeat:Connect(function()
local TotalDuration = Duration+WaitTime
local t = os.clock() - math.floor(os.clock()/TotalDuration)*TotalDuration
-- t goes from 0 to 30 seconds, repeatedly
-- math.floor() floors the number (1.33 -> 1, 1.75 -> 1, 64.2 -> 64)
-- By doing os.clock()/TotalDuration, what is does is basically this
-- 70 - math.floor(70/30)*30
-- 70 - math.floor(2,33)*30
-- 70 - 2*30
-- 70 - 60
-- 10 seconds
-- the number returned by os.clock() is very big, much bigger than 70, but the same principle applies
local alpha = math.min(t/Duration,1) -- Since duration is 20, and t can go to 30, t/Duration can be higher than 1
-- However, the math.min prevents alpha from going above 1 (math.min returns the smaller of the two given numbers)
-- This means that the train will be stuck at alpha 1 (100%), for 10 seconds
Part.Position = StartPosition:Lerp(EndPosition, alpha) -- :Lerp() lerps the vector from StartPosition to EndPosition, using alpha, alpha of 0.25 means the lerped vector will be 25% of the way between Start and End, 0.5 is halfway, and 1 is all the way to End
end)
You can do pretty much do the same thing using TweenService, but much simpler (without all the math), but I didn’t feel like introducing TweenService (as if this was simpler… um I wrote this, I don’t feel like erasing it)
Don’t feel intimidated by this code, it is important to not skip steps when learning to code, or learning doesn’t really work