Path Editor
// Project: Path Editor
// Created: 2017-10-30
// show all errors
SetErrorMode(2)
#constant clearBtn=1
#constant test1Btn=2
#constant test2Btn=3
#constant closedBtn=4
#constant loadBtn=5
#constant saveBtn=6
#constant exitBtn=7
#constant spr=1
#constant xMax=1024
#constant yMax=768
#constant horizontalGrid=64
#constant verticalGrid=64
global renderImg=100
global closed=1 //whether or not to draw as open or closed curve
type object
x as float
y as float
endtype
type mySpr
id as integer
x as float
y as float
xOffset as float
yOffset as float
closed as integer
endtype
global testSpr as mySpr
testSpr.id=2
testSpr.closed=closed
#include "include/Bezier Curve Library.agc"
gosub _bc_setup //this has to be called before any BC command, preferably before anything at all
// set window properties
SetWindowTitle( "Path Editor" )
SetWindowSize( xMax, yMax, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 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
//loadimage (1,"6.png")
CreateSprite (spr,0)
SetSpriteSize (spr,10,10)
//CreateSprite (testSpr.id,1)
CreateSprite (testSpr.id,0)
SetSpriteSize (testSpr.id,200,200)
//SetSpriteColor (testSpr.id,0,255,0,255)
SetSpritePositionByOffset(testSpr.id,xMax/2,yMax/2)
AddVirtualButton(clearBtn,40,30,60) //make a button
SetVirtualButtonText( clearBtn, "Clear" ) //set to exit text
SetVirtualButtonColor( clearBtn,200,200,200) //grey colour
AddVirtualButton(test1Btn,40,90,60) //make a button
SetVirtualButtonText( test1Btn, "Test Points" ) //set to music text
SetVirtualButtonColor( test1Btn,200,200,200) //grey colour
AddVirtualButton(test2Btn,40,150,60) //make a button
SetVirtualButtonText( test2Btn, "Test Bezier" ) //set to music text
SetVirtualButtonColor( test2Btn,200,200,200) //grey colour
AddVirtualButton(closedBtn,40,210,60) //make a button
if closed=1
SetVirtualButtonText( closedBtn, "Closed" ) //set to music text
else
SetVirtualButtonText( closedBtn, "Open" ) //set to music text
endif
SetVirtualButtonColor( closedBtn,200,200,200) //grey colour
AddVirtualButton(saveBtn,40,270,60) //make a button
SetVirtualButtonText( saveBtn, "Save" ) //set to music text
SetVirtualButtonColor( saveBtn,200,200,200) //grey colour
AddVirtualButton(loadBtn,40,330,60) //make a button
SetVirtualButtonText( loadBtn, "Load" ) //set to music text
SetVirtualButtonColor( loadBtn,200,200,200) //grey colour
AddVirtualButton(exitBtn,40,390,60) //make a button
SetVirtualButtonText( exitBtn, "Exit" ) //set to sound text
SetVirtualButtonColor( exitBtn,200,200,200) //grey colour
CreateRenderImage (renderImg,xMax,yMax,0,0)
CreateSprite(350,renderImg)
count=1
dim path[100] as object
SetSpriteVisible(testSpr.id,0)
SetSpriteDepth(testSpr.id,9)
SetRenderToImage (renderImg,0)
drawCrosshairAndGrid(horizontalGrid,verticalGrid)
repeat
mx#=GetPointerX()
my#=GetPointerY()
SetSpritePositionByOffset(spr,mx#,my#)
if GetRawMouseLeftPressed()
path[count].x=mx#:path[count].y=my#
SetRenderToImage (renderImg,0)
drawSprite(spr)
bc_addcurvepoint(getrawmousex(),getrawmousey())
if closed=0
bc_calculateopencurvesegmentpoints()
else
bc_calculateclosedcurvesegmentpoints()
endif
inc count
endif
if GetVirtualButtonPressed(clearBtn)
clearPoints()
count=1
SetRenderToImage (renderImg,0)
drawCrosshairAndGrid(horizontalGrid,verticalGrid)
endif
Update(0)
Render()
setrendertoscreen ()
SetSpriteSize(350,1024,768)
Update(0)
Render()
swap()
if GetVirtualButtonPressed(closedBtn)
if closed=1
closed=0:testSpr.closed=closed
SetVirtualButtonText( closedBtn, "Open" ) //
else
closed=1:testSpr.closed=closed
SetVirtualButtonText( closedBtn, "Closed" ) //
endif
endif
if GetVirtualButtonPressed(test1Btn)
testPaths()
endif
if GetVirtualButtonPressed(test2Btn)
drawBezier()
testBezierCurve()
//Bezier2()
endif
if GetVirtualButtonPressed(saveBtn)
saveArray(count)
endif
if GetVirtualButtonPressed(loadBtn)
clearPoints()
SetRenderToImage (renderImg,0)
drawCrosshairAndGrid(horizontalGrid,verticalGrid)
count=loadArray()
endif
until GetVirtualButtonPressed(exitBtn)
end
function drawCrosshairAndGrid(gridX, gridY)
for y=0 to yMax step gridX
drawline(0,y,xMax,y,0,255,0)
next y
for x=0 to xMax step gridY
drawline(x,0,x,yMax,0,255,0)
next x
drawline(0,yMax/2,xMax,yMax/2,255,0,0)
drawline(xMax/2,0,xMax/2,yMax,255,0,0)
endfunction
function clearPoints ()
for t = 0 to 100
path[t].x=0:path[t].y=0
next t
BC_RemoveCurvePoints()
DeleteSprite(350):DeleteImage(renderImg)
renderImg=CreateRenderImage (xMax,yMax,0,0)
CreateSprite(350,renderImg)
endfunction
function drawBezier()
if bc_getcurvesegmentpointcount()>0
SetRenderToImage (renderImg,0)
for i=0 to bc_getcurvesegmentpointcount()-2 //normally use -1, but I want to stop 1 early of the end of the array
drawline(bc_getcurvesegmentpointx(i),bc_getcurvesegmentpointy(i),bc_getcurvesegmentpointx(i+1),bc_getcurvesegmentpointy(i+1),255,0,0)
next i
endif
Update(0)
Render()
setrendertoscreen ()
Update(0)
Render()
swap()
endfunction
function testBezierCurve()
testSpr.xOffset=0:testSpr.yOffset=0
SetSpriteVisible(testSpr.id,1)
if bc_getcurvesegmentpointcount()>0
for i=0 to bc_getcurvesegmentpointcount()-1 //normally use -1, but I want to stop 1 early of the end of the array
SetSpritePositionByOffset(testSpr.id,bc_getcurvesegmentpointx(i)+testSpr.xOffset,bc_getcurvesegmentpointy(i)+testSpr.yOffset)
//add following to point to centre
angle#=getAngle(bc_getcurvesegmentpointx(i),bc_getcurvesegmentpointy(i),bc_getcurvesegmentpointx(i+1),bc_getcurvesegmentpointy(i+1))
SetSpriteAngle(testSpr.id,getAngle(GetSpriteXByOffset(testSpr.id),GetSpriteYByOffset(testSpr.id),xMax/2,yMax/2)):rem point to middle of screen
sync()
next i
endif
SetSpriteVisible(350,1)
SetSpriteVisible(testSpr.id,0)
endfunction
function testPaths()
//testSpr.x=xMax/2:testSpr.y=yMax/2
testSpr.xOffset=0:testSpr.yOffset=0
testSpr.x=path[1].x+testSpr.xOffset:testSpr.y=path[1].y+testSpr.yOffset
count=1:speed#=5
//SetSpriteVisible(350,0)
SetSpriteVisible(testSpr.id,1)
rem move sprite X steps
repeat
SetSpritePositionByOffset(testSpr.id,testSpr.x,testSpr.y)
//SetSpriteSize(testspr,200,200)
while getDistance(testSpr.x,testSpr.y,path[count+1].x,path[count+1].y)>5
angle#=getAngle(testSpr.x,testSpr.y,path[count+1].x,path[count+1].y)
testSpr.x=testSpr.x-sin(angle#)*speed#:testSpr.y=testSpr.y+cos(angle#)*speed#
SetSpritePositionByOffset(testSpr.id,testSpr.x+testSpr.xOffset,testSpr.y+testSpr.yOffset)
SetSpriteAngle(testSpr.id,getAngle(GetSpriteXByOffset(testSpr.id),GetSpriteYByOffset(testSpr.id),xMax/2,yMax/2)):rem point to middle of screen
//SetSpriteAngle(testspr,angle#):rem point to way point
print( getDistance(testSpr.x,testSpr.y,path[count+1].x,path[count+1].y))
sync()
endwhile
//x=path[count+1].x:y=path[count+1].y
inc count
until path[count+1].x=0 and path[count+1].y=0
rem move sprite to first point if closed path
if testSpr.closed=1
while getDistance(testSpr.x,testSpr.y,path[1].x,path[1].y)>5
angle#=getAngle(testSpr.x,testSpr.y,path[1].x,path[1].y)
testSpr.x=testSpr.x-sin(angle#)*speed#:testSpr.y=testSpr.y+cos(angle#)*speed#
SetSpritePositionByOffset(testSpr.id,testSpr.x+testSpr.xOffset,testSpr.y+testSpr.yOffset)
SetSpriteAngle(testSpr.id,getAngle(GetSpriteXByOffset(testSpr.id),GetSpriteYByOffset(testSpr.id),xMax/2,yMax/2)):rem point to middle of screen
//SetSpriteAngle(testspr,angle#):rem point to way point
print( getDistance(testSpr.x,testSpr.y,path[count+1].x,path[count+1].y))
sync()
endwhile
endif
SetSpriteVisible(350,1)
SetSpriteVisible(testSpr.id,0)
endfunction
function getAngle(x1#, y1#, x2#, y2#)
result# = ATanFull(x1# - x2#, y1# - y2#)
endfunction result#
function getDistance (x1#,y1#,x2#,y2#)
dx#=x1#-x2#
dy#=y1#-y2#
distance#=sqrt((dx#*dx#)+(dy#*dy#)):rem distance object to path point
endfunction distance#
function difference(x as float ,y as float)
diff as float
diff = (x-y)
endfunction diff
//Function Bezier4(p:TV2D Var,p1:TV2D,p2:TV2D,p3:TV2D,p4:TV2D,mu:Float)
function Bezier2()
//MR 01.07.2005
//Four control point Bezier interpolation
//mu ranges from 0 To 1, start To End of curve
mu as float
mum1 as float
mum13 as float
mu3 as float
count as integer
SetSpriteVisible(testSpr.id,1)
for mu=0 to 1 step .025
mum1 = 1.0 - mu
mum13 = mum1 * mum1 * mum1
mu3 = mu * mu * mu
testSpr.x = mum13*path[1].x + (3.0*mu*mum1*mum1*path[2].x) + (3.0*mu*mu*mum1*path[3].x) + (mu3*path[4].x)
testSpr.y = mum13*path[1].y + (3.0*mu*mum1*mum1*path[2].y) + (3.0*mu*mu*mum1*path[3].y) + (mu3*path[4].y)
//p.z = mum13*p1.z + 3.0*mu*mum1*mum1*p2.z + 3.0*mu*mu*mum1*p3.z + mu3*p4.z
SetSpritePositionByOffset(testSpr.id,testSpr.x,testSpr.y)
Print(testSpr.x)
sync()
next mu
//SetSpriteVisible(testSpr.id,0)
EndFunction
function saveArray(count as integer)
write = OpenToWrite("arrayPath.txt" ,0)
length=count
String$ = Str(length-1)
WriteLine (write,String$)
WriteLine (write,Str(closed))
for num=1 to length
StringX$ = Str(path[num].x-(xMax/2))
StringY$ = Str(path[num].y-(yMax/2))
WriteLine (write,StringX$)
WriteLine (write,StringY$)
next num
Closefile(write)
write = OpenToWrite("arrayBezier.txt" ,0)
length=bc_getcurvesegmentpointcount()-1
String$ = Str(length-1)
WriteLine (write,String$)
WriteLine (write,Str(closed))
if bc_getcurvesegmentpointcount()>0
for i=1 to bc_getcurvesegmentpointcount()-2 //normally use -1, but I want to stop 1 early of the end of the array
StringX$ = Str((bc_getcurvesegmentpointx(i)+testSpr.xOffset)-(xMax/2))
StringY$ = Str((bc_getcurvesegmentpointy(i)+testSpr.yOffset)-(yMax/2))
WriteLine (write,StringX$)
WriteLine (write,StringY$)
next i
endif
Closefile(write)
endfunction
function loadArray()
for t = 0 to 100
path[t].x=0:path[t].y=0
next t
If GetFileExists("arrayPath.txt")
read = OpenToRead("arrayPath.txt")
String1$ = ReadLine(read)
length=val(String1$)
String2$ = ReadLine(read)
closed=val(String2$):testSpr.closed=closed
BC_RemoveCurvePoints()
//dim path[length] as object
for num =1 to length
StringX$ = ReadLine(read)
StringY$ = ReadLine(read)
path[num].x=((xMax/2)+val(StringX$))
path[num].y=((yMax/2)+val(StringY$))
SetRenderToImage (renderImg,0)
SetSpritePosition(spr,path[num].x,path[num].y)
drawSprite(spr)
bc_addcurvepoint(path[num].x,path[num].y)
if closed=0
bc_calculateopencurvesegmentpoints()
else
bc_calculateclosedcurvesegmentpoints()
endif
Update(0)
Render()
setrendertoscreen ()
SetSpriteSize(350,1024,768)
Update(0)
Render()
swap()
next num
Closefile(read)
if closed=1
SetVirtualButtonText( closedBtn, "Closed" ) //set to music text
else
SetVirtualButtonText( closedBtn, "Open" ) //set to music text
endif
count=length
endif
endfunction count
Clonkex Bezier include library
/*
---------------------------------------------------------
---- Bezier Curve Library v1.21 (BASIC) ----
---- By Clonkex aka David Hynd ----
---- Created 12/03/14 - 11/04/14 ----
---------------------------------------------------------
Legal:
Do what you want with it. Have fun! xD
Changes:
[20/03/14] 1.0 - Public release
[21/03/14] 1.1 - Fixed closed curves (so they actually work and all that)
[22/03/14] 1.11 - Tiny eency little fix (forgot to change an X to a Y)
[22/03/14] 1.2 - Fixed some floats not being floats and wrote the C++ version of the library
[11/04/14] 1.21 - Fixed some bugs in the C++ version related to for-loops
Usage:
Coming soon (i.e. when I feel like writing it). For now look at the example.
Function list:
BC_AddCurvePoint(posx#,posy#) -- Adds a new point to the curve at the specified position
BC_RemoveCurvePoints() -- Removes all points from the curve
BC_CalculatePointOnOpenCurve(t#) -- Finds a point on the curve from distance along it in a range of 0-1; calculates an open-ended curve
BC_CalculatePointOnClosedCurve(t#) -- Finds a point on the curve from distance along it in a range of 0-1; calculates a closed curve
BC_GetCurvePointCount() -- Returns the number of points currently making up the curve
BC_GetCurvePointX() -- Returns the last calculated position from BC_CalculatePointOnXXXCurve()
BC_GetCurvePointY() -- Returns the last calculated position from BC_CalculatePointOnXXXCurve()
BC_CalculateClosestPointToCurve(x#,y#) -- Finds the closest point on the curve to the position; call BC_CalculateXXXCurveSegmentPoints() first!
BC_GetClosestPointX() -- Returns the last calculated closest position from BC_CalculateClosestPointToCurve()
BC_GetClosestPointY() -- Returns the last calculated closest position from BC_CalculateClosestPointToCurve()
BC_GetClosestPointDistance() -- Returns the distance to the last calculated closest position from BC_CalculateClosestPointToCurve()
BC_GetClosestPointIndex() -- Returns the index of the last calculated segment point from BC_CalculateClosestPointToCurve()
BC_SetCurveSegmentPointCount(count) -- Sets how many segment points should be created from the curve
BC_GetCurveSegmentPointCount() -- Returns the number generated of segment points
BC_GetCurveSegmentPointX(index) -- Returns the position of a specific segment point
BC_GetCurveSegmentPointY(index) -- Returns the position of a specific segment point
BC_CalculateOpenCurveSegmentPoints() -- Cuts up a curve into a set number of points (segment points) making straight lines
BC_CalculateClosedCurveSegmentPoints() -- Cuts up a curve into a set number of points (segment points) making straight lines
BC_Distance(x1#,y1#,x2#,y2#) -- Used internally; calculates the distance between two 2D points
BC_PointOnLineX(x1#,y1#,x2#,y2#,percent#) -- Used internally; calculates a position based on a distance along a 2D line
BC_PointOnLineY(x1#,y1#,x2#,y2#,percent#) -- Used internally; calculates a position based on a distance along a 2D line
*/
_BC_Setup:
global bc_lastcurvepointx#=0.0
global bc_lastcurvepointy#=0.0
global bc_curvepointcount=0
global bc_distanceiterations=50
global bc_closestdistance#=0.0
global bc_closestpointx#=0.0
global bc_closestpointy#=0.0
global bc_closestindex=0
global bc_curvesegmentpointcount=0
type bc_curvepointinfo
posx# as float
posy# as float
endtype
type bc_curvesegmentpointinfo
posx# as float
posy# as float
endtype
dim bc_curvepoint[0] as bc_curvepointinfo
dim bc_curvesegmentpoint[0] as bc_curvesegmentpointinfo
return
function BC_AddCurvePoint(posx#,posy#)
bc_curvepointcount=bc_curvepointcount+1
dim bc_curvepoint[bc_curvepointcount] as bc_curvepointinfo
bc_curvepoint[bc_curvepointcount-1].posx#=posx#
bc_curvepoint[bc_curvepointcount-1].posy#=posy#
endfunction
function BC_RemoveCurvePoints()
bc_curvepointcount=0
dim bc_curvepoint[bc_curvepointcount] as bc_curvepointinfo
bc_curvesegmentpointcount=0
dim bc_curvesegmentpoint[bc_curvesegmentpointcount] as bc_curvesegmentpointinfo
endfunction
function BC_CalculatePointOnOpenCurve(t#) //t# is the percentage of the way along the line in a range of 0-1
if bc_curvepointcount>1
totalt#=t#*(bc_curvepointcount-1)
i=trunc(totalt#)
realt#=totalt#-i
p1posx#=bc_pointonlinex(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,0.3333)
p1posy#=bc_pointonliney(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,0.3333)
p2posx#=bc_pointonlinex(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,0.3333)
p2posy#=bc_pointonliney(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,0.3333)
if i=0
p0posx#=bc_curvepoint[i].posx#
p0posy#=bc_curvepoint[i].posy#
else
tempx#=bc_pointonlinex(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i-1].posx#,bc_curvepoint[i-1].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i-1].posx#,bc_curvepoint[i-1].posy#,0.3333)
p0posx#=bc_pointonlinex(tempx#,tempy#,p1posx#,p1posy#,0.5)
p0posy#=bc_pointonliney(tempx#,tempy#,p1posx#,p1posy#,0.5)
endif
if i=bc_curvepointcount-2
p3posx#=bc_curvepoint[i+1].posx#
p3posy#=bc_curvepoint[i+1].posy#
else
tempx#=bc_pointonlinex(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i+2].posx#,bc_curvepoint[i+2].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i+2].posx#,bc_curvepoint[i+2].posy#,0.3333)
p3posx#=bc_pointonlinex(p2posx#,p2posy#,tempx#,tempy#,0.5)
p3posy#=bc_pointonliney(p2posx#,p2posy#,tempx#,tempy#,0.5)
endif
//begin calculations (conveniently adapted from http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/):
u#=1-realt#
tt#=realt#*realt#
uu#=u#*u#
uuu#=uu#*u#
ttt#=tt#*realt#
bc_lastcurvepointx#=uuu#*p0posx# //first term
bc_lastcurvepointy#=uuu#*p0posy# //first term
bc_lastcurvepointx#=bc_lastcurvepointx#+3*uu#*realt#*p1posx# //second term
bc_lastcurvepointy#=bc_lastcurvepointy#+3*uu#*realt#*p1posy# //second term
bc_lastcurvepointx#=bc_lastcurvepointx#+3*u#*tt#*p2posx# //third term
bc_lastcurvepointy#=bc_lastcurvepointy#+3*u#*tt#*p2posy# //third term
bc_lastcurvepointx#=bc_lastcurvepointx#+ttt#*p3posx# //fourth term
bc_lastcurvepointy#=bc_lastcurvepointy#+ttt#*p3posy# //fourth term
else
if bc_curvepointcount>0
bc_lastcurvepointx#=bc_curvepoint[0].posx#
bc_lastcurvepointy#=bc_curvepoint[0].posy#
else
message("Bezier Curve Library: Tried to calculate a curve with no points! You douchebag!")
end
endif
endif
endfunction
function BC_CalculatePointOnClosedCurve(t#) //t# is the percentage of the way along the line in a range of 0-1
if bc_curvepointcount>1
totalt#=t#*bc_curvepointcount
i=trunc(totalt#)
realt#=totalt#-i
if i=bc_curvepointcount-1
p1posx#=bc_pointonlinex(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,0.3333)
p1posy#=bc_pointonliney(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,0.3333)
p2posx#=bc_pointonlinex(bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,0.3333)
p2posy#=bc_pointonliney(bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,0.3333)
else
p1posx#=bc_pointonlinex(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,0.3333)
p1posy#=bc_pointonliney(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,0.3333)
p2posx#=bc_pointonlinex(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,0.3333)
p2posy#=bc_pointonliney(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,0.3333)
endif
if i=0
tempx#=bc_pointonlinex(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[bc_curvepointcount-1].posx#,bc_curvepoint[bc_curvepointcount-1].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[bc_curvepointcount-1].posx#,bc_curvepoint[bc_curvepointcount-1].posy#,0.3333)
p0posx#=bc_pointonlinex(tempx#,tempy#,p1posx#,p1posy#,0.5)
p0posy#=bc_pointonliney(tempx#,tempy#,p1posx#,p1posy#,0.5)
else
tempx#=bc_pointonlinex(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i-1].posx#,bc_curvepoint[i-1].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[i].posx#,bc_curvepoint[i].posy#,bc_curvepoint[i-1].posx#,bc_curvepoint[i-1].posy#,0.3333)
p0posx#=bc_pointonlinex(tempx#,tempy#,p1posx#,p1posy#,0.5)
p0posy#=bc_pointonliney(tempx#,tempy#,p1posx#,p1posy#,0.5)
endif
if i=bc_curvepointcount-2
tempx#=bc_pointonlinex(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,0.3333)
p3posx#=bc_pointonlinex(p2posx#,p2posy#,tempx#,tempy#,0.5)
p3posy#=bc_pointonliney(p2posx#,p2posy#,tempx#,tempy#,0.5)
else
if i=bc_curvepointcount-1
tempx#=bc_pointonlinex(bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,bc_curvepoint[1].posx#,bc_curvepoint[1].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[0].posx#,bc_curvepoint[0].posy#,bc_curvepoint[1].posx#,bc_curvepoint[1].posy#,0.3333)
p3posx#=bc_pointonlinex(p2posx#,p2posy#,tempx#,tempy#,0.5)
p3posy#=bc_pointonliney(p2posx#,p2posy#,tempx#,tempy#,0.5)
else
tempx#=bc_pointonlinex(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i+2].posx#,bc_curvepoint[i+2].posy#,0.3333)
tempy#=bc_pointonliney(bc_curvepoint[i+1].posx#,bc_curvepoint[i+1].posy#,bc_curvepoint[i+2].posx#,bc_curvepoint[i+2].posy#,0.3333)
p3posx#=bc_pointonlinex(p2posx#,p2posy#,tempx#,tempy#,0.5)
p3posy#=bc_pointonliney(p2posx#,p2posy#,tempx#,tempy#,0.5)
endif
endif
//begin calculations (conveniently adapted from http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/):
u#=1-realt#
tt#=realt#*realt#
uu#=u#*u#
uuu#=uu#*u#
ttt#=tt#*realt#
bc_lastcurvepointx#=uuu#*p0posx# //first term
bc_lastcurvepointy#=uuu#*p0posy# //first term
bc_lastcurvepointx#=bc_lastcurvepointx#+3*uu#*realt#*p1posx# //second term
bc_lastcurvepointy#=bc_lastcurvepointy#+3*uu#*realt#*p1posy# //second term
bc_lastcurvepointx#=bc_lastcurvepointx#+3*u#*tt#*p2posx# //third term
bc_lastcurvepointy#=bc_lastcurvepointy#+3*u#*tt#*p2posy# //third term
bc_lastcurvepointx#=bc_lastcurvepointx#+ttt#*p3posx# //fourth term
bc_lastcurvepointy#=bc_lastcurvepointy#+ttt#*p3posy# //fourth term
else
if bc_curvepointcount>0
bc_lastcurvepointx#=bc_curvepoint[0].posx#
bc_lastcurvepointy#=bc_curvepoint[0].posy#
else
message("Bezier Curve Library: Tried to calculate a curve with no points! You douchebag!")
end
endif
endif
endfunction
function BC_GetCurvePointCount()
endfunction bc_curvepointcount
function BC_GetCurvePointX()
endfunction bc_lastcurvepointx#
function BC_GetCurvePointY()
endfunction bc_lastcurvepointy#
function BC_CalculateClosestPointToCurve(posx#,posy#) //x# and y# are the point from which we're searching
bc_closestdistance#=1000000 //hack, but basically could never be larger than this anyway
if bc_curvepointcount>0
bc_closestpointx#=0
bc_closestpointy#=0
for i=0 to bc_distanceiterations-1
distance#=bc_distance(posx#,posy#,bc_curvesegmentpoint[i].posx#,bc_curvesegmentpoint[i].posy#)
if distance#<bc_closestdistance#
bc_closestdistance#=distance#
bc_closestpointx#=bc_curvesegmentpoint[i].posx#
bc_closestpointy#=bc_curvesegmentpoint[i].posy#
bc_closestindex=i
endif
next i
else
bc_closestpointx#=0
bc_closestpointy#=0
endif
endfunction
function BC_GetClosestPointX()
endfunction bc_closestpointx#
function BC_GetClosestPointY()
endfunction bc_closestpointy#
function BC_GetClosestPointDistance()
endfunction bc_closestdistance#
function BC_GetClosestPointIndex()
endfunction bc_closestindex
function BC_SetCurveSegmentPointCount(count)
bc_distanceiterations=count
endfunction
function BC_GetCurveSegmentPointCount()
endfunction bc_curvesegmentpointcount
function BC_GetCurveSegmentPointX(index)
x#=bc_curvesegmentpoint[index].posx#
endfunction x#
function BC_GetCurveSegmentPointY(index)
y#=bc_curvesegmentpoint[index].posy#
endfunction y#
function BC_CalculateOpenCurveSegmentPoints()
bc_curvesegmentpointcount=bc_distanceiterations
dim bc_curvesegmentpoint[bc_curvesegmentpointcount] as bc_curvesegmentpointinfo
if bc_curvepointcount>0
add#=1.0/bc_distanceiterations
t#=0
for i=0 to bc_curvesegmentpointcount-1
bc_calculatepointonopencurve(t#)
bc_curvesegmentpoint[i].posx#=bc_lastcurvepointx#
bc_curvesegmentpoint[i].posy#=bc_lastcurvepointy#
t#=t#+add#
next i
endif
endfunction
function BC_CalculateClosedCurveSegmentPoints()
bc_curvesegmentpointcount=bc_distanceiterations
dim bc_curvesegmentpoint[bc_curvesegmentpointcount] as bc_curvesegmentpointinfo
if bc_curvepointcount>0
add#=1.0/bc_distanceiterations
t#=0
for i=0 to bc_curvesegmentpointcount-1
if i=bc_distanceiterations-1 then t#=0.9999999
bc_calculatepointonclosedcurve(t#)
bc_curvesegmentpoint[i].posx#=bc_lastcurvepointx#
bc_curvesegmentpoint[i].posy#=bc_lastcurvepointy#
t#=t#+add#
next i
endif
endfunction
function BC_Distance(x1#,y1#,x2#,y2#)
dx#=x1#-x2#
dy#=y1#-y2#
distance#=sqrt(dx#*dx#+dy#*dy#)
endfunction distance#
function BC_PointOnLineX(x1#,y1#,x2#,y2#,percent#)
px#=x1#+((x2#-x1#)*percent#)
endfunction px#
function BC_PointOnLineY(x1#,y1#,x2#,y2#,percent#)
py#=y1#+((y2#-y1#)*percent#)
endfunction py#
and an example of using it with the current Bezier curve moving around the mouse x y position
and with a bullet trail using the draw command when mouse is clicked
// Project: Space Odyssey
// Created: 2017-11-27
// show all errors
SetErrorMode(2)
#constant spr=1
#constant xMax=1024
#constant yMax=768
type Ttrail
x as float
y as float
endtype
type object
x as float
y as float
endtype
type mySpr
id as integer
length as integer
offsetX as float
offsetY as float
x as float
y as float
closed as integer
endtype
global dim testSpr[100] as mySpr
// set window properties
SetWindowTitle( "Space Odyssey" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 ) // doesn't have to match the window
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 30, 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
//loadimage (1,"6.png")
//loadimage (2,"missileLaunch.png")
//loadimage (3,"missileTrail.png")
createSprite(1,0)
SetSpriteSize(1,100,100)
createSprite(100,0):SetSpriteSize(100,10,10)
SetSpriteVisible(100,0):SetSpriteDepth(100,10)
//createSprite(101,3):SetSpriteVisible(101,0):SetSpriteDepth(101,11)
//loadArrayPath():testSpr[0].x=testSpr[1].x+500:testSpr[0].y=testSpr[1].y+300
loadArrayBezier()
global count=1
local trail as Ttrail[10]
i=0
local x as float
local y as float
local time as float
time =0
do
x#=GetPointerX():y#=GetPointerY()
moveBezier(count,x#,y#)
//movePath(x#,y#,10)
//trail bullets
if getpointerpressed()=1
x=GetSpriteXByOffset(spr)+50
y=GetSpriteYByOffset(spr)
SetSpritePositionByOffset(100,x,y)
SetSpriteVisible(100,1)
endif
x=x+15
time = time +GetFrameTime()
if time>.05
time = 0
i1=i1+1
if i1>10 then i1=0
trail[i1].x = x
trail[i1].y = y
endif
for i=0 to 10
SetSpritePositionByOffset(100,trail[i].x,trail[i].y)
DrawSprite(100)
next
Sync()
loop
function loadArrayPath()
If GetFileExists("arrayPath.txt")
read = OpenToRead("arrayPath.txt")
String1$ = ReadLine(read)
length=val(String1$)
String2$ = ReadLine(read)
testSpr[0].length=length
//dim path[length] as object
for num =1 to length
testSpr[num].id=1
testSpr[num].length=length
testSpr[num].closed=val(String2$)
StringX$ = ReadLine(read)
StringY$ = ReadLine(read)
testSpr[num].x=val(StringX$)
testSpr[num].y=val(StringY$)
next num
Closefile(read)
count=length
endif
endfunction
function loadArrayBezier()
If GetFileExists("arrayBezier.txt")
read = OpenToRead("arrayBezier.txt")
String1$ = ReadLine(read)
length=val(String1$)
String2$ = ReadLine(read)
//dim path[length] as object
for num =1 to length
testSpr[num].id=1
testSpr[num].length=length
testSpr[num].closed=val(String2$)
StringX$ = ReadLine(read)
StringY$ = ReadLine(read)
testSpr[num].x=val(StringX$)
testSpr[num].y=val(StringY$)
next num
Closefile(read)
count=length
endif
endfunction count
function movePath(x#,y#,speed#)
if count<testSpr[1].length
if getDistance(testSpr[0].x,testSpr[0].y,testSpr[count+1].x,testSpr[count+1].y)<=5 then inc count
angle#=getAngle(testSpr[0].x,testSpr[0].y,testSpr[count+1].x,testSpr[count+1].y)
testSpr[0].x=testSpr[0].x-sin(angle#)*speed#:testSpr[0].y=testSpr[0].y+cos(angle#)*speed#
SetSpritePositionByOffset(1,testSpr[0].x+x#,testSpr[0].y+y#)
else
if getDistance(testSpr[0].x,testSpr[0].y,testSpr[1].x,testSpr[1].y)<=5 then count=1
angle#=getAngle(testSpr[0].x,testSpr[0].y,testSpr[1].x,testSpr[1].y)
testSpr[0].x=testSpr[0].x-sin(angle#)*speed#:testSpr[0].y=testSpr[0].y+cos(angle#)*speed#
SetSpritePositionByOffset(1,testSpr[0].x+x#,testSpr[0].y+y#)
endif
//if count>testSpr[1].length then count=1
endfunction
function moveBezier(num,x#,y#)
SetSpritePositionByOffset(testSpr[num].id,testSpr[num].x+x#,testSpr[num].y+y#)
inc count:if count>testSpr[1].length then count=1
endfunction
function getAngle(x1#, y1#, x2#, y2#)
result# = ATanFull(x1# - x2#, y1# - y2#)
endfunction result#
function getDistance (x1#,y1#,x2#,y2#)
dx#=x1#-x2#
dy#=y1#-y2#
distance#=sqrt((dx#*dx#)+(dy#*dy#)):rem distance object to path point
endfunction distance#
fubar