01-09-2026, 12:12 PM
Way back in the early '90s I was playing around with QuickBasic 2 - weren't we all? - I never even progressed to 4.5. At that time I created a Screen Menu Program - didn't we all? - and as part of that I spent many a happy hour creating a screen saver. This had a few variants - didn't we all do that? - one of which was "Bouncy". This was a text smiley character (ASC 2) bouncing around in a grid.
I archive it here for historical reasons. But coming back to it, I looked at the code and thought "what garbled unstructured mess". Actually that's usually my coding methodology - just see how things pan out, add bits as seem attractive. This code is obviously Screen 0 - obviously anybody with a scrap of sense (@Pete not in this Venn diagram section) wouldn't dream of using Screen 0 today, so whilst at it I produced a 32-bit graphics version.
The old code is not only messy (and gibberish in places), I couldn't fathom out parts, so started from scratch. The PE version has similar behaviour to the old but is not an exact replica. The only feature worthy of discussion is the real-time image manipulation. Really, I should have spent time re-learning _MEM object processing, but the graphics are so low-level that I cheated and just used PSET.
A point of interest is the wave propagation in the fixed cross images. A wave propagates from the top left (x,y origin) in a outward flowing circle. The wave propagation equation is: h(r,t) = A*SIN((2π/λ)*(r-v*t)) where A is the amplitude, λ is the wavelength and v is the propagation velocity.
Unzip the file and extract the folder into your PEQB64 directory. In the IDE make sure that you have the Run Option “Save EXE in source folder” checked.
Bouncy.zip (Size: 6.09 MB / Downloads: 10)
Bouncy.bas - original QB2 program
Bouncy PE.bas - Present version
The video shows the running Bouncy PE program.
Running Program Excerpt
I archive it here for historical reasons. But coming back to it, I looked at the code and thought "what garbled unstructured mess". Actually that's usually my coding methodology - just see how things pan out, add bits as seem attractive. This code is obviously Screen 0 - obviously anybody with a scrap of sense (@Pete not in this Venn diagram section) wouldn't dream of using Screen 0 today, so whilst at it I produced a 32-bit graphics version.
The old code is not only messy (and gibberish in places), I couldn't fathom out parts, so started from scratch. The PE version has similar behaviour to the old but is not an exact replica. The only feature worthy of discussion is the real-time image manipulation. Really, I should have spent time re-learning _MEM object processing, but the graphics are so low-level that I cheated and just used PSET.
A point of interest is the wave propagation in the fixed cross images. A wave propagates from the top left (x,y origin) in a outward flowing circle. The wave propagation equation is: h(r,t) = A*SIN((2π/λ)*(r-v*t)) where A is the amplitude, λ is the wavelength and v is the propagation velocity.
Unzip the file and extract the folder into your PEQB64 directory. In the IDE make sure that you have the Run Option “Save EXE in source folder” checked.
Bouncy.zip (Size: 6.09 MB / Downloads: 10)
Bouncy.bas - original QB2 program
Code: (Select All)
' Bouncy Program - Free Standing from a 1980's QB2 Screen Menu Program on an MS-DOS Desktop
COMMON SHARED true%, false%, mat%(), matb%(), noCrosses%
true% = -1: false% = 0
DIM mat%(25, 80), matb%(8, 1)
RANDOMIZE (TIMER)
phil% = true% ': noCrosses% = 0
WHILE phil% = true%: CALL bouncy(phil%, CHR$(176)): WEND
END
SUB bouncy (stot%, s$) STATIC
COLOR 8: CLS: CALL clearmat
posn% = 9 + 2 * INT(RND * 35): noise% = false%: esc% = 500 + INT(RND * 2000)
x1% = 4 + CINT(RND * 4): y1% = 10 + CINT(RND * 7): cr% = 1 + INT(RND * 6)
xstep% = 10: ystep% = 9 + CINT(RND): fcol% = 9 + INT(RND * 7): vv% = 0
cxrow% = INT(cr% / 7): x% = x1% + xstep% * cxrow% + 2: y% = y1% + 3 'cr% & cxrow% are complete jibberish
z = (x% + y%) / 2: doit% = true%: k$ = "": counton% = true%: bounce% = 0
xmove% = 1: ymove% = 1: blocky% = 0: h% = 7 + INT(RND * 6): h$ = ""
st1% = true%: stc% = 0: brick% = 12 + INT(RND * 100): gloop% = 0
IF INT(z) <> z THEN posn% = posn% + 1
FOR n% = 1 TO 25
mat%(n%, 1) = 1: mat%(n%, 80) = 1
LOCATE n%, 1: PRINT CHR$(254);
LOCATE n%, 80: PRINT CHR$(254);
NEXT n%
FOR n% = 2 TO 79
mat%(25, n%) = 1: mat%(1, n%) = 1
NEXT n%
xt$ = STRING$(78, CHR$(254))
LOCATE 25, 2: PRINT xt$;
LOCATE 1, 2: PRINT xt$;
FOR a% = 1 TO 12
xrow% = INT(a% / 7): yrow% = a% - 6 * xrow% - 1
IF a% <> h% THEN
xb% = x1% + xstep% * xrow%: yb% = y1% + ystep% * yrow%
CALL extras(xb%, yb%, 1): CALL cross(CHR$(197), xb%, yb%)
h$ = h$ + CHR$(a% + 64)
ELSE
xa% = x1% + xstep% * xrow%: ya% = y1% + ystep% * yrow%
hh$ = CHR$(a% + 64)
END IF
NEXT a%
start! = TIMER
WHILE doit% = true%
IF (RND <= 0.4 AND noCrosses% >= 2 AND blocky% = 0) THEN CALL delBlock
IF st1% = false% THEN
pp% = 1 + INT(RND * 11): h% = ASC(MID$(h$, pp%, 1)) - 64
MID$(h$, pp%) = hh$: hh$ = CHR$(h% + 64)
xrow% = INT(h% / 7): yrow% = h% - 6 * xrow% - 1
xa% = x1% + xstep% * xrow%: ya% = y1% + ystep% * yrow%
CALL extras(xa%, ya%, 0)
CALL cross(" ", xa%, ya%)
st1% = true%: stc% = 0: brick% = 12 + INT(RND * 100)
ELSEIF stc% = brick% THEN
counton% = true%
FOR i% = 2 TO 3: FOR j% = 1 TO 6
IF mat%(xa% + i% - 1, ya% + j% - 1) = 1 THEN counton% = false%
NEXT j%: NEXT i%
FOR j% = 3 TO 4: FOR i% = 1 TO 4 STEP 3
IF mat%(xa% + i% - 1, ya% + j% - 1) = 1 THEN counton% = false%
NEXT i%: NEXT j%
IF counton% = true% THEN
COLOR 8: CALL cross(CHR$(197), xa%, ya%): st1% = false%
CALL extras(xa%, ya%, 1): stc% = 0
END IF
ELSE
stc% = stc% + 1
END IF
IF bounce% <> 0 THEN
LOCATE x%, y%: PRINT " ";
mat%(x%, y%) = 0
END IF
IF mat%(x% + xmove%, y% + ymove%) = 0 THEN
'moveok% = true%
ELSEIF (x% + xmove% = 1) AND mat%(x% - xmove%, y% + ymove%) = 0 THEN
xmove% = -1 * xmove%
IF noise% = true% THEN SOUND 6000, 0.05
ELSEIF mat%(x% + xmove%, y% - ymove%) = 0 THEN
ymove% = -1 * ymove%
IF noise% = true% THEN SOUND 6000, 0.05
ELSEIF mat%(x% - xmove%, y% + ymove%) = 0 THEN
xmove% = -1 * xmove%
IF noise% = true% THEN SOUND 6000, 0.05
ELSEIF mat%(x% - xmove%, y% - ymove%) = 0 THEN
xmove% = -1 * xmove%: ymove% = -1 * ymove%
IF noise% = true% THEN SOUND 6000, 0.05
ELSE
doit% = false%: gloop% = 5
IF x% > 19 THEN x% = x% - 3
IF y% > 57 THEN y% = y% - 22
CALL byebye(x%, y%)
END IF
IF doit% = true% THEN
bounce% = bounce% + 1: blocky% = blocky% + 1
IF blocky% = 7 THEN blocky% = 0
x% = x% + xmove%: y% = y% + ymove%: mat%(x%, y%) = 1
COLOR fcol%: LOCATE x%, y%: PRINT CHR$(2);
IF (RND < 0.45 AND noCrosses% <= 7 AND blocky% = 0) THEN
vv% = vv% + 1: IF vv% = 8 THEN vv% = 1
COLOR vv%: CALL newBlock(s$)
END IF
WHILE doit% = true% AND TIMER < start! + 0.03 '52
k$ = INKEY$
IF k$ <> "" THEN
doit% = false%
IF ASC(k$) <> 0 THEN
stot% = false%
ELSEIF ASC(RIGHT$(k$, 1)) = 68 THEN
doit% = true%
IF noise% = true% THEN
noise% = false%
ELSE
noise% = true%
END IF
ELSEIF ASC(RIGHT$(k$, 1)) <> 64 THEN
stot% = false%
END IF
END IF
WEND
start! = TIMER
IF bounce% = 18000 THEN
doit% = false%
ELSEIF bounce% = esc% THEN
mat%(1, posn%) = 0: COLOR 8
LOCATE 1, posn% - 7: PRINT "ESCAPE" + CHR$(26) + " ";
END IF
IF x% = 1 THEN
IF y% > 59 THEN y% = 59
doit% = false%: gloop% = 3
CALL byebye(2, y%)
END IF
END IF
WEND
mat%(x%, y%) = 0
FOR a% = 1 TO 12
xrow% = INT(a% / 7): yrow% = a% - 6 * xrow% - 1
xb% = x1% + xstep% * xrow%: yb% = y1% + ystep% * yrow%
CALL extras(xb%, yb%, 0)
NEXT a%
WHILE (TIMER < start! + 2 + gloop%) AND stot% = true%
k$ = INKEY$: IF k$ <> "" THEN stot% = false%
WEND
COLOR 7, 0: CLS: CALL clearmat
END SUB
SUB byebye (topRow%, leftCol%) STATIC
COLOR 23
l1$ = CHR$(201) + STRING$(18, 205) + CHR$(187)
l2$ = CHR$(186) + " Bye-bye !! " + CHR$(186)
l3$ = CHR$(200) + STRING$(18, 205) + CHR$(188)
LOCATE topRow%, leftCol%: PRINT l1$;
LOCATE topRow% + 1, leftCol%: PRINT l2$;
LOCATE topRow% + 2, leftCol%: PRINT l3$;
'FOR n% = 1 TO 2: BEEP: NEXT n%
END SUB
SUB extras (n%, m%, apollo%) STATIC
FOR i% = n% + 1 TO n% + 2
FOR b% = m% TO m% + 5
mat%(i%, b%) = apollo%
NEXT b%
NEXT i%
FOR j% = m% + 2 TO m% + 3
mat%(n%, j%) = apollo%: mat%(n% + 3, j%) = apollo%
NEXT j%
END SUB
SUB clearmat STATIC
noCrosses% = 0
FOR a% = 1 TO 8: CALL matwrite(a%, 0): NEXT a%
END SUB
SUB matwrite (n%, zeus%) STATIC
FOR i% = matb%(n%, 0) + 1 TO matb%(n%, 0) + 2
FOR b% = matb%(n%, 1) TO matb%(n%, 1) + 5
mat%(i%, b%) = zeus%
NEXT b%
NEXT i%
FOR j% = matb%(n%, 1) + 2 TO matb%(n%, 1) + 3
mat%(matb%(n%, 0), j%) = zeus%: mat%(matb%(n%, 0) + 3, j%) = zeus%
NEXT j%
END SUB
SUB newBlock (ss$) STATIC
x0% = 2 + INT(20 * RND): y0% = 2 + INT(73 * RND)
touch% = true% 'check if overlap on existing cross
WHILE touch% = true%
touch% = false%
FOR i% = 2 TO 3: FOR j% = 1 TO 6 'STEP 5
IF mat%(x0% + i% - 1, y0% + j% - 1) = 1 THEN touch% = true%
NEXT j%: NEXT i%
FOR j% = 3 TO 4: FOR i% = 1 TO 4 STEP 3
IF mat%(x0% + i% - 1, y0% + j% - 1) = 1 THEN touch% = true%
NEXT i%: NEXT j%
IF touch% = true% THEN
x0% = 2 + INT(20 * RND): y0% = 2 + INT(73 * RND)
END IF
WEND
CALL cross(ss$, x0%, y0%)
noCrosses% = noCrosses% + 1
matb%(noCrosses%, 1) = y0%: matb%(noCrosses%, 0) = x0%
CALL matwrite(noCrosses%, 1)
END SUB
SUB delBlock STATIC
CALL cross(" ", matb%(1, 0), matb%(1, 1))
noCrosses% = noCrosses% - 1: CALL matwrite(1, 0)
IF noCrosses% >= 1 THEN
FOR n% = 1 TO noCrosses%
matb%(n%, 1) = matb%(n% + 1, 1): matb%(n%, 0) = matb%(n% + 1, 0)
NEXT n%
END IF
END SUB
SUB cross (s$, i%, j%) STATIC
LOCATE i%, j% + 2: PRINT STRING$(2, s$);: LOCATE i% + 1, j%: PRINT STRING$(6, s$);
LOCATE i% + 2, j%: PRINT STRING$(6, s$);: LOCATE i% + 3, j% + 2: PRINT STRING$(2, s$);
END SUB
Bouncy PE.bas - Present version
Code: (Select All)
' Bouncy Program :- 32-bit screen version by Magdha 2026-01-08
' Adapted from QB2 version with different bounce and timing conditions
' At least this code should be easier to understand
' X- horizontal, Y- Vertical (downwards), (0,0) top left
CONST False = 0, True = NOT False
CONST Lambda! = 20, PropVelocity! = 0.09, Amplitude%% = 80
DIM Mat%%(80, 25), MatCross%%(6, 4), MatCrosses%%(22, 1), Velocities%%(4, 1), FreeCrossImages&(10, 1)
_TITLE "Bouncy PE"
RANDOMIZE (TIMER)
RESTORE ReadData
'Define the structure of the crosses
FOR J%% = 1 TO 4
FOR I%% = 1 TO 6
READ Dum%%
IF Dum%% <> 0 THEN MatCross%%(I%%, J%%) = True
NEXT I%%
NEXT J%%
'Define the velocity vector (vx & vy)
FOR N%% = 1 TO 4
READ Velocities%%(N%%, 0)
READ Velocities%%(N%%, 1)
NEXT N%%
'Initial Conditons
DoBounce%% = True
EscapePosition%% = 9 + 2 * INT(RND * 35)
EscapeCount% = 0
CanEscape%% = False
IsTrapped%% = False
DoNoises%% = False '!!! TBF
EscapeTime% = 9000 + INT(RND * 5000)
WaveCount% = 0
SayByeByeSooty%% = False
k$ = ""
Vector%% = 1 'Movement of Bouncy
FixedCross%% = 0
BCount%% = 0
FCount%% = 0
NoFreeCrosses%% = 0
Y1%% = 4 + CINT(RND * 4) 'Static crosses
X1%% = 10 + CINT(RND * 7)
Ystep%% = 10
Xstep%% = 9 + CINT(RND)
FOR N%% = 11 TO 16
MatCrosses%%(N%%, 0) = X1%% + (N%% - 11) * Xstep%%
MatCrosses%%(N%%, 1) = Y1%%
NEXT N%%
FOR N%% = 17 TO 22
MatCrosses%%(N%%, 0) = X1%% + (N%% - 17) * Xstep%%
MatCrosses%%(N%%, 1) = Y1%% + Ystep%%
NEXT N%%
BounceY%% = Y1%% + 3 + Ystep%% * INT(RND * 2)
BounceX%% = X1%% + 4 + Xstep%% * INT(RND * 6)
PosnX% = 12 * BounceX%%
PosnY% = 21 * BounceY%%
'Define Initial Bouncy Position Occupied
Mat%%(BounceX%%, BounceY%%) = True
'Define Border Cells Occupied
FOR J%% = 0 TO 25
Mat%%(0, J%%) = True
Mat%%(79, J%%) = True
NEXT J%%
FOR I%% = 0 TO 80
Mat%%(I%%, 24) = True
Mat%%(I%%, 0) = True
NEXT I%%
'Add Fixed Crosses to grid
FOR N%% = 11 TO 22
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF MatCross%%(I%%, J%%) THEN Mat%%(MatCrosses%%(N%%, 0) + I%% - 1, MatCrosses%%(N%%, 1) + J%% - 1) = True
NEXT J%%
NEXT I%%
NEXT N%%
'Images - All Hardware
TempImage& = _NEWIMAGE(72, 84, 32)
_DEST TempImage&
LINE (24, 0)-(48, 83), _RGB32(255, 0, 0), BF
LINE (0, 21)-(71, 62), _RGB32(255, 0, 0), BF
FixedCrossImage& = MakeHardware&(TempImage&)
TempImage& = _LOADIMAGE("Smiley2.jpg", 32)
TempImage1& = _NEWIMAGE(12, 21, 32)
_DEST TempImage1&
_PUTIMAGE , TempImage&
Smiley& = MakeHardware&(TempImage1&)
_FREEIMAGE TempImage&
TempImage& = _NEWIMAGE(500, 400, 32)
_DEST TempImage&
_FONT _LOADFONT("cyberbit.ttf", 60, "BOLD")
COLOR _RGB32(255, 255, 255), _RGB32(0, 0, 150)
CLS
LINE (0, 0)-(499, 399), _RGB32(255, 215, 0), B
LINE (1, 1)-(498, 398), _RGB32(255, 215, 0), B
LINE (3, 3)-(496, 396), _RGB32(255, 215, 0), B
LINE (4, 4)-(495, 395), _RGB32(255, 215, 0), B
_PRINTSTRING (100, 100), "Bouncy Says"
_PRINTSTRING (100, 200), " Bye-bye"
Cheerio& = MakeHardware&(TempImage&)
TempImage& = _NEWIMAGE(960, 525, 32)
_DEST TempImage&
COLOR _RGB32(192, 192, 220), _RGB32(0, 65, 0)
CLS
'LINE (12, 0)-(947, 20), , BF
LINE (0, 504)-(959, 524), , BF
LINE (0, 0)-(11, 524), , BF
LINE (948, 0)-(959, 524), , BF
Background& = MakeHardware&(TempImage&)
TempImage& = _NEWIMAGE(936, 21, 32)
_DEST TempImage&
COLOR _RGB32(192, 192, 220), _RGB32(0, 65, 0)
CLS
LINE (0, 0)-(935, 20), , BF
TopLine& = MakeHardware&(TempImage&)
TempImage& = _NEWIMAGE(936, 21, 32)
_DEST TempImage&
COLOR _RGB32(255, 255, 255), _RGBA32(0, 0, 0, 0)
_PRINTSTRING (435, 3), CHR$(27) + " Escape " + CHR$(26)
FOR H% = 3 TO 18 STEP 5
FOR G% = 5 TO 430 STEP 5
PSET (G%, H%)
NEXT G%
FOR G% = 519 TO 929 STEP 5
PSET (G%, H%)
NEXT G%
NEXT H%
EscapeLine& = MakeHardware&(TempImage&)
'Screen (hardware images only)
SCREEN _NEWIMAGE(960, 525, 32)
_DEST 0
_DISPLAYORDER _HARDWARE ', _SOFTWARE
_SCREENMOVE 50, 70
AtStart! = TIMER
WHILE DoBounce%%
_LIMIT 60
'Display Images
'Background
_PUTIMAGE (0, 0), Background&
'Fixed Crosses
FOR N%% = 11 TO 22
IF N%% <> FixedCross%% THEN
_FREEIMAGE FixedCrossImage&
TempImage& = _NEWIMAGE(72, 84, 32)
_DEST TempImage&
FOR I%% = 0 TO 71
FOR J%% = 0 TO 83
IF (I%% >= 24 AND I%% <= 48 AND J%% >= 0 AND J%% <= 83) OR (I%% >= 0 AND I%% <= 71 AND J%% >= 21 AND J%% <= 62) THEN
Xcross% = MatCrosses%%(N%%, 0) * 12 + I%%
YCross% = MatCrosses%%(N%%, 1) * 21 + J%%
Rad! = SQR(Xcross% * Xcross% + YCross% * YCross%)
WaveHeight~%% = CINT(Amplitude%% * SIN((2 * _PI / Lambda!) * (Rad! - PropVelocity! * WaveCount%))) + 1.5 * Amplitude%% 'Always positive
COLOR _RGB32(WaveHeight~%%, 0.5 * WaveHeight~%%, 0.5 * WaveHeight~%%)
PSET (I%%, J%%)
END IF
NEXT J%%
NEXT I%%
FixedCrossImage& = MakeHardware&(TempImage&)
_PUTIMAGE (MatCrosses%%(N%%, 0) * 12, MatCrosses%%(N%%, 1) * 21), FixedCrossImage&
END IF
NEXT N%%
'Free Crosses
IF NoFreeCrosses%% > 0 THEN
FOR N%% = 1 TO NoFreeCrosses%%
_PUTIMAGE (MatCrosses%%(N%%, 0) * 12, MatCrosses%%(N%%, 1) * 21), FreeCrossImages&(N%%, 1)
NEXT N%%
END IF
'Escape Label
IF CanEscape%% THEN
_PUTIMAGE (12, 0), EscapeLine&
ELSE
_PUTIMAGE (12, 0), TopLine&
END IF
'Bouncy
_PUTIMAGE (PosnX%, PosnY%), Smiley&
'Completion Banner
IF SayByeByeSooty%% THEN
ToEnd% = ToEnd% + 1
_PUTIMAGE (230, 62), Cheerio&
IF ToEnd% = 300 THEN DoBounce%% = False
END IF
_DISPLAY
'Timings Counts
'Wave Propagation and Time Limit
WaveCount% = WaveCount% + 1
IF WaveCount% = 16000 THEN SayByeByeSooty%% = True
'The Speed which Bouncy moves
BCount%% = BCount%% + 1
IF BCount%% = 8 THEN BCount%% = 0
'Count to when Bouncy can escape at the top
IF NOT CanEscape%% THEN
EscapeCount% = EscapeCount% + 1
IF EscapeCount% = EscapeTime% THEN
FOR N%% = 1 TO 36
Mat%%(N%%, 0) = False
NEXT N%%
FOR N%% = 44 TO 78
Mat%%(N%%, 0) = False
NEXT N%%
CanEscape%% = True
END IF
END IF
IF BounceY%% = 0 THEN
'Bouncy Escapes and then program will terminate after a pause
SayByeByeSooty%% = True
ELSE
'Crosses Positions, Bouncy Position & Movement
IF BCount%% = 0 THEN
'Find if Bouncy can move and in which direction
IF IsTrapped%% THEN
'If Bouncy is trapped, wait until a path is clear
Vector%% = 1
WHILE Vector%% <= 4 AND IsTrapped%%
IF NOT Mat%%(BounceX%% + Velocities%%(Vector%%, 0), BounceY%% + Velocities%%(Vector%%, 1)) THEN
IsTrapped%% = False
Mat%%(BounceX%%, BounceY%%) = False
BounceX%% = BounceX%% + Velocities%%(Vector%%, 0)
BounceY%% = BounceY%% + Velocities%%(Vector%%, 1)
PosnX% = 12 * BounceX%%
PosnY% = 21 * BounceY%%
Mat%%(BounceX%%, BounceY%%) = True
ELSE
Vector%% = Vector%% + 1
END IF
WEND
ELSE
'Look for possible movements
PossMoves%% = 0
FOR N%% = 4 TO 1 STEP -1
IF NOT Mat%%(BounceX%% + Velocities%%(N%%, 0), BounceY%% + Velocities%%(N%%, 1)) THEN
PossMoves%% = PossMoves%% + 1
PossVector%% = N%%
END IF
NEXT N%%
IF NOT Mat%%(BounceX%% + Velocities%%(Vector%%, 0), BounceY%% + Velocities%%(Vector%%, 1)) THEN
'Nothing in the way - Just Carry On
PossMoves%% = 4 'Just a marker
ELSEIF PossMoves%% = 0 THEN
'Can't move
IsTrapped%% = True
Vector%% = 0
ELSEIF PossMoves%% = 1 THEN
'Only 1 possible move
Vector%% = PossVector%%
ELSE
'2 or 3 possible moves
'Look for reflection backwards and reflection bounce
IF NOT Mat%%(BounceX%% - Velocities%%(Vector%%, 0), BounceY%% - Velocities%%(Vector%%, 1)) AND NOT Mat%%(BounceX%%, BounceY%% + Velocities%%(Vector%%, 1)) AND NOT Mat%%(BounceX%% + Velocities%%(Vector%%, 0), BounceY%%) THEN
'Reflect backwards
Vector%% = Vector%% + 2
IF Vector%% > 4 THEN Vector%% = Vector%% - 4
ELSEIF Mat%%(BounceX%% + Velocities%%(Vector%%, 0), BounceY%%) AND NOT Mat%%(BounceX%% - Velocities%%(Vector%%, 0), BounceY%% + Velocities%%(Vector%%, 1)) THEN
'Reflect off solid (bounce)
SELECT CASE Vector%%
CASE 1
Vector%% = 2
CASE 2
Vector%% = 1
CASE 3
Vector%% = 4
CASE 4
Vector%% = 3
END SELECT
ELSEIF Mat%%(BounceX%%, BounceY%% + Velocities%%(Vector%%, 1)) AND NOT Mat%%(BounceX%% + Velocities%%(Vector%%, 0), BounceY%% - Velocities%%(Vector%%, 1)) THEN
'Reflect off solid (bounce)
SELECT CASE Vector%%
CASE 1
Vector%% = 4
CASE 2
Vector%% = 3
CASE 3
Vector%% = 2
CASE 4
Vector%% = 1
END SELECT
ELSE
Vector%% = PossVector%%
END IF
END IF
IF PossMoves%% > 0 THEN
'Bouncy Can Move
Mat%%(BounceX%%, BounceY%%) = False
BounceX%% = BounceX%% + Velocities%%(Vector%%, 0)
BounceY%% = BounceY%% + Velocities%%(Vector%%, 1)
PosnX% = 12 * BounceX%%
PosnY% = 21 * BounceY%%
Mat%%(BounceX%%, BounceY%%) = True
'After Bouncy has moved deal with the Fixed Crosses
'Create/Remove Fixed Cross
IF FixedCross%% = 0 THEN
IF RND > 0.9 THEN
'Remove a fixed cross
FixedCross%% = 11 + INT(12 * RND)
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF MatCross%%(I%%, J%%) THEN Mat%%(MatCrosses%%(FixedCross%%, 0) + I%% - 1, MatCrosses%%(FixedCross%%, 1) + J%% - 1) = False
NEXT J%%
NEXT I%%
END IF
ELSE
IF RND > 0.9 THEN
'Fill fixed cross space
'Have to check if occupied
CanReplace%% = True
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF Mat%%(MatCrosses%%(FixedCross%%, 0) + I%% - 1, MatCrosses%%(FixedCross%%, 1) + J%% - 1) THEN CanReplace%% = False
NEXT J%%
NEXT I%%
IF CanReplace%% THEN
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF MatCross%%(I%%, J%%) THEN Mat%%(MatCrosses%%(FixedCross%%, 0) + I%% - 1, MatCrosses%%(FixedCross%%, 1) + J%% - 1) = True
NEXT J%%
NEXT I%%
FixedCross%% = 0
END IF
END IF
END IF
END IF
END IF
'The Free Crosses
FCount%% = FCount%% + 1
IF FCount%% = 4 THEN
FCount%% = 0
'Create/Delete Free Cross
IF (RND <= 0.4 AND NoFreeCrosses%% >= 4) THEN
'Delete an existing Free Cross
'Remove from grid:
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF MatCross%%(I%%, J%%) THEN Mat%%(MatCrosses%%(1, 0) + I%% - 1, MatCrosses%%(1, 1) + J%% - 1) = False
NEXT J%%
NEXT I%%
'Change down & remove crosses
FOR N%% = 2 TO NoFreeCrosses%%
MatCrosses%%(N%% - 1, 0) = MatCrosses%%(N%%, 0)
MatCrosses%%(N%% - 1, 1) = MatCrosses%%(N%%, 1)
_FREEIMAGE (FreeCrossImages&(N%% - 1, 1))
FreeCrossImages&(N%% - 1, 1) = _COPYIMAGE(FreeCrossImages&(N%%, 0), 33)
NEXT N%%
_FREEIMAGE (FreeCrossImages&(NoFreeCrosses%%, 1))
_FREEIMAGE (FreeCrossImages&(NoFreeCrosses%%, 0))
NoFreeCrosses%% = NoFreeCrosses%% - 1
ELSEIF (RND < 0.45 AND NoFreeCrosses%% <= 9) OR NoFreeCrosses%% <= 3 THEN
'Create a Free Cross
'Find a position where the grid is not occupied
NoFreeCrosses%% = NoFreeCrosses%% + 1
CanCreate%% = False
WHILE NOT CanCreate%%
MatCrosses%%(NoFreeCrosses%%, 0) = 1 + INT(RND * 73)
MatCrosses%%(NoFreeCrosses%%, 1) = 1 + INT(RND * 20)
CanCreate%% = True
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF Mat%%(MatCrosses%%(NoFreeCrosses%%, 0) + I%% - 1, MatCrosses%%(NoFreeCrosses%%, 1) + J%% - 1) THEN CanCreate%% = False
NEXT J%%
NEXT I%%
WEND
'Add to grid
FOR I%% = 1 TO 6
FOR J%% = 1 TO 4
IF MatCross%%(I%%, J%%) THEN Mat%%(MatCrosses%%(NoFreeCrosses%%, 0) + I%% - 1, MatCrosses%%(NoFreeCrosses%%, 1) + J%% - 1) = True
NEXT J%%
NEXT I%%
'Create new image & convert to hardware for display
'Running image manipulations are done in software
FreeCrossImages&(NoFreeCrosses%%, 0) = _NEWIMAGE(72, 84, 32)
_DEST FreeCrossImages&(NoFreeCrosses%%, 0)
Red~%% = INT(RND * 150)
Green~%% = 70 + INT(RND * 186)
Blue~%% = 100 + INT(RND * 156)
LINE (24, 0)-(48, 83), _RGB32(Red~%%, Green~%%, Blue~%%), BF
LINE (0, 21)-(71, 62), _RGB32(Red~%%, Green~%%, Blue~%%), BF
COLOR _RGB32(75, 0, 0), _RGB32(Red~%%, Green~%%, Blue~%%)
_PRINTSTRING (22, 28), "QB64"
_PRINTSTRING (30, 44), "PE"
FreeCrossImages&(NoFreeCrosses%%, 1) = _COPYIMAGE(FreeCrossImages&(NoFreeCrosses%%, 0), 33)
END IF
END IF
END IF
END IF
'Keyboard Input - Esc to Quit
k$ = INKEY$
IF k$ <> "" THEN
IF ASC(k$) = 27 THEN SayByeByeSooty%% = True 'DoBounce%% = False
END IF
k$ = ""
WEND
SYSTEM
ReadData:
DATA 0,0,1,1,0,0
DATA 1,1,1,1,1,1
DATA 1,1,1,1,1,1
DATA 0,0,1,1,0,0
DATA 1,1,-1,1,-1,-1,1,-1
FUNCTION MakeHardware& (Imagename&)
MakeHardware& = _COPYIMAGE(Imagename&, 33)
_FREEIMAGE Imagename&
END FUNCTION
The video shows the running Bouncy PE program.
Running Program Excerpt

