How to make a CFramed object face the right way?

Hello me and @sasial are working on a train script. When we were trying to rotate the train, it was “drifting” and not facing the right way. So my question is, how do we make the train face the right way?

Here is our script:

wait(7)
local trainoff = Vector3.new(1,9,0)
local offpos = trainoff + Vector3.new(0,0,script.OffZ.Value)
for i,v in pairs(script.Parent.Cars:GetChildren()) do
    local PrimaryPart = script.Parent.Cars["Car"..i]
    PrimaryPart:SetPrimaryPartCFrame(CFrame.new(workspace.Tracks.Start.PrimaryPart.Position + offpos))
    offpos = offpos + Vector3.new(0,0,script.Parent.Cars["Car"..i].Box.Size.Z)
end
--- Train Script Below
local RunService = game:GetService("RunService")

local Grinding = true

local function GetDist(p)
	return (p.Node1.WorldPosition - p.Node0.WorldPosition).Magnitude
end

local function GetNewPosition(p, a)
	return (p.Node1.WorldPosition - p.Node0.WorldPosition) * a + p.Node0.WorldPosition
end

local function GetNewNode(currentNode, dir)
   return currentNode.Part.NextNode.Value
end

local function GrindRail(Train, RailParts, CurrentPart)

	--AlignPosition.Attachment1.Position = AlignPosition.Attachment0.WorldPosition
	
	local CurrentNode = RailParts[CurrentPart]
	
	--alpha between Node0 and Node1
	local a = 0--dist2.Unit:Dot(dist1)/dist2.Magnitude
	--All variables should be found by now!

	
	
	--AlignPosition.Enabled = true
	
	local connection
	local CurrentRatio = GetDist(CurrentNode.Part)
	
	connection = RunService.Heartbeat:Connect(function(dt)
		a = a + dt*script.Speed.Value/CurrentRatio
		print(a)
		if a > 1 then
			repeat
				local newPart = GetNewNode(CurrentNode, 1)
				if newPart then
					CurrentNode = RailParts[newPart]
					local NewRatio = GetDist(newPart)
					a = a - 1
					a = a * NewRatio/CurrentRatio
					CurrentRatio = NewRatio
				else
					connection:Disconnect()
					break
				end
			until a <= 1
		elseif a < 0 then
			repeat
				local newPart = GetNewNode(CurrentNode, -1)
				if newPart then
					CurrentNode = RailParts[newPart]
					local NewRatio = GetDist(newPart)
					a = a + 1
					a = a * NewRatio/CurrentRatio
					CurrentRatio = NewRatio
				else
					connection:Disconnect()
					break
				end
			until a >= 0
		end
		
		if CurrentNode and Grinding then
			local dir = (CurrentNode.Part.Node1.WorldPosition - CurrentNode.Part.Node0.WorldPosition).Unit
			--[[Train.PrimaryPart.CFrame = Train.PrimaryPart.CFrame:Lerp(CFrame.new(
				GetNewPosition(CurrentNode.Part,a) + Vector3.new(0,10,0),
				GetNewPosition(CurrentNode.Part,a) + Vector3.new(0,10,0) + dir
			), 0.1)--]]
			for i,v in pairs(script.Parent.Cars:GetChildren()) do
				print(i)
		        local car = script.Parent.Cars["Car"..i]
		--        print(getdistancetonode(currentpart,dir,i))
		    --    print(i)
	            --print(ii.." "..i)
				local offpos = trainoff + Vector3.new(0,0,script.OffZ.Value)
				local hyp= CurrentNode.Part.Size.X/2
	            --[[car:SetPrimaryPartCFrame(CFrame.new(car.PrimaryPart.Position--[[,CurrentNode.Part.NextNode.Value.Position+trainoff--):Lerp(CFrame.new(
                	GetNewPosition(CurrentNode.Part,a) + trainoff + Vector3.new(hyp * math.sin(math.rad(CurrentNode.Part.Orientation.Y)),0,hyp * math.cos(math.rad(CurrentNode.Part.Orientation.Y))).unit,
			          	CurrentNode.Part.NextNode.Value.Position + trainoff + Vector3.new(hyp * math.sin(math.rad(CurrentNode.Part.Orientation.Y)),0,hyp * math.cos(math.rad(CurrentNode.Part.Orientation.Y))).unit--)
	                , 0.1))--]]
				car.PrimaryPart.CFrame = CurrentNode.Part.CFrame:ToWorldSpace(trainoff)
 				--car.PrimaryPart.Orientation = CurrentNode.Part.Orientation
			end
			wait(1/script.Speed.Value)
			--AlignPosition.Attachment1.Position = GetNewPosition(CurrentNode.Part,a) + Vector3.new(0,3,0)
		else
			--AlignPosition.Enabled = false
			wait(2)
			Grinding = false
		end
		
	end)
end

wait(1)
print("waiting for setup...")
wait(2.3)
print("ready!")

local train = script.Parent

local RailParts = {}
local RailModel = workspace.Tracks

for _, part in ipairs(RailModel:GetChildren()) do
	
	RailParts[part.PrimaryPart] = {
		Part = part.PrimaryPart
	}
end

GrindRail(train, RailParts, workspace.Tracks.Start.PrimaryPart)

Your help is much appreciated.

2 Likes

Would you mind providing visuals of whats happening? Also why are certain sections commented off? Theres likely a far simpler way to do this, if this specific code gives you too much trouble.

Sure, we made a lot of changes, but it looks like this. The parts are put in comments, because we’re working on them.

image

1 Like

Is that it while its in movement or beforehand? A gif of the movement might help us understand your issue, if given context.

It’s when it moves. I’ll try to remove the commented part and then I’ll send you more screenshots.

Your issue seems to be that you’re setting the cframe of all the carriages to one point. Have a primarypart for each carriage. and see then if that works.

1 Like

@PapaBreadd @InternallyAmplified Thank you for your help, it’s getting late so I’ll look at it tomorrow. Have a great day/night.

1 Like

@InternallyAmplified Because the picture is old, then we made a lot of new changes. Now all carriages are CFramed on different nodes. The problem is just that carriages aren’t facing the right way.
@PapaBreadd I tried to remove the commented part, but because we’re editing one line, then the code won’t work. It is the line that where we need to fix the facing of the carriages.

So what do you recommend me to do to make the train face the correct way?

Very late response, apologies.

Use AlignOrientation