I need help with CFrames

Hi everyone, I’m baking an idea that came to my mind and I’m struggling with CFrames a bit. (At least I think that’s what I should use for this)

Basically I’m making a simple road generator that will use premade meshes like those…

…and just snap them togheter to create a road that starts at point A and ends at point B with as many pieces I decide in the middle of them.

Now, I got the following piece of code…

local SS = game:GetService("ServerStorage")
local roadParts = SS:WaitForChild("RoadParts")
local partsAmount = 5

for i=1,partsAmount,1 do
	
	-- if i==1 then places the start of the road
	if i==1 then
		start = roadParts.StartFinish.Start:Clone()
		start.Parent = workspace.Road
		start.Name = tostring(i)
		start.Short_Straight.CFrame = CFrame.new(0,1,0)
		continue
	end
	
	-- Takes all the parts available and put them in a table to assign them a number
	parts=roadParts:GetChildren()
	partsArray = {}
	for i=1, #parts, 1 do
		if parts[i]:IsA("Model") then
			table.insert(partsArray, parts[i])
		end
	end
	
	-- Chooses a random road part
	chosenPart = partsArray[math.random(1,#partsArray)]
	-- Clones it and gives it a name
	clone = chosenPart:Clone()
	clone.Parent = workspace.Road
	clone.Name = tostring(i)
	previousRoadPart = workspace.Road:FindFirstChild(tostring(i-1)):FindFirstChildOfClass("MeshPart")
	
	-- Takes the CFrame of the previously spawned road part
	referenceCframe = previousRoadPart.After.WorldCFrame.Position
	
	-- Makes the new road part CFrame the same of the previous one plus the difference between the center and the Before point of the mesh
	newCFrameVector3= referenceCframe + (clone:FindFirstChildOfClass("MeshPart").CFrame.Position - clone:FindFirstChildOfClass("MeshPart").Before.WorldCFrame.Position)	
	
	
	-- Applies the new CFrame
	clone:FindFirstChildOfClass("MeshPart").CFrame = CFrame.new(newCFrameVector3)
	
end

…which works, but as soon as a turn comes in, the next piece of road is not turned to follow the path.

Now you are gonna say: “It’s obvious, there’s no rotation in your CFrame” and you are right but that’s because I just left the part of the script that worked…
I tried many different methods but none seems to work correctly. I tried PivotTo but doesn’t work, I tried LookAt but doesn’t work, I tried LookAlong but doesn’t work… Maybe I’m doing it wrong idk… A little bit of help on this would mean a lot to me…

Just for reference as I know this might be useful, all the pieces of road have this hierarcy where After and Before are 2 Attachments. After is the attachment that tells you where you should be traveling to and Before is the attachment that tells you where you came from.

I checked that all the 3D arrows of the Attachments point to the right directions, and I’m pretty positive they are unless I’m interpretating them wrongly… In the case of the last picture the After attachment is the one on the left while the Before Attachment is the one on the right.

Thank you in advance to anyone who’s willing to help me out on this!

4 Likes

Sorry for bumping and I know that CFrames are not the easiest thing to work with but can anyone give me any hint on this?

The problem lies here, you are placing the next road relative to the next road’s direction from before to after and your final CFrame has only positional component, rotation is set to zero. If you have placed your attachment with appropriate rotation (Z along next road direction) then you could do :

newCFrameVector = referenceCframe * CFrame.new(0,0,-(After-Before).Magnitude/2))

Hey! While recreating this in my own code, I think I found a few reasons why it isn’t working for you.

First, attachment issues. As you can see by the diagram below, the attachments must be rotated on their Y axis to face inwards for Before attachments, and outwards for After attachments.

Here is the diagram:

Second, while the main issue is rotation and can be fixed with the solution above, another issue is aligning the new part’s Before attachment to the previous part’s After attachment.
To fix this, we can invert the new part’s Before CFrame and apply that transformation to the previous part’s After attachment’s WorldCFrame. This means we’re applying the offset of the Before attachment (relative to the new part’s origin) to the WorldCFrame of the After attachment.

Here is what the code would look like:

local PreviousAfterAttachment = PreviousPart.After
local NewBeforeAttachment = NewPart.Before

NewPart.CFrame = PreviousAfterAttachment.WorldCFrame * NewBeforeAttachment.CFrame:Inverse()

Here is how I implemented it with examples of both road attachments in ReplicatedStorage.Roads & the math explained above.
RoadCreation.rbxl (59.6 KB)

If you are still confused on any part of this, please let me know!

6 Likes

Thank you so much for your amazing explanation! It works flawlessly and I also was able to add inclination to it very easily by changing this line like this

referenceCframe = previousRoadPart.After.WorldCFrame * CFrame.fromEulerAngles(math.rad(0), math.rad(0), math.rad(math.random(-15,0)))

And that’s the result!

2 Likes

You’re welcome! I love the inclination you implemented, beats the issue of parts overlapping LOL.

1 Like

Also limiting it to change part each time it chooses one, and adding many different parameters can fix this.

Example

1 Like

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