This tiny source code snippet uses PlayBASIC's shapes to draw batches of line fragments. The fragments are all connected in a circle were each vertex is waving and rotating. On their own the effect is really simple; but when you overlay (rotate and scale) a bunch of them on top of each other it creates a sort of button effect similar to the robotic voice in the classic science function movie 2001 A Space Odyssey. Excuse my poor impressions of Hal in this video.. It's just for laughs
PlayBASIC Code:
; PROJECT : Morphing Shape Tunnel; AUTHOR : Learn To Code PlayBASIC - http://PlayBASIC.com; CREATED : 11/05/2022; EDITED : 13/05/2022; ---------------------------------------------------------------------openscreen1280,960,32,1positionscreengetscreenxpos(),10
Count=360*3
RingShape =NewShape(Count, Count)// Set the edge links for this shape.For lp =0to Count-2SetShapeEdge RingShape,lp, lp,lp+1next; // link the last one back to the first SetShapeEdge RingShape,lp,lp,0
Screen=NewFxImage(GetSurfaceWidth(),GetSurfaceHeight())
Scaler#=2
Rings=10
Ringcolour=$505050
ColourCountDown=200dorendertoimage Screen
inkmode1+2048boxc0,0,getsurfacewidth(),getsurfaceheight(),true,$f0e0d0
mx#=getsurfacewidth()/2
my#=GetSurfaceheight()/2
Scaler#=wrapvalue(scaler#+0.25,1,100)for lp =0to Count-1; randomly init the vertex as polar coordinates
Angle#=(360.0/Count)*lp
; Radius# =120+cosRadius(WobbleAngle2#+lp*1.23,34)+ Cos(WobbleAngle#+(Angle#*Scaler#))*50
Radius# =90+cos(WobbleAngle#+(Angle#*Scaler#))*50setshapevertex RingShape,lp,Cosradius(Angle#,Radius#) ,Sinradius(Angle#,Radius#)next; WobbleAngle2#+=0.43
WobbleAngle#-=(2.25)*4lockbuffer
Scale#=0.5inkmode1+64for lp=0to Rings
inkRgbFade( Ringcolour, Float(lp)/Rings *50)rotateshape ringShape,SpinAngle#+lp*10,Scale#
drawshape RingShape,mx#,my#,1
Scale#+=0.33nextunlockbuffer
SpinAngle#+=0.2rendertoscreendrawimage Screen,0,0,false
ColourCountDown--if ColourCountDown<0
ColourCountDown=30
Ringcolour=rgbalphaadd((rndrgb()and$3f3f3f), $080808)endifsyncloopspacekey()
- Music: The Right Direction by Shane Ivers - https://www.silvermansound.com
Movie samples - https://movie-sounds.org/
2D Vector Library
By: Kevin Picone | Added: July 7th, 2025
2D Vector Library
This library provides a set of functions for working with 2D vectors. A 2D vector is a geometric object that has both magnitude (length) and direction and can be represented by an ordered pair of real numbers (x, y).
The functions in this library allow you to create, manipulate, and perform calculations with 2D vectors. Some of the things you can do with these functions include:
- Set the x and y components of a 2D vector using SetVector2D - Convert polar coordinates (angle and radius) to Cartesian coordinates (x and y) using SetPolar2D - Copy the values of one 2D vector to another using CopyVector2D - Add or subtract two 2D vectors using AddVectors2D or SubVectors2D - Multiply or divide two 2D vectors component-wise using MultVectors2D or DivVectors2D - Multiply or divide a 2D vector by a scalar value using MultVector2D or DivVector2D - Linearly interpolate between two 2D vectors using LerpVector2D - Normalize a 2D vector (i.e., set its magnitude to 1) using GetVectorNormal2D - Calculate the length or squared length of a 2D vector using GetVectorLength2D or GetVectorSquaredLength2D - Check if two 2D vectors are equal using AreVectorsEqual2D - Calculate the dot product or cross product of two 2D vectors using DotProduct2D or CrossProduct2D
PlayBASIC Code:
; PROJECT : Vector Library; AUTHOR : Kevin Picone - PlayBASIC Tutor - https://PlayBASIC.com; CREATED : 12/05/2022; EDITED : 28/05/2022; ---------------------------------------------------------------------// Use a typed array to hold all the vectors we'll be usingDim vectors(100)as vector2d
for lp =0togetArrayElements(vectors())
vectors(lp)=new vector2D
next// declare some pointers of type vector for use in the examples Dim N as vector2d pointerDim V1 as vector2d pointerDim V2 as vector2d pointerDim OldPoint as vector2D pointer// Get pointers to some pre--allocated vectors in our cache array
n = Vectors(0).vector2d
V1 = Vectors(1).vector2d
V2 = Vectors(2).vector2d
Dim CurrentPoint as vector2D pointer
CurrentPOint = Vectors(3).vector2d
Dim OldPoint as vector2D pointer
OldPOint = Vectors(4).vector2d
Dim Lerp1 as vector2D pointer
Lerp1 = Vectors(10).vector2d
Dim Lerp2 as vector2D pointer
Lerp2 = Vectors(11).vector2d
SetVector2d lerp1, 500,100
SetPolar2d lerp2, Rnd(36),rndrange(10,100)
Addvectors2d Lerp2, Lerp2, Lerp1
// Set up this vector
Setvector2d OldPOint,Mousex(),MouseY()Flushmouse// -----------------------------------------------------------// -----------------------------------------------------------// -----------------------------------------------------------Do// -----------------------------------------------------------// -----------------------------------------------------------// -----------------------------------------------------------CLS// Set up this vecor
Setvector2d CurrentPoint,Mousex(),MouseY()circlec OldPoint.X,OldPoint.Y, 50,true, $00ff00circle CurrentPoint.X,CurrentPOint.Y, 50,true// Subtract target from current N = Old - Current
Subvectors2d(N , oldPoint,CurrentPoint)
ypos=50text10,Ypos, "Delta:"+StrVector2d$(N)// Get the length of this delta vector
Dist#=GetVectorLenght2D(N)// normalize N = and store it back in N
GetVectorNormal2D(N , N)text10,Ypos+30, "Normalized:"+StrVector2d$(N)// Scale Normal by Dist#
Multvector2d(N , N, Dist#)text10,Ypos+60, "Scaled Normalized:"+StrVector2d$(N)// Add origin (current point) back on.
Addvectors2d(N , N, CurrentPoint)text10,Ypos+90, "Result:"+StrVector2d$(N)// Scale it so we can draw line between themline CurrentPOint.x,CurrentPOint.y,n.x,n.y
ifMousebutton()=1
CopyVector2d OldPoint,CurrentPOint
endif// test lerpLinec Lerp1.x,Lerp1.y,Lerp2.x,Lerp2.y, $ff00ff//
LerpFrame =mod(LerpFrame+1,100)
LerpScale# =LerpFrame/100.0
LerpVector2d N,Lerp1,Lerp2,LerpScale#
Circlec n.x , n.y, 5, true ,$ff00ff// Curve Lerp vector to the one between
LerpVector2d V1,Lerp1,Lerp2,LerpScale#
LerpVector2d V2,CurrentPoint,OldPoint,LerpScale#
LerpVector2d V1,V2,V1,LerpScale#
Circlec v1.x , v1.y, 5, true ,$ff00ff
LerpVector2d V1,Lerp1,Oldpoint,LerpScale#
LerpVector2d V2,lerp2,CurrentPoint,LerpScale#
LerpVector2d V1,V2,V1,LerpScale#
Circlec v1.x , v1.y, 5, true ,$ff00ffSyncloopSpacekey()
#1
2D-Vectors-Library-V001.zip (4.85 KB)
Tokenize String Simple String Lexer
By: Kevin Picone | Added: July 10th, 2025
Tokenize String - Simple String Lexer
Here are the main bullet points that summarize what this code does:
* The code defines a custom data type named tLexToken that has three fields: TOKEN$, TOKEN_TYPE, and INDEX.
- The code initializes an array named TOKENS to hold instances of tLexToken. The array has 256 elements.
- The code creates a string variable named Message$ that contains a string to be tokenized. The string has some numbers, a string literal, and an arithmetic expression.
- The code calls a function named TOKENIZE_STRING that takes two arguments: a string to be tokenized and an array of tLexToken instances to hold the tokens.
- The TOKENIZE_STRING function defines three arrays to map ASCII characters to token types: ASCII_MAP, ASCII_WORD, and ASCII_NUMBER. The function also initializes a variable named TOKENS_COUNT to zero.
- The TOKENIZE_STRING function loops over each character in the input string and checks its ASCII value against the mapping arrays to determine its token type. The function then groups consecutive characters of the same type into a single token and adds it to the TOKENS array.
- The TOKENIZE_STRING function returns the number of tokens that it has created.
- The main code then loops over the TOKENS array and prints each token's index, type, and value. Finally, the code waits for the user to press a key before terminating.
PlayBASIC Code:
Type tLexToken
TOKEN$
TOKEN_TYPE
INDEX
EndTypeDim TOKENS(256)as tLexToken
Message$=" This is the string I was to tokenize. 1000 * 2000"
Message$+=chr$(34)+"String Literal"+chr$(34)
Message$+="12+4+5+6"print Message$
Count=TOKENIZE_STRING(Message$, TOKENS())For lp =0to Count-1
s$ ="("+str$(Tokens(lp).TOKEN_TYPE)+")"
s$+="="+Tokens(lp).TOKEN
print"#"+str$(lp)+" "+s$
nextSyncwaitkey// --------------------------------------------------------------------------------------------------// --------------------------------------------------------------------------------------------------// -------------------------------------->> TOKENIZE STRING <<---------------------------------------// --------------------------------------------------------------------------------------------------// --------------------------------------------------------------------------------------------------function TOKENIZE_STRING(InputTEXT$, TOKENS().tLexToken)
Size =len(InputTEXT$)Static _INIT_LOCALS
if _INIT_LOCALS=false
_INIT_LOCALS=truedim ASCII_MAP(255)dim ASCII_WORD(255)dim ASCII_NUMBER(255)// ----------------------------------------------------------// Map common ASCC CHARACTERs// ----------------------------------------------------------
ASCII_MAP(9)=9// TAB charatcer// ----------------------------------------------------------// MAP Characters// ----------------------------------------------------------
WORD$ =" .()+-/*="for lp=1tolen(WORD$)
ThisCHR =mid(WORD$,lp)
ASCII_MAP(ThisCHR)= ThisCHR
next// ----------------------------------------------------------// WORDS UPPER / LOWER CASE with UNDER SCORES// ----------------------------------------------------------
WORD$ ="_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"for lp=1tolen(WORD$)
ThisCHR =mid(WORD$,lp)
ASCII_MAP(ThisCHR)=1000next// ----------------------------------------------------------// NUMBERS// ----------------------------------------------------------
WORD$ ="0123456789"for lp=1tolen(WORD$)
ThisCHR =mid(WORD$,lp)
ASCII_MAP(ThisCHR)=1001next// ----------------------------------------------------------// STRING LITERAL // ----------------------------------------------------------
ASCII_MAP(34)=1002// STRING LITERAL block// ----------------------------------------------------------// ALPHA NUMERIC WORDS // ----------------------------------------------------------
WORD$ ="0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";for lp=1tolen(WORD$)
ThisCHR =mid(WORD$,lp)
ASCII_WORD( ThisCHR)= ThisCHR
next// ----------------------------------------------------------// ALPHA NUMERIC WORDS // ----------------------------------------------------------
WORD$ ="0123456789."for lp=1tolen(WORD$)
ThisCHR =mid(WORD$,lp)
ASCII_NUMBER( ThisCHR)= ThisCHR
nextendif
TOKENS_COUNT=0for lp=1to size
ThisCHR =mid(InputTEXT$,lp)
CHR_TYPE = ASCII_MAP(ThisCHR)// DECODE RUN OF SAME TYPE OF CHARACTERS if(CHR_TYPE>255)
EndPOS = lp
// -------------------------------------------------// DECODE A WORD // -------------------------------------------------if(CHR_TYPE=1000)for ScanLP=lp to Size
SearchCHR =mid(InputTEXT$,ScanLP)if(ASCII_WORD(SearchCHR)=0)thenexit
EndPOS = ScanLP
nextendif// -------------------------------------------------// DECODE A NUMBER // -------------------------------------------------if(CHR_TYPE=1001)for ScanLP=lp to Size
SearchCHR =mid(InputTEXT$,ScanLP)if(ASCII_NUMBER(SearchCHR)=0)thenexit
EndPOS = ScanLP
nextendif// -------------------------------------------------// DECODE A STRING LITERAL// -------------------------------------------------if(CHR_TYPE=1002)for ScanLP=lp+1to Size
SearchCHR =mid(InputTEXT$,ScanLP)
EndPOS = ScanLP
if SearchCHR=34thenexitnextendif// Get This TOKEN
TOKEN$ =mid$(InputTEXT$, lp, (EndPOS+1)-lp)
TOKENS(TOKENS_COUNT)=new tLexTOKEN
TOKENS(TOKENS_COUNT).TOKEN = TOKEN$
TOKENS(TOKENS_COUNT).TOKEN_TYPE = CHR_TYPE
TOKENS(TOKENS_COUNT).INDEX = lp
TOKENS_COUNT++;
lp=EndPOS
continueendifif(CHR_TYPE)
TOKENS(TOKENS_COUNT)=new tLexTOKEN
TOKENS(TOKENS_COUNT).TOKEN =chr$(ThisCHR)
TOKENS(TOKENS_COUNT).TOKEN_TYPE = CHR_TYPE
TOKENS(TOKENS_COUNT).INDEX = lp
TOKENS_COUNT++endifnextendfunction TOKENS_COUNT
Make Cogs Shapes Example
By: Kevin Picone | Added: July 7th, 2025
Make Cogs - Shapes Example
Here's a cool old example that you'll find deep inside the PlayBASIC example packs
PlayBASIC Code:
; PROJECT : Make_Cogs; AUTHOR : Kevin Picone; CREATED : 11/04/2006; EDITED : 21/06/2006; ---------------------------------------------------------------------
Cog=Create_Cog_Shape(100,80,23)
ScreenCX=GetScreenWidth()/2
ScreenCY=GetScreenHeight()/2
ShapeColour=rgb(255,255,255)
TestShape =newconvexshape(200,4)
TestShape2 =newconvexshape(100,4)mergeshape testshape2,testshape
Doclsrgb(100,100,100)
mx=mousex()
my=mousey()
dx#=ScreencX-mx
dy#=ScreencY-mY
lockbuffer
ShadowX#=ScreenCX+(dx#/2)
ShadowY#=ScreenCY+(dy#/2)inkrgbfade(shapecolour,20)rotateshape cog,angle#,2DrawShape Cog,ShadowX#,ShadowY#,2; draw the foreground version of the spinning cog shaperotateshape cog,angle#,1ink ShapeCOlour
inkmode1DrawShape cog,ScreenCX,ScreenCY,2unlockbuffer; bump the rotation angle
angle#=wrapangle(angle#,1)syncloopFunction Create_Cog_Shape(outterRadius,InnerRadius,sides)
sides=sides -(mod(sides,2))
EdgeCount =Sides*2
VertexCount =Sides*2
ThisShape =NewShape(VertexCount+1,EdgeCount+1)For lp=0to sides
x#=Cosradius(angle#,OutterRadius)
y#=Sinradius(angle#,OutterRadius)SetshapeVertex thisshape,Numberofvertex,x#,y#
inc Numberofvertex
x#=Cosradius(angle#,InnerRadius)
y#=Sinradius(angle#,InnerRadius)SetshapeVertex Thisshape,Numberofvertex,x#,y#
inc Numberofvertex
angle#=angle#+(360.0/Sides)nextFor Vertex=0to Numberofvertex-2step2
NextVertex=vertex+1if NextVertex=>Numberofvertex then nextVertex=Numberofvertex-NextVertex
SetshapeEdge Thisshape,Edge,vertex,Nextvertex
inc edge
if Outline
SrcVertex=Vertex
NextVertex2=vertex+2if NextVertex2=>Numberofvertex then nextVertex2=Numberofvertex-NextVertex
else
SrcVertex=NextVertex
NextVertex2=vertex+3if NextVertex2=>Numberofvertex then nextVertex2=Numberofvertex-NextVertex
endifSetshapeEdge Thisshape,Edge,Srcvertex,Nextvertex2
inc edge
Outline=1-Outline
nextEndFunction ThisShape
Clip Rectangle To Rectangle
By: Kevin Picone | Added: July 7th, 2025
Clip Rectangle To Rectangle
In this example, we're clipping the background rectangle to the foreground rectangle. This results in 16 possible layouts that the pair of rectangles can have in relation to each other. The goal is to output a list of areas that represent the visible portion of the background rectangle without overlapping any pixels
PlayBASIC Code:
; PROJECT : Clip Foreground Rectangle TO Background Rectangle; AUTHOR : Kev Picone - https://PlayBASIC.com; CREATED : 8/04/2023; EDITED : 9/04/2023; ---------------------------------------------------------------------loadfont"courier new",1, 40Type tRect
x1,y1
x2,y2
Colour
EndTypeDim Rects(16)as tRect
Global RectCount =0doDim Back as tRect Pointer
Back =new TRect
w=rndrange(100,500)
h=rndrange(100,500)
X=rnd(getscreenwidth()*0.60)
Y=rnd(getscreenheight()*0.60)
Back.x1 = x
Back.y1 = y
Back.x2 = x+w
Back.y2 = y+h
Back.colour =rndrgb()Dim Front as tRect Pointer
Front =new TRect
W=500
H=150// --------------------------------------------------------Do// --------------------------------------------------------cls$203040Boxc Back.x1,Back.y1,Back.x2,Back.y2,true,Back.Colour
Front.x1=mousex()
Front.y1=mousey()
Front.x2=Front.x1+W
Front.y2=Front.y1+H
box Front.x1,Front.y1,Front.x2,Front.y2,trueinkmode1+1024
Status =ClipRectangles(Front,Back)inkmode1for lp =0to Status-1
X1=Rects(lp).x1
y1=Rects(lp).y1
x2=Rects(lp).x2
y2=Rects(lp).y2
boxc x1,y1,x2,y2,false, $00ff00boxc x1+1,y1+1,x2-1,y2-1,false, $00ff00
s$ =" X1="+str$(X1)
s$+=" Y1="+str$(Y1)
s$+=" Y1="+str$(X2)
s$+=" Y1="+str$(Y2)Print"#"+str$(lp)+s$
nextif Status=-2Print"Foreground covers background"endififmousebutton()=2
w=rndrange(50,500)
h=rndrange(50,350)endifsync// --------------------------------------------------------loopspacekey()// --------------------------------------------------------free front
free back
loopFunction ClipRectangles(Front as tRect Pointer, Back as tRect Pointer)
RectCount =0
Count =-1ifint(Front)=0orint(Back)=0thenExitFunction-1// chec if the Front rect to the left or right of te back rectif Front.X2<Back.X1 thenexitfunction Count
if Front.X1>Back.X2 thenexitfunction Count
// check if the FRONT is ABOVE or BELLOW the BACK rectif Front.Y2<Back.Y1 thenexitfunction Count
if Front.Y1>Back.Y2 thenexitfunction Count
// Make bit pattern for what side each point is to its patern
Layout =(Front.X1>=Back.X1 <<1)+( Front.X2>Back.X2)
Layout =Layout<<2
Layout+= Front.Y1>=Back.Y1 <<1
Layout+= Front.Y2>Back.Y2
Filled =truestatic ThisRGB
ThisRGB =-1printbin$(Layout)Select LayOut
// ---------------------------------------------case%0000// ---------------------------------------------// front is covering back to left and // above and bellow back
SetBox( Front.x2 ,Back.y1 ,back.x2 ,front.y2 , ThisRGB)
SetBox( Back.x1 ,front.y2 ,back.x2 ,back.y2 , ThisRGB)// ---------------------------------------------case%0001// ---------------------------------------------// front is covering back to left and // above and bellow back
SetBox( Front.x2,Back.y1 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%0010// ---------------------------------------------// top chunk
SetBox( Back.x1,Back.y1 ,back.x2 , front.y1, ThisRGB )// bottom chunk
SetBox( Back.x1,front.y2 ,back.x2 , back.y2, ThisRGB )// middle chuck to the right of the front rect
SetBox( Front.x2,front.y1 ,back.x2 ,front.y2, ThisRGB )// ---------------------------------------------case%0011// ---------------------------------------------// The front rect is covering back rect
SetBox( Back.x1,Back.y1 ,Back.x2 ,Front.y1, ThisRGB )
SetBox( front.x2,front.y1,back.x2,back.y2 ,ThisRGB )// ---------------------------------------------case%0100// ---------------------------------------------// visible left edge of back
SetBox( Back.x1,front.y2 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%0101// ---------------------------------------------// draw nothing// front overlaps backdropexitfunction-2// ---------------------------------------------case%0110// ---------------------------------------------// Top
SetBox( Back.x1,back.y1 ,back.x2 ,front.y1, ThisRGB )// bottom
SetBox( Back.x1,front.y2 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%0111// ---------------------------------------------// visible left edge of back
SetBox( Back.x1,back.y1 ,back.x2 ,front.y1, ThisRGB )// ---------------------------------------------case%1000// ---------------------------------------------// chunks of either side
SetBox( Back.x1 ,Back.y1 ,front.x1 ,front.y2, ThisRGB )
SetBox( front.x2 ,Back.y1 ,back.x2 , front.y2, ThisRGB )// bottom section
SetBox( Back.x1 ,front.y2 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%1001// ---------------------------------------------
SetBox( Back.x1,Back.y1 ,front.x1 ,back.y2, ThisRGB )
SetBox( front.x2,Back.y1 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%1010// ---------------------------------------------// front rect is inside the background rect// Top Chunk
SetBox( Back.x1,Back.y1 ,back.x2 ,front.y1, ThisRGB )// bottom
SetBox( Back.x1,front.y2 ,back.x2 ,back.y2, ThisRGB )// Left chunk
SetBox( Back.x1,front.y1 ,front.x1 ,front.y2, ThisRGB )// right chunk
SetBox( front.x2,front.y1 ,back.x2 ,front.y2, ThisRGB )// ---------------------------------------------case%1011// ---------------------------------------------// top section
SetBox( Back.x1,back.y1 ,back.x2 ,front.y1, ThisRGB )// left and right blocks
SetBox( Back.x1,front.y1 ,front.x1 ,back.y2, ThisRGB )
SetBox( front.x2,front.y1 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%1100// ---------------------------------------------// visible left edge of back
SetBox( Back.x1,Back.y1 ,front.x1 ,back.y2, ThisRGB )// visible bottom strip of bacl
SetBox( front.x1,front.y2 ,back.x2 ,back.y2, ThisRGB )// ---------------------------------------------case%1101// ---------------------------------------------// front is covering back to left and // above and bellow back
SetBox( Back.x1,Back.y1 ,front.x1 ,back.y2, ThisRGB )// ---------------------------------------------case%1110// ---------------------------------------------// top part
SetBox( Back.x1,Back.y1 ,Back.x2 ,Front.y1, ThisRGB )// bottom part
SetBox( Back.x1,front.y2 ,Back.x2 ,back.y2, ThisRGB )// left hand box
SetBox( Back.x1,front.y1 ,front.x1 ,Front.y2, ThisRGB )// ---------------------------------------------case%1111// ---------------------------------------------// The front rect is covering back rect
SetBox( Back.x1,Back.y1 ,Back.x2 ,Front.y1, ThisRGB )
SetBox( Back.x1,front.y1,front.x1,back.y2 ,ThisRGB )EndSelect
Count=RectCount
ThisRGB+=$112233EndFunction Count
function SetBox(X1,Y1,X2,Y2,Colour)if Rects(RectCount)=0
Rects(RectCount)=new tRect
endif
Rects(RectCount).x1=x1
Rects(RectCount).y1=y1
Rects(RectCount).x2=x2
Rects(RectCount).y2=y2
Rects(RectCount).Colour=Colour
RectCount++Boxc x1,y1,x2,y2,true,Colour
EndFunction