BezierPath, an easy to use and optimized spline path module for TD games and general paths

function BezierPath:CalculateUniformCFrame(T: number): CFrame
	local TranslatedIndex = math.min(math.floor(math.clamp(T,0,1) * self.ITERATION_AMOUNT),self.ITERATION_AMOUNT - 1)
	local FirstSample = self.PrecomputedCache["CFrames"][TranslatedIndex]
	local SecondSample = self.PrecomputedCache["CFrames"][math.min(TranslatedIndex + 1,self.ITERATION_AMOUNT - 1)]

	local Progress = (T - math.clamp(FirstSample[2], 0, T)) / (SecondSample[2] - FirstSample[2])
		
	if Progress~=Progress then Progress = 1 end
	
	return FirstSample[1]:Lerp(SecondSample[1],Progress)
end

remplace CalculateUniformCFrame with this one!! (you can do the same stuff on progress for CalculateUniformPosition)

this is a fix to this “fix” which isn’t really a fix imo

Version 1.0.9

Fixed positions jumping at the very end and removed the curve size clamp.

close to the fix, but not really. the math.clamp in the first section of the progress variable is useless and your if statement can be a bit buggy as it can give false truths due to how floats work in computers. (unless roblox has an internal thingy to compensate which im not sure)

was working for me ig, and ok
the only reason why i added clamp is so it doesn’t give -math.huge

Fixed the clamp distance function leading to really small curves

I have a question about the module. Does it support speed changes while the movement is happening? I tried setting the speed var to lets say 0 to stop the movement in place but it teleported it to the very beginning. Is there any supported way of changing the speed ?

1 Like

Yes, You just need to store your T value in the enemy and update it everytime you change the enemies position.

1 Like

How would the “updating” look? Would you have to recalculate the T value or?

1 Like
--in the loop that updates enemies TValue
Enemy.TValue += calculations
Enemy.SpawnTime = tick()
1 Like

How would the “calculations” look like? I’m also trying to do what kater3ds is trying to do.

the calculations is just TimePassed / TotalpathTime.

heres a pseudocode example.

--outside loop
local Speed = 5
local StartTime = tick()
local Enemy = {}
local PathObject = bezierpath.new(args)
--in loop
Enemy.AlphaValue += (tick() - StartTime) / (PathObject:GetPathLength() / Speed)
StartTime = tick()

if you want it to be a bit more optimized you could save the alpha value when an enemies speed changes and only cange the AlphaValue variable and StartTime variable when their speed is changed. but this just makes it a bit easier to handle changing speed IMO.

4 Likes

As per request by a couple of people ive added BezierPath to wally!

BezierPath = "omrezkeypie/bezierpath@1.0.11"
3 Likes

Is it possible to open source the game?

VERSION 1.1.0

Added 2 new functions:
CalculateDerivative
CalculateClosestPoint

more info in the github

2 Likes

w skibidi rizz very valid +1 sigma respect keep it up mr. sigmakeychain

where was this away from me :star_struck:, thanks omrez for this cool module

Hello, could anyone fix this equation for changing t? I cant use the original one because it dosent work with speed changes. Here it is:

self.translated += (os.clock() - PreviousTime) * self.speed / path["path"]:GetPathLength()

PreviousTime = os.clock()

it’s meant to be (os.clock() - PreviousTime) / (PathLength / Speed)

pretty much what this equation means is:
Time Passed / Total Time To Complete Path.

and by dividing these 2 numbers you get a number from 0-1 to use in the spline

1 Like

If you’re wondering why does the mob restart when you set the speed to something else, here is the correct formula.

local currentTime = tick()
local elapsedTime = currentTime - StartTime
T = elapsedTime / TotalTime

if Speed ~= mob.Stats.Walkspeed.Value then
	local currentDistance = T * Path:GetPathLength()
	Speed = mob.Stats.Walkspeed.Value

	TotalTime = Path:GetPathLength() / Speed
	T = currentDistance / Path:GetPathLength()
	StartTime = currentTime - T * TotalTime
end
1 Like