Here's a bit of a rough example I put together. Hope it helps!
SetWindowSize(800,600,0)
SetVirtualResolution(800,600)
SetSyncRate(0,0)
UseNewDefaultFonts(1)
points as tVec2[3]
points[0].x = 100
points[0].y = 100
points[1].x = 230
points[1].y = 300
points[2].x = 450
points[2].y = 340
points[3].x = 600
points[3].y = 100
spline as tSpline
spline = MakeSpline(points)
// just making a sprite to show the spline path
img = CreateImageColor(255,0,255,255)
ResizeImage(img,8,8)
spr = CreateSprite(img)
pos as tVec2
do
// loop t value from 0 to 1
t# = t# + 0.25 * GetFrameTime()
if t# > 1.0 then t# = 0.0
// evaluate the spline at the t value and position sprite
pos = EvaluateSpline(spline, t#)
SetSpritePositionByOffset(spr,pos.x, pos.y)
// draw the spline points and tangent handles
DrawSpline(spline)
print("T = " + str(t#))
print("FPS = " + str(ScreenFPS()))
sync()
loop
type tVec2
x as float
y as float
endtype
type tBezier
points as tVec2[3]
endtype
type tSpline
segments as tBezier[]
endtype
function MakeBezier(a ref as tVec2, b ref as tVec2, c ref as tVec2, d ref as tVec2)
bez as tBezier
bez.points[0] = a
bez.points[1] = b
bez.points[2] = c
bez.points[3] = d
endfunction bez
// accepts an array of tVec2 defining the path points for the spline.
// turns path points into bezier segments, just using an x offset for the tangent points for simplicity's sake.
function MakeSpline(points ref as tVec2[])
spl as tSpline
for i = 0 to points.length
if i + 1 <= points.length
bez as tBezier
handleA as tVec2
handleB as tVec2
handleA.x = points[i].x + 50 : handleA.y = points[i].y
handleB.x = points[i+1].x - 50 : handleB.y = points[i+1].y
bez.points[0] = points[i]
bez.points[1] = handleA
bez.points[2] = handleB
bez.points[3] = points[i+1]
spl.segments.insert(bez)
endif
next i
endfunction spl
// find the position along a cubic bezier curve at the given t value
function EvaluateBezier(bez ref as tBezier, t as float)
lva as tVec2
lvb as tVec2
lvc as tVec2
lvd as tVec2
lve as tVec2
result as tVec2
lva = lerpVec(bez.points[0], bez.points[1], t)
lvb = lerpVec(bez.points[1], bez.points[2], t)
lvc = lerpVec(bez.points[2], bez.points[3], t)
lvd = lerpVec(lva, lvb, t)
lve = lerpVec(lvb, lvc, t)
result = lerpVec(lvd, lve, t)
endfunction result
// just draws the control points
function DrawBezier(bez ref as tBezier)
DrawBox(bez.points[0].x - 4, bez.points[0].y - 4, bez.points[0].x + 4, bez.points[0].y + 4, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 1)
DrawBox(bez.points[1].x - 2, bez.points[1].y - 2, bez.points[1].x + 2, bez.points[1].y + 2, 0xFF00FFFF, 0xFF00FFFF, 0xFF00FFFF, 0xFF00FFFF, 1)
DrawBox(bez.points[2].x - 2, bez.points[2].y - 2, bez.points[2].x + 2, bez.points[2].y + 2, 0xFF00FFFF, 0xFF00FFFF, 0xFF00FFFF, 0xFF00FFFF, 1)
DrawBox(bez.points[3].x - 4, bez.points[3].y - 4, bez.points[3].x + 4, bez.points[3].y + 4, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 1)
endfunction
// find the position along the composite bezier spline at the given t value
function EvaluateSpline(spl ref as tSpline, t as float)
rVec as tVec2
tscaled as float
localt as float
tscaled = t * (spl.segments.length + 1)
segIdx = floor(tscaled)
localt = tscaled - segIdx
rVec = EvaluateBezier(spl.segments[segIdx], localt)
endfunction rVec
function DrawSpline(spl ref as tSpline)
for i = 0 to spl.segments.length
DrawBezier(spl.segments[i])
next i
endfunction
function lerpFloat(a#, b#, t#)
ret# = a# + (b# - a#) * t#
endfunction ret#
function lerpVec(a ref as tVec2, b ref as tVec2, t as float)
rVec as tVec2
rVec.x = lerpFloat(a.x, b.x, t)
rVec.y = lerpFloat(a.y, b.y, t)
endfunction rVec