Ai train scripting help

So i was scripting a ai train system and then this happened when the train spawns :sob:


As in the video you can see that the train was really bumpy and glitchy
if anyone could help me or send feedback it would be much appreciated thank you.

not sure but maybe its the collisions, on spawn the train might be colliding with rails somehow, you could try adding collision groups

1 Like

Yeah maybe I could. Would uncolliding the tracks can work also?

I tried doing that it made the problem a little bit less worse but its still a little buggy

I can try sending you my code if that’s fine for you.

i mean you could do that just to test it but im guessing you would still want for players to collide with tracks, send the code ig

Alr gng this is my main module:

local TrainSuperClass = {}
TrainSuperClass.__index = TrainSuperClass
local Workspace = game:GetService("Workspace")
local TweenService = game:GetService("TweenService")
local ServerStorage = game:GetService("ServerStorage")	--variables
local Carriages = ServerStorage.Train.Carriages
local Settings = Workspace:FindFirstChild("Settings")
function TrainSuperClass.new(TrainModel, Nodes)
	local Train = {}

	setmetatable(Train, TrainSuperClass)

	Train.Nodes = Nodes
	Train.TestModel = TrainModel
	Train.Node = 1
	Train.Connections = {}
	Train.LastCarriage = nil

	coroutine.wrap(function()
		task.wait(1)

		Train:Setup()
	end)()

	return Train
end

function TrainSuperClass:Setup()

	if not self.Nodes:FindFirstChild("Node"..self.Node) then
		warn("Cannot Find Node "..self.Node)
		return
	end

	for _, v in next, self.Nodes:GetChildren() do
		v.Transparency = 1
	end

	self.Train = self.TestModel:Clone()
	self.Train.Parent = Workspace.Trains

	local Children = self.Train:GetChildren()

	for i = 1, #Children do
		if Children[i]:IsA("BasePart") and Children[i] ~= self.Train.PrimaryPart then
			local Weld = Instance.new("WeldConstraint")
			Weld.Part0 = Children[i]
			Weld.Part1 = self.Train.PrimaryPart
			Weld.Parent = self.Train.PrimaryPart
		end
	end

	local Killer = self.Train:FindFirstChild("Killer")

	if Killer then
		local KillPart = Killer.Touched:Connect(function(hit)
			if hit.Parent:FindFirstChild("Humanoid") then
				hit.Parent:FindFirstChild("Humanoid").Health = hit.Parent:FindFirstChild("Humanoid").Health - 1
			end
		end)

		table.insert(self.Connections, KillPart)
	end

	local startNode = self.Nodes:FindFirstChild("Node"..self.Node)
	self.Train:SetPrimaryPartCFrame(startNode.CFrame * CFrame.new(0, self.Train.PrimaryPart.Size.Y / 2, 0))
	self:Move()
end

function TrainSuperClass:GetTime(Distance)
	return Distance / self.Speed
end

function TrainSuperClass:Carriages(Node)
	if not Settings.Carriages.Value then return end
	local Carriage = Carriages:GetChildren()[math.random(1, #Carriages:GetChildren())]:Clone()

	local All = Carriage:GetChildren()

	for i = 1, #All do
		if All[i]:IsA("BasePart") and All[i] ~= Carriage.PrimaryPart then
			local Weld = Instance.new("WeldConstraint")
			Weld.Part0 = All[i]
			Weld.Part1 = Carriage.PrimaryPart
			Weld.Parent = Carriage.PrimaryPart
		end
	end

	if not self.LastCarriage then
		self.LastCarriage = self.Train
	end
	Carriage:SetPrimaryPartCFrame(self.LastCarriage:GetPrimaryPartCFrame() * CFrame.new(0, 0, Carriage.PrimaryPart.Size.Z - ((Carriage.PrimaryPart.Size.Z - self.LastCarriage.PrimaryPart.Size.Z) / 2) + 2)) -- distance between carriages -- 

	self.LastCarriage = Carriage
	Carriage.Parent = Workspace.Trains

	spawn(function()
		self:MoveCarriage(Node, Carriage)
	end)
end

function TrainSuperClass:MoveCarriage(NodeNum, Carriage)
	local Node = self.Nodes:FindFirstChild("Node"..NodeNum)

	if not Node then
		Carriage:Destroy()
		return
	end

	local Distance = (Carriage.PrimaryPart.Position - Node.Position).Magnitude

	local Time = self:GetTime(Distance)

	local TweenInfo = TweenInfo.new(
		Time,

		Enum.EasingStyle.Linear,

		Enum.EasingDirection.Out,

		0,

		false,

		0
	)

	TweenService:Create(Carriage.PrimaryPart, TweenInfo, {CFrame = Node.CFrame * CFrame.new(0, Carriage.PrimaryPart.Size.Y / 2, 0)}):Play()
	task.wait(Time)

	self:MoveCarriage(NodeNum + 1, Carriage)

end

function TrainSuperClass:Move()


	local Node = self.Nodes:FindFirstChild("Node"..self.Node)

	if not Node then
		self:Stop()
		return
	end
	if self.Node == 1 then

		for i = self.CarriagesCount, 1, -1 do

			self:Carriages(self.Node)
		end
	end
	self.Node = self.Node + 1
	local Distance = (self.Train.PrimaryPart.CFrame.p - Node.CFrame.p).Magnitude

	local Time = self:GetTime(Distance)

	local TweenInfo = TweenInfo.new(
		Time,

		Enum.EasingStyle.Linear,

		Enum.EasingDirection.Out,

		0,

		false,

		0
	)

	TweenService:Create(self.Train.PrimaryPart, TweenInfo, {CFrame = Node.CFrame * CFrame.new(0, self.Train.PrimaryPart.Size.Y / 2, 0)}):Play()
	task.wait(Time)

	self:Move()
end

function TrainSuperClass:Stop()
	for _, v in next, self.Connections do
		v:Disconnect()
	end
	self.LastCarriage = nil
	self.Node = 1
	self.Train:Destroy()
	task.wait(10)
	self:Setup()
end

return TrainSuperClass

wait why are you using tween for moving? You should be using lerp

I’m not sure why the train would be phasing off of the rails because of this, but you should note that the Tween moves in a straight line from the current Node towards the next Node and ignores the curve between them, which could be causing the shaking that happens throughout the video.

Also I wouldn’t recommend using a Tween on an unanchored model as the model could fall a little bit and then be teleported back up repeatedly, which could possibly create a lot of unexpected vertical velocity, and that could be causing the train to buck upwards.

There could also be some bug where the train doesn’t have correct physics the moment that it’s first created, or the train could be spawning with its wheels inside the track or something

You could try either anchoring the entire train model and using a lot of math to make the carriages rotate correctly along the track, or replace the Tween movement system with a Velocity system and possibly have invisible barriers on either side of the train to prevent it from falling off

SetPrimaryPartCFrame() is deprecated consider using :GetPivot().

It’s also not recommended to use Tweens in nodes as encountered. Tweens are supposed to end at some point, however mathematical calculations are to be used correctly. For example, you could try moving the thing with movers of Roblox. Tweens, if correct, use

Also you sometimes didn’t use task. The main reason is that if you care for ms in every frame, without task it runs at 33.33 ms (roughly to 30 FPS). With task, it runs at stable 60 FPS, If I remember correctly.

Note you’re also using .p which is also deprecated. It’s also the fact that there was a function called :GetPrimaryPartCFrame() that was also deprecated, but it got moved to :GetPivot()

Consider also using PhysicsService for controlled and supervised collisions, within the carriers and the train.

The closest thing you could go, which everyone uses, is ofcourse Bezier. Since Tweens do this, they ignore curvature lines. They take the shortest path as possible, so they jitter a lot and are not recommended in nodes.

1 Like

Thank you that was the issue the train is moving smoothly now.

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