So i've been wanting to use bezier curves, and i know you need to use :lerp() to move something along the curve. The problems is, I have no clue how to move using :Lerp(). Would you just move the position along the line made using :Lerp(), or is there another way of doing this?
How to use CFrame:Lerp() to move object?
2 answers
I did do a script that creates a Bézier curve. I made this script a few years ago.I just went through it and updated it and it Should work. Your free to use/study the code.
Code:
local modelGrp = workspace:FindFirstChild("Stem Group")
if(modelGrp == nil) then
modelGrp = Instance.new("Model",workspace)
modelGrp.Name = "Stem Group"
end
function doStrand(name,firePos,TargPos,Properties,parent)
local Sides = {"Front","Back","Top","Bottom","Left","Right"}
local P = parent:FindFirstChild(name)
if(P == nil) then
P = Instance.new("Part",parent)
P.formFactor = "Custom"
P.Transparency = 0
P.Reflectance = 0
P.Name = name
P.Locked = true
P.CanCollide = false
P.Shape = "Cylinder"
P.Anchored = true
for i=1,#Sides do
P[Sides[i].."Surface"] = "SmoothNoOutlines"
end
for k,v in pairs(Properties) do
if(k ~= "Size") then
P[k] = v
end
end
end
P.Size = Vector3.new((firePos - TargPos).magnitude,Properties.Size.x,Properties.Size.y)
P.CFrame = CFrame.new((firePos + TargPos)/2,firePos)*CFrame.Angles(0,math.rad(90),0)
return P
end
function CalculateBezierPoint(t, p0, p1, p2, p3)
local u = (1 - t);
local uu = u*u;
local uuu = uu * u;
local tt = t*t;
local ttt = tt * t;
local p = uuu * p0; -- first term
p = p + 5 * uu * t * p1; --second term
p = p + 5 * u * tt * p2; --third term
p = p + ttt * p3 --fourth term
return p;
end
function ChangeV3(Pos,GtoPos,mod)
local x = Pos.x
local y = Pos.y
local z = Pos.z
if(x > GtoPos.x) then if(x-mod < GtoPos.x) then x = GtoPos.x else x = x -mod end
elseif(x < GtoPos.x) then if(x+mod > GtoPos.x) then x = GtoPos.x else x = x +mod end
else x = x end
if(y > GtoPos.y) then if(y-mod < GtoPos.y) then y = GtoPos.y else y = y -mod end
elseif(y < GtoPos.y) then if(y+mod > GtoPos.y) then y = GtoPos.y else y = y +mod end
else y = y end
if(z > GtoPos.z) then if(z-mod < GtoPos.z) then z = GtoPos.z else z = z -mod end
elseif(z < GtoPos.z) then if(z+mod > GtoPos.z) then z = GtoPos.z else z = z +mod end
else z = z end
return Vector3.new(x,y,z)
end
local Points = {
Stem = {
Pos = {Vector3.new(0,0,0), Vector3.new(0,5,0), Vector3.new(0,10,0), Vector3.new(0,15,0)},
Goals = {Vector3.new(0,0,0),Vector3.new(0,5,0), Vector3.new(0,10,0), Vector3.new(0,15,0)}
}
}
local createWeight = function(point,name)
local CP = workspace:FindFirstChild(name)
local Faces = {"TopSurface","BottomSurface","LeftSurface","RightSurface","FrontSurface","BackSurface"}
if(CP == nil) then
CP = Instance.new("Part",workspace)
CP.Anchored = true
CP.Name = name
CP.FormFactor = "Custom"
CP.Shape = "Ball"
CP.Transparency = 0.4
CP.Size = Vector3.new(2,2,2)
for f=1,#Faces do
CP[Faces[f]] = "SmoothNoOutlines"
end
end
CP.CFrame = point
return CP
end
local step = 0.1
local StemBaseSize = 2
local SEGMENT_COUNT = 50
local CPoints = {}
for i=1,#Points.Stem.Goals do
local name = (i >1 and i < 4) and "ControlPoint ["..(i-1).."]" or (i == 1) and "Start Point" or "End Point"
CBrick = createWeight(CFrame.new(Points.Stem.Goals[i]),name)
CPoints[i] = CBrick
end
local myStyle = {
BrickColor = BrickColor.new("Bright green"),
Material = Enum.Material.SmoothPlastic,
Size = Vector2.new(0.2,0.2),
Shape = "Cylinder"
}
local SIndex = 0
function scale(valueIn, baseMin, baseMax, limitMin, limitMax)
return ((limitMax - limitMin) * (valueIn - baseMin) / (baseMax - baseMin)) + limitMin;
end
function drawWeightLine(Goal,id)
local myStyle = {
BrickColor = BrickColor.Black(),
Material = Enum.Material.SmoothPlastic,
Size = Vector2.new(0.2,0.2),
Transparency = 0.7
}
local Segs = modelGrp:GetChildren()
local Dist = math.huge
local ClosestPoint = nil
for i=1,#Segs do
local dist = (Goal - Segs[i].Position).magnitude
if(dist < Dist) then
ClosestPoint = Segs[i]
Dist = dist
end
end
if(ClosestPoint ~= nil) then
doStrand("Weight Line ["..id.."]",ClosestPoint.Position,Goal,myStyle,workspace)
end
end
while true do
local StemPos = Points.Stem.Pos
local StemGoals = Points.Stem.Goals
for i=1,#StemPos do
StemGoals[i] = CPoints[i].Position
step = (StemPos[i] - StemGoals[i]).magnitude/4
StemPos[i] = ChangeV3(StemPos[i],StemGoals[i],step)
end
--print(StemGoals[2])
for s = 0, SEGMENT_COUNT do
local name = "Part "..s
local t = s / SEGMENT_COUNT;
local tu = (s >0) and (s-1) / SEGMENT_COUNT or 0
pixel = CalculateBezierPoint(t, StemPos[1], StemPos[2], StemPos[3], StemPos[4]);
Prev = CalculateBezierPoint(tu, StemPos[1], StemPos[2], StemPos[3], StemPos[4]);
Seg = doStrand(name,pixel,Prev,myStyle,modelGrp)
end
for i=1,#StemGoals do
drawWeightLine(StemGoals[i],i)
end
SIndex = (SIndex < SEGMENT_COUNT) and SIndex+1 or 0
wait()
end
The script runs creates a vertical line with 4 spheres acting as weights. Move the spheres and you'll see the Line move, kinda like the Photoshop Bézier curve tool.
If I had a chance to re-make the script it would be a lot neater as I was learning to code at the time I made this script so sorry for the mess lol.
I was thinking you could rather than create the vertical line you could record the positions as if they were a path.
Hope this helps!
1 comment
Whew! 172 lines?! As someone who isnt learning this much in math yet, this math is CONFUSING! Thanks for the help though! I'll look through and try to figure it out.
Thanks for the help! That link helped me figure it out. I basically just change the position between two points using CFrame:Lerp() in a for loop. To do the curve, i just plugged the time and others parameters into the function through an equation and move the object there. I honestly dont understand how the equation works, but at least I know how to use curves now. Thanks for the help!
This discussion is preserved as it was. New answers, comments, and votes are closed.

1 comment
https://developer.roblox.com/en-us/articles/Understanding-CFrame