_TITLE "b+ Asteroids m2" 'started 2018-07-13" ' 2020-10-27 remove the alternate subs and get down below 200 LOC almost there now! new shooter action font and background
' 2020-10-28 another makeover explosions and split asteroids
' 2020-10-29 fix baby rock management, break between lives
CONST xmax
= 1200, ymax
= 700, pi
= _PI, polyAngle
= _PI / 6, nRocks
= 100, nBullets
= 1000, bSpeed
= 30
ra
AS SINGLE 'rotation angle a = a + spin heading
AS SINGLE 'heading from which dx, dy are calc with speed hit
AS LONG 'TF or count before or after hit not sure I need this from explosions live
AS LONG 'need this to track rocks still active like bullets
DIM SHARED lives&
, rocks&
' rocks is the minimum number of parent rocks to have on screen automatic replace when hit or out of bounds, always live
fnt&
= _LOADFONT("ARLRDBD.ttf", 12, "MONOSPACE")COLOR &HFF00FFFF, &H00000000 rocks& = 6 ' always active rocks
lives& = 100
FOR i
= 1 TO nRocks
'reset rocks mainly clear baby rocks newRock (i)
IF i
> rocks&
THEN r
(i
).live
= 0 ship.x = xmax / 2 'avoids explosions top left corner at start
ship.y = ymax / 2
ship.live = 1
'draw everything then process bullets
S$
= "Lives:" + STR$(lives&
) + " Hits:" + STR$(Hits&
) + " Bullets:" + STR$(bullets
) + " Shooting:" + STR$(INT(Hits&
* 100 / bullets
)) + "%" IF r
(i
).live
THEN drawRock
(i
) ' while drawing rocks the ship could be blown up drawship
IF lastx
<> ship.x
OR lasty
<> ship.y
THEN lastx = ship.x: lasty = ship.y
fire = 0
IF lastt
= 0 OR t
- lastt
> .2 THEN fire
= 1: lastt
= t: bullets
= bullets
+ 1
FOR i
= 0 TO nBullets
'handle bullets IF b
(i
).live
= 0 AND fire
= 1 THEN 'have inactive bullet to use b
(i
).x
= ship.x
+ bSpeed
* COS(ship.a
) b
(i
).y
= ship.y
+ bSpeed
* SIN(ship.a
) b
(i
).dx
= bSpeed
* COS(ship.a
) b
(i
).dy
= bSpeed
* SIN(ship.a
) b(i).live = -1
fire = 0
IF b
(i
).live
THEN 'new location b(i).x = b(i).x + b(i).dx
b(i).y = b(i).y + b(i).dy
IF b
(i
).x
> 0 AND b
(i
).x
< xmax
AND b
(i
).y
> 0 AND b
(i
).y
< ymax
THEN 'in bounds draw it FOR r
= 1 TO nRocks
'check for collision with rock IF SQR((r
(r
).x
- b
(i
).x
) ^ 2 + (r
(r
).y
- b
(i
).y
) ^ 2) < r
(r
).r
THEN 'its a hit! explode r(r).x, r(r).y, r(r).r, r(r).r - r(r).hit
Hits& = Hits& + 1
' for reference
'x AS LONG
'y AS LONG
'r AS LONG 'radius
'ra AS SINGLE 'rotation angle a = a + spin
'heading AS SINGLE 'heading from which dx, dy are calc with speed
'speed AS SINGLE 'speed
'spin AS SINGLE
'seed AS LONG
'c AS INTEGER 'color rgb(grey)
'hit AS LONG 'TF or count before or after hit not sure I need this from explosions
'live AS INTEGER 'need this to track rocks still active like bullets
IF r
(r
).r
> 30 THEN ' split rock ' new rock
newRockN = freeRock& ' get inactive rock number
newRock newRockN ' new identity and activate
'_PRINTSTRING (xmax / 2, ymax / 4), "NewRock " + STR$(newRockN)
'_DISPLAY
r(newRockN).r = (r(r).r - 10) / 2 ' split in half minus 20% mass
r(newRockN).x = r(r).x + irnd&(-10, 10) ' thrown from parent
r(newRockN).y = r(r).y + irnd&(-10, 10)
r(newRockN).c = r(r).c ' same color as parent
r(newRockN).heading = rrnd(ship.a, ship.a + pi / 2)
'r(newRockN).live = 1
' remainder of rock carries on smaller and changed
r(r).r = (r(r).r - 10) / 2 ' split in half minus 20% mass
r(r).x = r(r).x + irnd&(-5, 5) ' thrown a bit
r(r).y = r(r).y + irnd&(-5, 5)
r(r).heading = rrnd(ship.a, ship.a - pi / 2)
r
(r
).ra
= RND * 2 * pi
' twisted r(r).speed = rrnd(3, 7) ' different
r(r).spin = rrnd(-pi / 10, pi / 10) 'different
'r(r).live = 1
ELSE ' not big enough to split END IF ' big enough to split b(i).live = 0 'kill bullet
IF b
(i
).live
THEN fcirc b
(i
).x
, b
(i
).y
, 3, _RGB32(255, 255, 0) 'draws bullet b(i).live = 0 'out of bounds
END IF ' bullet is in bounds END IF ' if ship still live IF ship.live
= 0 THEN SLEEP ELSE _LIMIT 30 ' if ship dies let's rest and regroup before restart next life lives& = lives& - 1
FOR i&
= rocks&
+ 1 TO nRocks
' look for inactive rock number BEEP 'when we can't find a free rock
SUB explode
(x
, y
, r
, frm
) maxParticles = r * 10
NewDot i, x, y, r
rounds = r
dots(i).x = dots(i).x + dots(i).dx
dots(i).y = dots(i).y + dots(i).dy
dots(i).dx = dots(i).dx * .9
dots(i).dy = dots(i).dy * .9
fcirc dots(i).x, dots(i).y, dots(i).size / 2, dots(i).kolor
NewDot (rounds + i), x, y, r
rounds = rounds + r
dots
(i
).x
= x
+ rd
* COS(angle
) dots
(i
).y
= y
+ rd
* SIN(angle
) dots
(i
).size
= RND * r
* .1 rd
= RND 'STxAxTIC recommended for rounder spreads dots
(i
).dx
= rd
* 7 * (7 - dots
(i
).size
) * COS(angle
) dots
(i
).dy
= rd
* 7 * (7 - dots
(i
).size
) * SIN(angle
) dots
(i
).kolor
= _RGBA32(rd
, rd
, rd
, 40)
SUB drawship
'simple red iso triangle pointed towards radianAngle 'calculate 3 tail points of triangle ship
x1
= ship.x
+ 40 * COS(ship.a
- pi
) ' middle y1
= ship.y
+ 40 * SIN(ship.a
- pi
) ' x2
= ship.x
+ 60 * COS(ship.a
+ .9 * pi
) ' wing y2
= ship.y
+ 60 * SIN(ship.a
+ .9 * pi
) x3
= ship.x
+ 60 * COS(ship.a
- .9 * pi
) ' other wing y3
= ship.y
+ 60 * SIN(ship.a
- .9 * pi
) ftri ship.x
, ship.y
, x1
, y1
, x2
, y2
, _RGB32(80, 120, 80, 80) ftri ship.x
, ship.y
, x1
, y1
, x3
, y3
, _RGB32(60, 100, 60, 80) LINE (ship.x
, ship.y
)-(x1
, y1
), _RGB32(255, 255, 128) LINE (ship.x
, ship.y
)-(x2
, y2
), _RGB32(180, 180, 120) LINE (ship.x
, ship.y
)-(x3
, y3
), _RGB32(180, 180, 120)
' for reference
'x AS LONG
'y AS LONG
'r AS LONG 'radius
'ra AS SINGLE 'rotation angle a = a + spin
'heading AS SINGLE 'heading from which dx, dy are calc with speed
'speed AS SINGLE 'speed
'spin AS SINGLE
'seed AS LONG
'c AS INTEGER 'color rgb(grey)
'hit AS LONG 'TF or count before or after hit not sure I need this from explosions
'live AS INTEGER 'need this to track rocks still active like bullets
RANDOMIZE USING r
(iRock
).seed
'this prevents having to save a particular sequence of random numbers dx
= r
(iRock
).speed
* COS(r
(iRock
).heading
) dy
= r
(iRock
).speed
* SIN(r
(iRock
).heading
) 'update location r(iRock).ra = r(iRock).ra + r(iRock).spin
IF r
(iRock
).x
+ dx
+ r
(iRock
).r
< 0 OR r
(iRock
).x
+ dx
- r
(iRock
).r
> xmax
OR r
(iRock
).y
+ dy
+ r
(iRock
).r
< 0 OR r
(iRock
).y
+ yx
- r
(iRock
).r
> ymax
THEN IF iRock
<= rocks&
THEN newRock iRock
ELSE r
(iRock
).live
= 0 EXIT SUB ' ressigned get out of here r(iRock).x = r(iRock).x + dx
r(iRock).y = r(iRock).y + dy
IF ((r
(iRock
).x
- ship.x
) ^ 2 + (r
(iRock
).y
- ship.y
) ^ 2) ^ .5 < r
(iRock
).r
+ 30 THEN 'rock collides with ship? fcirc ship.x
, ship.y
, rad
, _RGB32(255 - rad
, 255 - 2 * rad
, 0) lives& = lives& - 1
IF iRock
<= rocks&
THEN newRock iRock
ELSE r
(iRock
).live
= 0 FOR j
= 10 TO 3 STEP -1 ' rock drawing (see demo program where developed code) rRad = .1 * j * r(iRock).r
leg
= rRad
* (RND * .7 + .3) x0
= r
(iRock
).x
+ leg
* COS(r
(iRock
).ra
) y0
= r
(iRock
).y
+ leg
* SIN(r
(iRock
).ra
) rc
= r
(iRock
).c
+ 30 * RND - 15 c&
= _RGB32(rc
+ 5, rc
- 10, rc
+ 5) x1 = x0
y1 = y0
xoff
= RND * 20 - 10 + r
(iRock
).x
yoff
= RND * 20 - 10 + r
(iRock
).y
leg
= rRad
* (RND * .35 + .65) x2 = x0: y2 = y0
x2
= xoff
+ leg
* COS(i
* polyAngle
+ r
(iRock
).ra
) y2
= yoff
+ leg
* SIN(i
* polyAngle
+ r
(iRock
).ra
) ftri r(iRock).x, r(iRock).y, x1, y1, x2, y2, c&
x1 = x2: y1 = y2
' for reference
'x AS LONG
'y AS LONG
'r AS LONG 'radius
'ra AS SINGLE 'rotation angle a = a + spin
'heading AS SINGLE 'heading from which dx, dy are calc with speed
'speed AS SINGLE 'speed
'spin AS SINGLE
'seed AS LONG
'c AS INTEGER 'color rgb(grey)
'hit AS LONG 'TF or count before or after hit not sure I need this from explosions
'live AS INTEGER 'need this to track rocks still active like bullets
side = irnd&(1, 4) 'bring rock in from one side, need to set heading according to side
r(iRock).x = -10
r(iRock).y = rrnd(20, ymax - 20)
r
(iRock
).heading
= 3 * pi
/ 2 + RND * pi
r(iRock).x = xmax + 10
r(iRock).y = rrnd(20, ymax - 20)
r
(iRock
).heading
= pi
/ 2 + RND * pi
r(iRock).x = rrnd(20, xmax - 20)
r(iRock).y = -10
r
(iRock
).heading
= RND * pi
r(iRock).x = rrnd(20, xmax - 20)
r(iRock).y = ymax + 10
r
(iRock
).heading
= pi
+ RND * pi
r(iRock).speed = rrnd(3, 7) 'speed, rotation angle, radius, gray coloring, spin, seed, hit for explosion
r
(iRock
).ra
= RND * 2 * pi
r(iRock).r = irnd&(30, 100)
r(iRock).c = irnd&(10, 60)
r(iRock).spin = rrnd(-pi / 10, pi / 10)
r
(iRock
).seed
= INT(RND * 64000) - 32000 r(iRock).hit = 0
r(iRock).live = 1
FUNCTION irnd&
(n1
, n2
) 'return an integer between 2 numbers IF n1
> n2
THEN l%
= n2: h%
= n1
ELSE l%
= n1: h%
= n2
irnd&
= INT(RND * (h%
- l%
+ 1)) + l%
FUNCTION rrnd
(n1
, n2
) 'return real number (_single, double, _float depending on default / define setup) rrnd
= (n2
- n1
) * RND + n1
_BLEND a&
'<<<< new 2019-12-16 fix
x0 = R: y0 = 0: e = 0
y0 = y0 + 1
LINE (x
- x0
, y
+ y0
)-(x
+ x0
, y
+ y0
), C
, BF
LINE (x
- x0
, y
- y0
)-(x
+ x0
, y
- y0
), C
, BF
e = e + 2 * y0
LINE (x
- y0
, y
- x0
)-(x
+ y0
, y
- x0
), C
, BF
LINE (x
- y0
, y
+ x0
)-(x
+ y0
, y
+ x0
), C
, BF
x0 = x0 - 1: e = e - 2 * x0
LINE (x
- R
, y
)-(x
+ R
, y
), C
, BF