set display mode 1280, 1024, 32
sync on
sync rate 0
randomize timer()
backdrop on
color backdrop 0
 
 
type psuedoPoint
   x#
   y#
endtype
 
type psuedoLine
   p as psuedoPoint
endtype
 
type Asteroid
   x#
   y#
   speedX#
   speedY#
   rotSpeed#
   angle#
 
   cX#
   cY#
 
   imgId
   size
   radiusSquared
endtype
 
 
 
 
#constant ASTEROID_POINTS 12
#constant ASTEROID_COUNT 6
#constant ASTEROID_MIN_RADIUS_FACTOR 0.40
#constant ASTEROID_MAX_RADIUS_FACTOR 0.99
 
Dim Asteroids(ASTEROID_COUNT) as Asteroid
 
`Lines
Dim psuedoLineArray(ASTEROID_COUNT, ASTEROID_POINTS) as psuedoLine
 
 
`Make 'ASTEROID_COUNT' asteroids
for j = 1 to ASTEROID_COUNT
   `Asteroid size (width and height)
   ASTEROID_SIZE = 128 + rnd(128)
 
   `Make a colour
   col as dword
 
   select rnd(7)
      case 0 : col = rgb(255, 128, 128) : endcase
      case 1 : col = rgb(128, 255, 128) : endcase
      case 2 : col = rgb(128, 128, 255) : endcase
      case 3 : col = rgb(255, 255, 128) : endcase
      case 4 : col = rgb(255, 128, 255) : endcase
      case 5 : col = rgb(128, 255, 255) : endcase
      case 6 : col = rgb(255, 255, 255) : endcase
      case 7 : col = rgb(128, 128, 128) : endcase
   endselect
   inc col,(128 << 24) && 0xFFFFFFFF
 
 
   for i = 0 to ASTEROID_POINTS
      if i < ASTEROID_POINTS
         `Get the angle
         angle# = 360.0 * i / (ASTEROID_POINTS * 1.0)
 
         `Distance is currently 95% of the radius (distance from edge to middle) - this SHOULD make a "circle"
         dist# = (ASTEROID_SIZE * ASTEROID_MIN_RADIUS_FACTOR)   +   (rnd(ASTEROID_SIZE * 100.0 * (ASTEROID_MAX_RADIUS_FACTOR - ASTEROID_MIN_RADIUS_FACTOR)) * 0.01)
         dist# = dist# * 0.5
 
         `Create a point based on the current angle, above distance. This is from the origin; 0,0
         psuedoLineArray(j, i).p.x# = (cos(angle#) * dist#) `+ cP#
         psuedoLineArray(j, i).p.y# = (sin(angle#) * dist#) `+ cP#
      else
         psuedoLineArray(j, ASTEROID_POINTS).p.x# = psuedoLineArray(j, 0).p.x#
         psuedoLineArray(j, ASTEROID_POINTS).p.y# = psuedoLineArray(j, 0).p.y#
      endif
   next i
 
   Asteroids(j).cX# = ASTEROID_SIZE * 0.5
   Asteroids(j).cY# = ASTEROID_SIZE * 0.5
   Asteroids(j).size = ASTEROID_SIZE
   Asteroids(j).radiusSquared = (ASTEROID_SIZE * 0.5) * (ASTEROID_SIZE * 0.5)
 
 
   make memblock 1, 12 + (ASTEROID_SIZE * ASTEROID_SIZE * 4)
   write memblock dword 1, 0, ASTEROID_SIZE
   write memblock dword 1, 4, ASTEROID_SIZE
   write memblock dword 1, 8, 32
 
 
   p as psuedoPoint
   for y = 0 to ASTEROID_SIZE - 1
      for x = 0 to ASTEROID_SIZE - 1
         pos = 12 + ((y * ASTEROID_SIZE) + x) * 4
 
         p.x# = x - (ASTEROID_SIZE * 0.5)
         p.y# = y - (ASTEROID_SIZE * 0.5)
 
         if PointInAsteroid(p, j, 0.0) = 0
            `outside
            write memblock dword 1, pos, 0
         else
            `inside
            write memblock dword 1, pos, col
         endif
      next x
   next y
   make image from memblock j, 1
 
   delete memblock 1
 
   sprite j, 0, 0, j
   offset sprite j, Asteroids(j).cX#, Asteroids(j).cY#
 
   Asteroids(j).x# = rnd(screen width())
   Asteroids(j).y# = rnd(screen height())
 
   Asteroids(j).speedX# = rnd(25) + 25 : if rnd(1) then Asteroids(j).speedX# = Asteroids(j).speedX# * -1
   Asteroids(j).speedY# = rnd(25) + 25 : if rnd(1) then Asteroids(j).speedY# = Asteroids(j).speedY# * -1
   Asteroids(j).rotSpeed# = rnd(40) + 20 : if rnd(1) then Asteroids(j).rotSpeed# = Asteroids(j).rotSpeed# * -1
   Asteroids(j).angle# = 0.0
 
   Asteroids(j).imgId = j : `Temp - will allow multiple asteroids for randomness
next j
 
 
 
 
 
global frameTime#
frameTime# = 1.0
startTime = timer()
do
   frameTime# = (frameTime# * 0.8) + ((timer() - startTime) * 0.2)
   startTime = timer()
 
   moveAsteroids()
   checkAsteroids()
 
   text 0, screen height() - 20, "FPS: " + str$(screen fps())
   sync
loop
end
 
 
exitfunction
function checkAsteroids()
   for i = 1 to ASTEROID_COUNT
      for j = i+1 to ASTEROID_COUNT
         `Check squared distance between asteroids... Quicker check to see if we need to check points
         dx# = Asteroids(i).x# - Asteroids(j).x#
         dy# = Asteroids(i).y# - Asteroids(j).y#
         radiussum# = (Asteroids(i).size * 0.5) + (Asteroids(j).size * 0.5)
 
         if (dx#*dx#)+(dy#*dy#) <= radiussum#*radiussum#
            `Compare asteroid i to j. This loop structure should stop comparing A to B then B to A...
            ap as psuedoPoint
            angle# = Asteroids(i).angle#
            for k = 1 to ASTEROID_POINTS
               ap.x# = (psuedoLineArray(i, k).p.x# * cos(angle#)) - (psuedoLineArray(i, k).p.y# * sin(angle#))
               ap.y# = (psuedoLineArray(i, k).p.x# * sin(angle#)) + (psuedoLineArray(i, k).p.y# * cos(angle#))
 
               inc ap.x#, dx#
               inc ap.y#, dy#
 
               `Point p is now 1 vertice of asteroid 'i'. See if this point is in asteroid 'j'
               if PointInAsteroid(ap, j, Asteroids(j).angle#) = 1 then text 400, 400, "ASTEROID COLLISION!!!"
            next k
         endif
      next j
   next i
endfunction
 
 
 
 
 
 
 
`CODE HERE BASED ON: http://astronomy.swin.edu.au/~pbourke/geometry/insidepoly/
function PointInAsteroid(p as psuedoPoint, j, angle#)
   `Check if point p is within asteroid 'j'
   p1 as psuedoPoint
   p2 as psuedoPoint
   counter = 0
 
 
   `Angle is zero, no need to rotate!
   if angle# = 0.0
      p1 = psuedoLineArray(j, 0).p
   else
      p1.x# = (psuedoLineArray(j, 0).p.x# * cos(angle#)) - (psuedoLineArray(j, 0).p.y# * sin(angle#))
      p1.y# = (psuedoLineArray(j, 0).p.x# * sin(angle#)) + (psuedoLineArray(j, 0).p.y# * cos(angle#))
   endif
 
 
   for i = 1 to ASTEROID_POINTS
      if angle# = 0.0
         p2 = psuedoLineArray(j, i MOD ASTEROID_POINTS).p
      else
         iMODap = i MOD ASTEROID_POINTS
         p2.x# = (psuedoLineArray(j, iMODap).p.x# * cos(angle#)) - (psuedoLineArray(j, iMODap).p.y# * sin(angle#))
         p2.y# = (psuedoLineArray(j, iMODap).p.x# * sin(angle#)) + (psuedoLineArray(j, iMODap).p.y# * cos(angle#))
      endif
 
 
 
      if p.y# > MIN(p1.y#, p2.y#)
         if p.y# <= MAX(p1.y#, p2.y#)
            if p.x# <= MAX(p1.x#, p2.x#)
               if p1.y# <> p2.y#
                  xinters# = (p.y# - p1.y#) * (p2.x# - p1.x#) / (p2.y# - p1.y#) + p1.x#
                  if p1.x# = p2.x# OR p.x# <= xinters# then inc counter
               endif
            endif
         endif
      endif
 
      p1 = p2
   next i
 
   result = counter MOD 2
endfunction result
 
 
 
 
 
 
 
 
function moveAsteroids()
   for j = 1 to ASTEROID_COUNT
      inc Asteroids(j).x#, Asteroids(j).speedX# * frameTime# * 0.001
      inc Asteroids(j).y#, Asteroids(j).speedY# * frameTime# * 0.001
      inc Asteroids(j).angle#, Asteroids(j).rotSpeed# * frameTime# * 0.001
      rotate sprite j, Asteroids(j).angle#
 
      `Check for horizontal bounds
      if Asteroids(j).speedX# < 0
         `going left, are we too far?
         if Asteroids(j).x# + Asteroids(j).Size * 0.5 < 0 then inc Asteroids(j).x#, screen width() + Asteroids(j).Size
      else
         `going right, are we too far?
         if Asteroids(j).x# - Asteroids(j).Size * 0.5 > screen width() then dec Asteroids(j).x#, screen width() + Asteroids(j).Size
      endif
 
 
 
      `Check for vertical bounds
      if Asteroids(j).speedY# < 0
         `going up, are we too far?
         if Asteroids(j).y# + Asteroids(j).Size * 0.5 < 0 then inc Asteroids(j).y#, screen height() + Asteroids(j).Size
      else
         `going right, are we too far?
         if Asteroids(j).y# - Asteroids(j).Size * 0.5 > screen height() then dec Asteroids(j).y#, screen height() + Asteroids(j).Size
      endif
 
      sprite j, Asteroids(j).x#, Asteroids(j).y#, Asteroids(j).imgId
   next j
endfunction
 
 
 
 
 
function MIN(a#, b#)
   if a# < b# then r# = a# else r# = b#
endfunction r#
 
function MAX(a#, b#)
   if a# > b# then r# = a# else r# = b#
endfunction r#