Splines#
A Spline is a curve through the Attachments inside it, taken in Explorer order. Roads, rails,
fences, rivers and the route a cart rides are all a spline with something laid along it. The spline
draws nothing in the game by itself: it is a shape you read from scripts and build along in the
editor.
A minecart track round a hill, as a closed loop of six points that climbs on the far side:
-- server
local track = game.world:add("Spline", { name = "Track", closed = true, cframe = cframe(0, 65, 0) }) :: Spline
for i, at in { vec3(0, 0, 0), vec3(20, 0, -6), vec3(32, 3, -24), vec3(20, 6, -42), vec3(-4, 3, -36), vec3(-10, 0, -16) } do
track:add("Attachment", { name = "Point" .. i, cframe = cframe(at.x, at.y, at.z) })
end| Property | Default | |
|---|---|---|
smooth |
true | a smooth curve through every point; off runs straight from point to point |
closed |
false | joins the last point back to the first, for a ring road or a race track |
- The curve passes through every point. Between them it bends the way the points around it lead, so moving one point reshapes the curve near it and leaves the rest alone.
- A closed spline needs at least three points.
- A point's own rotation tilts the curve's up. Turn an attachment about the way the road runs and the road banks there, which is how a race track leans into a corner.
- A script that moves an attachment moves the curve.
In the editor#
Insert > Grouping > Spline adds one. With the spline selected, the Properties panel has two buttons:
- Add point adds an attachment four metres past the last point, carrying on the way the curve was going. The first point goes where the spline is.
- Place along copies the first part or model inside the spline every few metres along the curve,
each one turned to face along it. The copies go into a folder called
Alonginside the spline. Placing again replaces that folder, so change the spacing or the part and press Place again. It is one undo step.
The curve is drawn in the viewport with each point numbered. Click a point's icon to select it and move it with the gizmo like anything else; the curve follows as you drag. Reorder points by dragging their rows in the Explorer.
The part copied by Place along stays where you left it. Put it at the first point, or move it out of the spline once the copies are made.
Reading the curve#
spline:getLength() |
the length of the curve in metres, 0 with no points |
spline:sample(alpha) |
the frame at alpha of the way along, from 0 at the first point to 1 at the end |
spline:sampleDistance(metres) |
the frame that many metres along |
spline:getFramesAlong(spacing) |
a frame every spacing metres, from the start to the end |
spline:closest(position) |
the alpha of the point on the curve nearest to position |
A frame is a CFrame in world space. Its position is on the curve, its look vector points along the
curve and its up vector is the points' up, so a part given the frame sits on the curve facing the way
it runs. alpha is measured along the curve's length, so 0.5 is always halfway in metres, however
the points are spaced.
Calling any of these on a spline with no points is an error.
Placing parts along it#
The track's sleepers and its two rails, short pieces laid end to end so they bend with the curve:
-- server
local track = game.world:find("Track") :: Spline
local laid = track:add("Folder", { name = "Laid" })
local wood, steel = color(0.4, 0.27, 0.16), color(0.45, 0.45, 0.48)
for _, frame in track:getFramesAlong(0.8) do
laid:add("Part", { size = vec3(1.8, 0.15, 0.3), cframe = frame, color = wood, anchored = true })
end
for _, frame in track:getFramesAlong(0.5) do
for _, side in { -0.6, 0.6 } do
laid:add("Part", {
size = vec3(0.1, 0.12, 0.52),
cframe = frame * cframe(side, 0.135, 0),
color = steel,
anchored = true,
})
end
endframe * cframe(side, 0.135, 0) moves each rail piece sideways and up in the curve's own frame, so
the rails stay on top of the sleepers and keep their gauge where the track banks or climbs.
Riding it#
A cart that starts where it was placed and rides the loop at 6 metres a second:
-- server
local track = game.world:find("Track") :: Spline
local cart = game.world:find("Cart") :: Part
local length = track:getLength()
local travelled = track:closest(cart.position) * length
game.stepped:connect(function(dt)
travelled = (travelled + 6 * dt) % length
cart.cframe = track:sampleDistance(travelled) * cframe(0, 0.6, 0)
end)closest gives an alpha, so times the length it is metres along. The cart is anchored and moved
each tick, so players standing in it ride along, see
Doors, lifts and moving platforms.
Extruding a profile#
spline:extrude(profile, options) sweeps a cross-section along the curve and hands back an
EditableMesh. Each point of the profile is a vec3: x is metres to the
right of the curve and y metres up. Its z is not used.
A road five metres wide with a kerb on each side, along a spline called Road:
-- client
local road = game.world:find("Road") :: Spline
local profile = {
vec3(-2.7, 0.2, 0), vec3(-2.5, 0.2, 0), vec3(-2.5, 0, 0),
vec3(2.5, 0, 0), vec3(2.5, 0.2, 0), vec3(2.7, 0.2, 0),
}
local mesh = road:extrude(profile, { spacing = 0.5 })
game.world:add("MeshPart", { meshId = mesh.uri, cframe = road.cframe, anchored = true })Each kerb is the 0.2 metre step at either edge and the flat 0.2 metre top beyond it.
| Option | Default | |
|---|---|---|
spacing |
1 | metres between one ring of the profile and the next; smaller follows tight bends better |
loop |
false | joins the profile's last point to its first, for a pipe or a tunnel |
- The mesh is built in the spline's own frame, so give the
MeshPartthe spline's frame and the two line up. - List the profile from left to right for a surface that faces up, like a road. Listed the other way
round it faces down. A
MaterialOverridewithdoubleSided = truedraws both sides. - The texture runs along the curve in metres, and across the profile in metres, so a 1 metre image tiles once per metre each way.
- A closed spline joins the end of the mesh to its start.
Meshes are seen only on the side that made them, so extrude from a client script, as EditableMesh explains. A spline made on the server is sent to every player, so every client can read it and extrude its own copy.
Paths and splines#
A CameraPath is a curve too, made for flying the camera along over time. A spline is the general
shape: it has no clock of its own, and is what you lay things along. A Path from game.path is a
route found around obstacles, see Paths.
