CFrame Train sometimes flinging away

Hello dev’s,
I’m currently trying to make a train system for my game, however my train sometimes flings away for no reason (its y position changes to inf) like in this video:

I have already tried some fixes but none of them worked.

here is my script (its a server script):

local runs = game["Run Service"]

local train = script.Parent

local plr = game.Players:FindFirstChild(string.split(train.Name, "'")[1])



local FAST_SPEED = 200
local SLOW_SPEED = 50



local world = workspace:FindFirstChild("World1")
if not world then return end
local rails = world:FindFirstChild("Rails")
if not rails then return end

local trainSpeed = 0
local maxTrainSpeed = 0

local visual = train.PrimaryPart:Clone()
visual:ClearAllChildren()
visual.Parent = workspace
visual.Name = "Visual"
visual.Color = Color3.fromRGB(255, 0, 0)

local railPointFolder = Instance.new("Folder", rails)
railPointFolder.Name = plr.Name.."'s RailPoints"

function CreatePoint(part)
	local point = Instance.new("Part")
	point.Anchored = true
	point.CanCollide = false
	point.CanTouch = false
	point.Name = "RailPoint"
	point.Parent = railPointFolder
	point.CFrame = part.CFrame * CFrame.new(0, 0, part.Size.Z/2)
	point.Size = Vector3.new(1, 1, 1)
	point.Transparency = 0.2
	point.CastShadow = false
	
	return point
end

for i, v in rails:GetChildren() do
	if v:IsA("BasePart") then
		CreatePoint(v)
	end
end

local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Include

local dist = 1000

local curPoint
local nextPoint

runs.Heartbeat:Connect(function(dt)
	local points = {}
	for _, v in railPointFolder:GetChildren() do
		if v ~= curPoint then
			table.insert(points, v)
		end
	end
	
	params.FilterDescendantsInstances = points
	
	local dir = train.PrimaryPart.CFrame:VectorToWorldSpace(Vector3.new(0, 0, -1))
	
	local result = workspace:Shapecast(train.PrimaryPart, dir*dist, params)
	
	visual.CFrame = result 
		and train.PrimaryPart.CFrame * CFrame.new(0, 0, -result.Distance) 
		or train.PrimaryPart.CFrame + (dir*dist)
	
	if not result then return end
	
	local railPoints = railPointFolder:GetChildren()
	
	local railPoint = railPoints[table.find(railPoints, result.Instance, 1)]
	
	if not curPoint then
		curPoint = CreatePoint(train.PrimaryPart)
	end
	
	if not nextPoint then
		nextPoint = railPoint
	end
	
	local distTraveledOnSection = (curPoint.Position - train.PrimaryPart.Position).Magnitude
	local sectionLength = (curPoint.Position - nextPoint.Position).Magnitude
	local newAlpha = (distTraveledOnSection + trainSpeed * dt) / sectionLength
	
	train.PrimaryPart.CFrame = curPoint.CFrame:Lerp(nextPoint.CFrame, newAlpha)
	
	if newAlpha >= 1 then
		curPoint = nextPoint
		nextPoint = railPoint
	end
	print(trainSpeed, newAlpha)
end)

while task.wait(0.05) do
	local trainGear = train:GetAttribute("Speed")
	
	if trainGear == "Fast" then
		maxTrainSpeed = FAST_SPEED
	elseif trainGear == "Slow" then
		maxTrainSpeed = SLOW_SPEED
	elseif trainGear == "Stop" then
		maxTrainSpeed = 0
	end
	
	if trainSpeed < maxTrainSpeed then
		trainSpeed += 1
	elseif trainSpeed > maxTrainSpeed then
		trainSpeed -= 1
	end
	
	if trainSpeed < 0 then
		trainSpeed = 0
	end
end

Any help would be appreciated!

3 Likes

If this is the same print statement from the video, then it looks like newAlpha is hitting inf.

local sectionLength = (curPoint.Position - nextPoint.Position).Magnitude
local newAlpha = (distTraveledOnSection + trainSpeed * dt) / sectionLength

That’s only going to happen if sectionLength is 0 or extremely close to zero which would happen when curPoint and nextPoint are at the same position or very close to each other.

I would double check the sectionLength calculations to ensure you’re not getting zero at any point. At the very least, you can add a check to make sure sectionLength isn’t 0 and if it is, clamp newAlpha to some max value.

3 Likes

Alright I will check if that works, thank you for your time!

1 Like

Hey there! If you’re struggling to implement @Uhsleep91’s solution, you can simply try this code (created off of what he said).

local runs = game["Run Service"]

local train = script.Parent

local plr = game.Players:FindFirstChild(string.split(train.Name, "'")[1])



local FAST_SPEED = 200
local SLOW_SPEED = 50



local world = workspace:FindFirstChild("World1")
if not world then return end
local rails = world:FindFirstChild("Rails")
if not rails then return end

local trainSpeed = 0
local maxTrainSpeed = 0

local visual = train.PrimaryPart:Clone()
visual:ClearAllChildren()
visual.Parent = workspace
visual.Name = "Visual"
visual.Color = Color3.fromRGB(255, 0, 0)

local railPointFolder = Instance.new("Folder", rails)
railPointFolder.Name = plr.Name.."'s RailPoints"

function CreatePoint(part)
	local point = Instance.new("Part")
	point.Anchored = true
	point.CanCollide = false
	point.CanTouch = false
	point.Name = "RailPoint"
	point.Parent = railPointFolder
	point.CFrame = part.CFrame * CFrame.new(0, 0, part.Size.Z/2)
	point.Size = Vector3.new(1, 1, 1)
	point.Transparency = 0.2
	point.CastShadow = false
	
	return point
end

for i, v in rails:GetChildren() do
	if v:IsA("BasePart") then
		CreatePoint(v)
	end
end

local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Include

local dist = 1000

local curPoint
local nextPoint

runs.Heartbeat:Connect(function(dt)
	local points = {}
	for _, v in railPointFolder:GetChildren() do
		if v ~= curPoint then
			table.insert(points, v)
		end
	end
	
	params.FilterDescendantsInstances = points
	
	local dir = train.PrimaryPart.CFrame:VectorToWorldSpace(Vector3.new(0, 0, -1))
	
	local result = workspace:Shapecast(train.PrimaryPart, dir*dist, params)
	
	visual.CFrame = result 
		and train.PrimaryPart.CFrame * CFrame.new(0, 0, -result.Distance) 
		or train.PrimaryPart.CFrame + (dir*dist)
	
	if not result then return end
	
	local railPoints = railPointFolder:GetChildren()
	
	local railPoint = railPoints[table.find(railPoints, result.Instance, 1)]
	
	if not curPoint then
		curPoint = CreatePoint(train.PrimaryPart)
	end
	
	if not nextPoint then
		nextPoint = railPoint
	end
	
	local distTraveledOnSection = (curPoint.Position - train.PrimaryPart.Position).Magnitude
	local sectionLength = (curPoint.Position - nextPoint.Position).Magnitude
	local newAlpha = math.clamp((distTraveledOnSection + trainSpeed * dt) / sectionLength, 0, 1)
	
	train.PrimaryPart.CFrame = curPoint.CFrame:Lerp(nextPoint.CFrame, newAlpha)
	
	if newAlpha >= 1 then
		curPoint = nextPoint
		nextPoint = railPoint
	end
	print(trainSpeed, newAlpha)
end)

while task.wait(0.05) do
	local trainGear = train:GetAttribute("Speed")
	
	if trainGear == "Fast" then
		maxTrainSpeed = FAST_SPEED
	elseif trainGear == "Slow" then
		maxTrainSpeed = SLOW_SPEED
	elseif trainGear == "Stop" then
		maxTrainSpeed = 0
	end
	
	if trainSpeed < maxTrainSpeed then
		trainSpeed += 1
	elseif trainSpeed > maxTrainSpeed then
		trainSpeed -= 1
	end
	
	if trainSpeed < 0 then
		trainSpeed = 0
	end
end
2 Likes

Alright that worked!
Thank you guys for your time!

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.