Nice module! Would be cool if you could include degree elevation, subdivision and normal vectors.

De Casteljau’s algorithm is actually much faster than the explicit definition, you can try it yourself:

local points = {Vector3.new(0,1.324,38), Vector3.new(9.28,0,2),
Vector3.new(0,0.38292,4.372), Vector3.new(0.32762,78.281,9)}
local function deCasteljau(t:number):Vector3
local copy = {unpack(points)}
local n = #copy
for j = 1, n - 1 do
for k = 1, n - j do
copy[k] = copy[k] * (1 - t) + copy[k + 1] * t
end
end
return copy[1]
end
local function fac(n:number):number
if n == 0 then return 1 end
return n * fac(n - 1)
end
local function explicit(t:number):Vector3
local result = Vector3.zero
local n = #points-1
for i = 0, n do
result += (fac(n)/(fac(i)*fac(n-i))) * t^i * (1-t)^(n-i) * points[i+1]
end
return result
end

I want to thank you for this Module. There are several out there that performs bezier tweens, but I particularly love this one due to the real time path node change in position affecting the object already in motion. Such a nice feature. Creates some really nice organic-like path movements. Thank you.

Is there any built-in way to convert a position to a point in the curve? “CalculatePositionAt” seems to do the exact opposite, so right now the closest I managed to get was this:

local Start, End, Current = Points[1].Position, Points[#Points].Position, RootPart.Position
local NumCurrent = string.format("%.2f", ((Current - Start).Magnitude / (End - Start).Magnitude))

Which seems to work fine at the moment, but is probably innacurate as it uses the magnitude between the start and the end points of the curve instead of the actual curve’s length or whatever metric the actual module uses (normally I just avoid making a post and just fork whatever feature is missing in, but maths are not my thing).

I imagine this isn’t getting any updates anymore (which is totally alright), but I think it’d be cool if we had more control over the tweening functions such as letting us start from a custom percentage (so if for example in my game I wanna make it so when players touch a point in the curve, the tween starts from said point) and letting us decide at what point of the curve the tween ends (which I got working by inverting the NumberValue so the tween plays in reverse based on what end is closest, but I don’t think this is ideal).

There’s also Catmull-Rom Splines which I imagine would be nice for having more control over the curves, but I can’t really imagine how complicated supporting something like that would really be.

Regardless of the previous, thank you, been using this since july of last year for cutscenes, visual curves and such (currently trying to use it for rail grinding), and it’s extremely useful and way more accessible than any of the alternatives I’ve seen so far, so huge thanks for making such a well made module.

I’ve already made a module for Catmull-Rom Splines, you should check it out!

As for this module, I think I’m going to make a V2 later on. This was a very quickly made version of something I had in mind, but I can definitely make a better functioning one! Thanks for the feedback !

oh, I didn’t notice you were the creator of that one too , ngl, I tried it yesterday and I couldn’t get it to work, but I just tried porting my system to work with V1 and it works wonderfully!

I’m having an issue though, when transitioning from V1 to V2 I get an error telling me splines can’t have more than 3 points (which I assume requires a path), and when I try to use paths instead I get an error telling me i’m trying to use the Calculate functions from a table.

Do you think you could add the same examples from V1 updated to work with V2? I don’t think I fully understood how to use the paths and splines together.

Of course, I’ll do that soon! I’m not sure what the problem could be as of right now, but I will look into that. I think a tutorial for how to use V2 is necessary, I just haven’t gotten to it yet ;-;

For now, if V1 works better for you, I suggest using V1. It should work the same as V2, but a little less efficient and more prone to errors. V2 has multiple modules and is more organized, but I haven’t fully documented. I’ll get to that ASAP!

Hey, I have a question, how do I use the Bezier and turn it into a beam? I want to make it so it shows the trajectory of a bullet so players can aim. How to turn the bezier into a beam?

I have a question about using models as a replacement for lines. While I haven’t yet tried to do this, do you have plans to implement passing a model for the module use to generate as path sections? Each section stretching to meet the next.

I’m trying to create cart ride track sections with nice curves, but I keep running into issues trying to find ways that make the building workflow easier. I’m not a builder, so doing it by hand takes me forever. If you have suggestions for using your module in a way that smoothly places cart track rails, that would be amazing!!

Amazing work regardless, I look forward to using this in my future projects!

Hey, very nice module, but I have a question. Is there a way to make a tween move at a constant speed? I’d like for my part to always move at the same speed no matter how far the ending point is.

Make sure you’re using Bezier:CalculatePositionRelativeToLength(). This function takes in a percentage of the length of the Bezier curve and returns the position at the given percentage.

Since the object is moving at a constant speed, you can track how much distance the object has covered and use this to get the percentage of the length of the curve.

distance = speed * time
dx = speed*dt

By adding intervals of distance covered every time step, we can accurately keep track of distance covered in real time.

local speed = 10
local position = 0
local bezier = Bezier.new() -- your bezier curve
-- make sure your bezier curve is completely updated and ready to use
-- it should not be updated any further after this point, otherwise
-- the length of the curve should be updated accordingly
-- we are using bezierLength to refer to the length of our curve
local bezierLength = bezier.Length
local lastTimeStamp = os.clock()
while task.wait() do
local currentTimeStamp = os.clock()
local dt = currentTimeStamp - lastTimeStamp
position += speed*dt
if (position > length) then
break
end
-- this gives the current position assuming constant speed
local currentPosition = bezier:CalculatePositionRelativeToLength(position/length)
lastTimeStamp = currentTimeStamp
end

Thanks, but that doesn’t seem to be working for me:

local dis = (Char.HumanoidRootPart.Position - mouseP).Magnitude
local speed = 10
local position = 0
local NewBezier = Bezier.new((Char.HumanoidRootPart.CFrame * CFrame.new(0,0,-3)).Position, (Char.HumanoidRootPart.CFrame * CFrame.new(0,0,-15)).Position, (Char.HumanoidRootPart.CFrame * CFrame.new(math.random(dis*-1, dis),math.random(1, 8), -dis/2)).Position, mouseP)
-- make sure your bezier curve is completely updated and ready to use
-- it should not be updated any further after this point, otherwise
-- the length of the curve should be updated accordingly
-- we are using bezierLength to refer to the length of our curve
local bezierLength = NewBezier.Length
local lastTimeStamp = os.clock()
task.spawn(function()
while task.wait() do
local currentTimeStamp = os.clock()
local dt = currentTimeStamp - lastTimeStamp
position += speed*dt
if (position > bezierLength) then
break
end
-- this gives the current position assuming constant speed
local currentPosition = NewBezier:CalculatePositionRelativeToLength(position/bezierLength)
lastTimeStamp = currentTimeStamp
end
end)
local TweenInf = TweenInfo.new(2, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0)
local Tween2 = NewBezier:CreateCFrameTween(Fireball, {"CFrame"}, TweenInf)
Tween2:Play()

local dis = (Char.HumanoidRootPart.Position - mouseP).Magnitude
local NewBezier = Bezier.new((Char.HumanoidRootPart.CFrame * CFrame.new(0,0,-3)).Position, (Char.HumanoidRootPart.CFrame * CFrame.new(0,0,-15)).Position, (Char.HumanoidRootPart.CFrame * CFrame.new(math.random(dis*-1, dis),math.random(1, 8), -dis/2)).Position, mouseP)
local OBJECT_PATH_SPEED = 10 -- set this to the speed you want the object to travel at
local TweenInf = TweenInfo.new(NewBezier.length/OBJECT_PATH_SPEED, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, 0, false, 0)
local Tween2 = NewBezier:CreateCFrameTween(Fireball, {"CFrame"}, TweenInf, true)
Tween2:Play()

So as you can see, projectiles being moved along the curve seem to be bouncing up and down. I should mention that this doesn’t always happen, and it’s weirdly inconsistent. I don’t believe this is being caused by anything in my script, as the only;thing moving the projectile is this module.