Rotating Train's cart's depending on the cart's in front orientation

I’m trying to make a CFrame based train system with carts
How ever, i’ve only managed to make it so the carts would follow the cart in front, but they don’t rotate around corners, but instead always stay in straight line. I’ve already tried rotating them based on last orientation, this resulted in either completely absurd results, or them continuing to stay straight.

The part that’s responsible for rotating these carts is at the end of the script, Runservice.Heartbeat

local RailTrack = workspace["Rail track"]
local Train = RailTrack.Train

local NodeMdel = RailTrack.Nodes
local Nodes = NodeMdel:GetChildren()

table.sort(Nodes, function(a, b)
	return tonumber(a.Name) < tonumber(b.Name)
end)

local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

local speed = 20

local Carts = Train:GetChildren()
table.sort(Carts, function(a, b)
	return tonumber(a.Name) < tonumber(b.Name)
end)

local FrontCart = Train[1].Function.Cart
spawn(function()
	while true do
		for i,node in pairs(Nodes) do
			local duration = (node.Position - FrontCart.Position).Magnitude / speed
			local Tween = TweenService:Create(FrontCart, TweenInfo.new(duration, Enum.EasingStyle.Linear), {CFrame = node.CFrame})
			Tween:Play()
			Tween.Completed:Wait()
		end
	end
end)

local LastOrientation = {}

for i,v in pairs(Carts) do
	table.insert(LastOrientation, v.Function.Cart.Orientation)
end

RunService.Heartbeat:Connect(function()
	for i,v in pairs(Carts) do
		if i > 1 then
			v.Function.Cart.Front.Orientation = Carts[i-1].Function.Cart.Back.WorldOrientation - LastOrientation[i-1]
			LastOrientation[i-1] = Carts[i-1].Function.Cart.Back.WorldOrientation
			
			v.Function.Cart.CFrame = Carts[i-1].Function.Cart.Back.WorldCFrame * v.Function.Cart.Front.CFrame:Inverse()
		end
	end
end)

If you have any questions, feel free to ask. Any help is appreciated

1 Like

Why do u set the CFrame of the cart AFTER setting the Orientation of the cart? Because you should know that setting the CFrame changes the Orientation too

i’m changing the orientation of an attachment, i guess i forgot to mention that, but changing the orientation of the attachment adjusts the orientation at which the cart get’s moved at

Problem: I checked the wiki for Attachment. It looks like Attachment.Orientation is NotReplicated. That means even if you change the Orientation on the server, it wont replicate to the clients, and so the client wont SEE its orientation (and the value) changing.

Solution: So you have to use normal Orientation to change the orientation of the train.
or maybe Attachment.CFrame if you know how to deal with CFrame.

Note: look at the wiki, WorldOrientation and pretty much everything there is NotReplicated too. The only thing that u can change that replicate to client is the Attachment.CFrame . Since CFrame changes both position and orientation for the Attachment. Basically, the other properties are as good as ReadOnly properties

i’m sorry for the slow replies, how ever this entire system is local, so there shouldn’t be any issues with replication. it’s just that i can’t figure out the math to calculate how much to rotate the attachment on a cart to make it look smooth around corners

Attachment.Orientation is not replicated because when you set it, it calculates the Attachment CFrame which IS replicated. It would be pointless to replicate the orientation when the client can just calculate it based off of the cframe.

However when you are ordering the carts here

your looping through in pairs, this doesn’t loop through them all in order so it messes up the LastOrientation table. Its probably not the solution, but it is a bug.

1 Like

the Carts table is organized at the start of the script

local Carts = Train:GetChildren()
table.sort(Carts, function(a, b)
	return tonumber(a.Name) < tonumber(b.Name)
end)

so that is not an issue, as i said before, the script itself is functional, i’m just looking for ways to calculate how much to rotate an attachment, depending on how much a cart in front of it has rotated. in more basic words, i’m looking for help with figuring out a math formula or a simpler way of finding that difference

I personally don’t see how you could do that beside running each cart on the nodes themselves, the carts would need a node designation for each of them instead of just the front one’s node designation.

Also pairs doesn’t loop through sorted tables like carts in order, you would need to use ipairs for that.

oh, i actually didn’t quite know about that, thanks for the help, i’ll be sure to fix that problem