The title says it all.
After a discussion on discord I knocked this quick example together.
// Project: Path_Following_Demo
// Created: 2021-12-30
// show all errors
SetErrorMode(2)
// set window properties
SetWindowTitle( "Path_Following_Demo" )
SetWindowSize( 1200, 800, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1200, 800 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 0, 0 ) // 30fps instead of 60 to save battery
SetScissor( 0,0,0,0 ) // use the maximum available screen space, no black borders
UseNewDefaultFonts( 1 ) // since version 2.0.22 we can use nicer default fonts
type tWayPoint
col as integer
txt as integer
x as float
y as float
endtype
type tBlob
spr as integer
wp as integer
turnspeed as integer
speed as float
angle as float
desired as float
endtype
global path as tWayPoint[5]
global blob as tBlob[]
global collide as integer = 1
SetPhysicsGravity(0, 0)
SetPhysicsDebugOn()
SetViewOffset(0, 0) //Short-cut to remove physics walls
//Create Path
NewPath()
//Create Blobs
CreateBlobs(10)
do
Print("Press P for a new random path")
Print("Press Up Arrow for more blobs (Currently: " + str(blob.length+1)+")")
Print("Press C to toggle collision on/off (Currently: "+GetOnOff(collide))
if GetRawKeyPressed(80)
NewPath()
endif
if GetRawKeyPressed(38)
CreateBlobs(10)
endif
if GetRawKeyPressed(67)
ToggleCollision()
endif
UpdateBlobs()
DrawPath()
Print("FPS: " + str(ScreenFPS(), 0))
Sync()
loop
function UpdateBlobs()
for c = 0 to blob.length
nextWP = mod((blob[c].wp+1), path.length+1)
if GetSpriteCollision(blob[c].spr, path[nextWp].col)
inc blob[c].wp
endif
x1# = GetSpriteXByOffset(blob[c].spr)
y1# = GetSpriteYByOffset(blob[c].spr)
x2# = path[nextWP].x
y2# = path[nextWP].y
blob[c].desired = ATanFull(x2#-x1#, y2#-y1#)
blob[c].angle = CurveAngle(blob[c].desired, blob[c].angle, blob[c].turnspeed)
SetSpritePhysicsVelocity(blob[c].spr, sin(blob[c].angle)*blob[c].speed, -cos(blob[c].angle)*blob[c].speed)
next c
endfunction
function NewPath()
DeleteAllText()
//Create Random Path
for k = 0 to path.length
if GetSpriteExists(path[k].col) then DeleteSprite(path[k].col)
path[k].x = Random2(GetScreenBoundsLeft()+50, GetScreenBoundsRight()-50)
path[k].y = Random2(GetScreenBoundsTop()+50, GetScreenBoundsBottom()-50)
path[k].col = CreateDummySprite()
SetSpritePositionByOffset(path[k].col, path[k].x, path[k].y)
SetSpritePhysicsOn(path[k].col, 1)
SetSpriteSize(path[k].col, 100, 100)
SetSpriteShape(path[k].col, 1)
SetSpritePhysicsIsSensor(path[k].col, 1)
path[k].txt = CreateText(str(k))
SetTextSize(path[k].txt, 20)
SetTextPosition(path[k].txt, path[k].x, path[k].y)
next k
endfunction
function DrawPath()
c = MakeColor(0, 255, 0, 255)
for p = 0 to path.length-1
DrawLine(path[p].x, path[p].y, path[p+1].x, path[p+1].y, c, c)
next p
DrawLine(path[p].x, path[p].y, path[0].x, path[0].y, c, c)
endfunction
function CreateBlobs(qty)
b as tBlob
for c = 1 to qty
b.spr = CreateSprite(0)
SetSpriteColor(b.spr, Random2(0, 255), Random2(0, 255), Random2(0, 255), 255)
b.wp = 0
b.speed = Random2(50, 150)
b.turnspeed = Random2(30, 150)
SetSpritePhysicsOn(b.spr, 2)
SetSpriteSize(b.spr, 10, -1)
SetSpritePhysicsCanRotate(b.spr, 0)
SetSpriteCollideBit(b.spr, 1, collide)
SetSpriteShape(b.spr, 1)
SetSpritePositionByOffset(b.spr, path[0].x, path[0].y)
blob.insert(b)
next c
endfunction
function ToggleCollision()
collide = not(collide)
for b = 0 to blob.length
SetSpriteCollideBit(blob[b].spr, 1, collide)
next b
endfunction
function GetOnOff(value)
if value then exitfunction "On"
endfunction "Off"
//**********************************
// Wrap Angle
//**********************************
//Returns a value that does not exceed the range of 0 to 360.
function WrapAngle(angle as float)
angle = fmod(angle, 360.0)
if angle <0 then angle=angle+360
endfunction angle
//**********************************
// Curve Angle
//**********************************
//This command will return an auto-interpolated angle based on a given speed.
function CurveAngle( destination as float, current as float, speed as float)
local diff as float
if speed < 1.0 then speed = 1.0
destination = WrapAngle( destination )
current = WrapAngle( current )
diff = destination - current
if diff <- 180.0 then diff = ( destination + 360.0 ) - current
if diff > 180.0 then diff = destination - ( current + 360.0 )
current = current + ( diff / speed )
current = WrapAngle( current )
endfunction current
I should credit Virtual Nomad with the idea for this. I didn't realise how much advantage could be gained by
misusing Box2D like this.
[Edit] Minor update. You can now press the up arrow to increase the number of 'blobs'
[Edit2] Another small update to toggle collision on/off