randomize timer()
 
REM VARIABLES
depth# = 498
screenwidth# = 800
screenheight# = 600
width# = (depth#/100)*160
height# = (depth#/100)*120
even# = screenwidth#/1.6
prop# = depth#/even#
#constant obj_paddle = 1
#constant obj_ball = 2
paddle_X# = screenwidth#/2          :  `X position of paddle (start centered of screen)
paddle_Width = 40                   :  `paddle's half width (if set to 20, total paddle width would be 40)
paddle_thickness = 5                :  `thickness of paddle
#constant INTERFACE_BORDER = 800    :  `x-intercept boundary marking off interface from game area
#constant MAX_ANGLE = 75            :  `max angle that paddle can reflect ball off
#constant BRICK_WIDTH = 60
#constant BRICK_HEIGHT = 40
death = 1
score = 0
lives = 4
 
type vector2d
   x as float
   y as float
endtype
 
type toy
   position as vector2d
   oldPosition as vector2d
   direction as vector2d
   velocity as float
   radius as float
endtype
 
ball as toy
 
ball.position.x = 50
ball.position.y = paddle_thickness + ball.radius
ball.direction.x = 0
ball.direction.y = 1
ball.velocity = 4
ball.radius = 10
 
type fadeObject
   object as integer
   fade as integer
endtype
 
dim fadeObjectOut(0) as fadeObject
fade_count = 0
dim killObject(0)
 
type triangle
   x1 as float
   y1 as float
   x2 as float
   y2 as float
   x3 as float
   y3 as float
   alive as integer
endtype
 
type brick
   a as triangle
   b as triangle
endtype
 
dim map(11,5) as brick
 
rem temp variable
tri as triangle
 
null = make vector2(1)  :  `ball direction vector and reflection vector(after calculation)
null = make vector2(2)  :  `line normal
 
 
REM SETUP
set display mode screenwidth#,screenheight#,32
sync on
sync rate 60
autocam off
hide mouse
 
REM CREATE IMAGE
for x=1 to 20
   for y=1 to 20
      c = rnd(255)
      dot rnd(128), rnd(128), rgb(c,c,c)
   next y
next x
get image 1, 1,1,128,128
 
 
REM CREATE PADDLE
make object plain obj_paddle,paddle_Width*2,paddle_thickness
color object obj_paddle, rgb(255,0,0)
 
REM CREATE BALL
make object sphere obj_ball, ball.radius
color object obj_ball, rgb(200,128,0)
 
REM CREATE BACKGROUND
make object plain 3, screenwidth#+4, screenheight#+4
position object 3, screenwidth#/2, screenheight#/2,500
texture object 3, 1
 
 
 
 
color as dword
obj = 3
REM Create triangles
   for x = 1 to 11
      for y = 1 to 5
         color = rgb(rnd(255),rnd(255),rnd(255))
         inc obj
         make object triangle obj,0,0,0,0,-BRICK_HEIGHT,0,BRICK_WIDTH,-BRICK_HEIGHT,0
         position object obj, x*BRICK_WIDTH,screenheight#-y*BRICK_HEIGHT,depth#
         color object obj, color
         map(x,y).a.x1 = x*BRICK_WIDTH
         map(x,y).a.y1 = screenheight#-y*BRICK_HEIGHT
         map(x,y).a.x2 = x*BRICK_WIDTH
         map(x,y).a.y2 = screenheight#-(y+1)*BRICK_HEIGHT
         map(x,y).a.x3 = (x+1)*BRICK_WIDTH
         map(x,y).a.y3 = screenheight#-(y+1)*BRICK_HEIGHT
         map(x,y).a.alive = obj
 
         inc obj
         make object triangle obj,0,0,0,BRICK_WIDTH,0,0,BRICK_WIDTH,-BRICK_HEIGHT,0
         position object obj, x*BRICK_WIDTH,screenheight#-y*BRICK_HEIGHT,depth#
         color object obj, color
         map(x,y).b.x1 = x*BRICK_WIDTH
         map(x,y).b.y1 = screenheight#-y*BRICK_HEIGHT
         map(x,y).b.x2 = (x+1)*BRICK_WIDTH
         map(x,y).b.y2 = screenheight#-y*BRICK_HEIGHT
         map(x,y).b.x3 = (x+1)*BRICK_WIDTH
         map(x,y).b.y3 = screenheight#-(y+1)*BRICK_HEIGHT
         map(x,y).b.alive = obj
      next y
   next x
 
 
 
 
REM STUFF
position camera width#/2,height#/2,0
 
speedup_stamp = timer()
 
 
 
 
REM ==============================  MAIN LOOP =================================
DO
 
   rem record previous position
   ball.oldPosition.x = ball.position.x
   ball.oldPosition.y = ball.position.y
 
   gosub _handle_controls
 
   if death = 0
      rem get new position of ball
      ball.position.x = ball.position.x + ball.direction.x*ball.velocity
      ball.position.y = ball.position.y + ball.direction.y*ball.velocity
 
      gosub _handle_ball_collisions
   else
      ball.position.x = paddle_X
      if mouseclick() = 1 then death = 0
   endif
 
   if speedup_stamp+2000 < timer()
      ball.velocity = ball.velocity + 0.2
      speedup_stamp = timer()
   endif
 
   position object obj_ball, ball.position.x, ball.position.y,depth#
   position object obj_paddle, paddle_X,5,498
 
   gosub _handle_fading_objects
 
   center text screenwidth#/2,1,"Score: "+str$(score)
   text screenwidth#-100,1,"Lives: "+str$(lives)
   text 1,1,"FPS: "+str$(screen fps())
   text 1,10,"Speed: "+str$(ball.velocity)
 
 
   fastsync
LOOP
REM =========================  END  MAIN  LOOP  ===============================
 
 
 
 
 
 
rem handle paddle movement with mouse and handle paddle's boundaries
_handle_controls:
   paddle_X = paddle_x + mousemovex()/3
   if paddle_X-paddle_Width < 0 then paddle_X = paddle_Width
   if paddle_X+paddle_Width > interface_border then paddle_X = interface_border-paddle_Width
return
 
 
 
 
rem handles ball collision with paddle, play area boundaries, and brick objects
_handle_ball_collisions:
 
   rem if ball hits paddle
   if ball.position.y <= (paddle_thickness + ball.radius)
      if ball.position.x >= paddle_X - paddle_Width AND ball.position.x <= paddle_X + paddle_Width
         angle# = 90-((ball.position.x-paddle_X) * MAX_ANGLE)/paddle_Width
         ball.direction.x = cos(angle#)
         ball.direction.y = sin(angle#)
      endif
   endif
 
   rem walls
   if ball.position.x <= ball.radius
      ball.position.x = ball.radius
      ball.direction.x = ball.direction.x*-1
   endif
   if ball.position.x >= INTERFACE_BORDER-ball.radius
      ball.position.x = INTERFACE_BORDER-ball.radius
      ball.direction.x = ball.direction.x*-1
   endif
   rem ceiling
   if ball.position.y >= screenheight#-ball.radius
      ball.position.y = screenheight#-ball.radius
      ball.direction.y = ball.direction.y*-1
   endif
 
   rem if ball drops below paddle
   if ball.position.y < 0
      ball.position.y = paddle_thickness + ball.radius
      ball.direction.y = 1
      ball.direction.x = 0
      ball.velocity = 4
      death = 1
      dec lives, 1
   endif
 
   rem brick collision
   for x = 1 to 11
      for y = 1 to 5
         if map(x,y).a.alive > 0
            tri = map(x,y).a
            if triangle_collide#(ball,tri) > 0
               `hide object map(x,y).a.alive
               array insert at top fadeObjectOut(0)
               fadeObjectOut(0).object = map(x,y).a.alive
               fadeObjectOut(0).fade = 100
               inc fade_count, 1
               inc score, 10
               map(x,y).a.alive = 0
               if map(x,y).a.alive = 0 and map(x,y).b.alive = 0 then inc score, 5
               calculate_reflection()
            endif
         endif
         if map(x,y).b.alive > 0
            tri = map(x,y).b
            if triangle_collide#(ball,tri) > 0
               `hide object map(x,y).b.alive
               array insert at top fadeObjectOut(0)
               fadeObjectOut(0).object = map(x,y).b.alive
               fadeObjectOut(0).fade = 100
               inc fade_count, 1
               inc score, 10
               map(x,y).b.alive = 0
               if map(x,y).a.alive = 0 and map(x,y).b.alive = 0 then inc score, 5
               calculate_reflection()
            endif
         endif
      next y
   next x
return
 
 
 
rem does some stuff, i don't feel like documenting right now
_handle_fading_objects:
   for i = 0 to fade_count
      obj = fadeObjectOut(i).object
      fadeObjectOut(i).fade = fadeObjectOut(i).fade - 2
      if fadeObjectOut(i).fade >= 0
         fade object obj, fadeObjectOut(i).fade
      else
         array insert at top killObject()
         killObject(0) = obj
         `hide object obj
         `array delete element fadeObjectOut(i)
         `dec fade_count, 1
      endif
   next i
 
   for j = 0 to array count(killObject())
      for i = 0 to fade_count
         if fadeObjectOut(i).object = killObject(j)
            `hide object killObject(j)
            array delete element fadeObjectOut(i)
            dec fade_count, 1
         endif
      next i
   next j
   empty array killObject()
 
return
 
 
 
rem calculates ball's reflection from brick(triangle)
rem assumes reflection surface vector was set and normalized (vector 2)
function calculate_reflection()
   set vector2 1, ball.direction.x, ball.direction.y
   dp# = dot product vector2(1,2)*2
   multiply vector2 2,dp#
   subtract vector2 1, 1, 2
   normalize vector2 1, 1
   ball.direction.x = x vector2(1)
   ball.direction.y = y vector2(1)
endfunction
 
 
 
 
rem returns a time value of set [0,1] of closest intersection between ball's velocity vector and triangle's sides
rem if intersection happens, calculates normal of reflection surface and stores in vector 2
rem returns -1 if no sides were hit
function triangle_collide#(b as toy, t as triangle)
   a# = _line_intersect(b.oldPosition.x,b.oldPosition.y,b.position.x,b.position.y,t.x1,t.y1,t.x2,t.y2)
   b# = _line_intersect(b.oldPosition.x,b.oldPosition.y,b.position.x,b.position.y,t.x1,t.y1,t.x3,t.y3)
   c# = _line_intersect(b.oldPosition.x,b.oldPosition.y,b.position.x,b.position.y,t.x2,t.y2,t.x3,t.y3)
 
   rem if a# is first intersection
   if a# < 1
      if a# < b# and a# < c#
         rem set normal of reflection surface
         set vector2 2, t.y2-t.y1,-(t.x2-t.x1)
         normalize vector2 2,2
         exitfunction a#
      endif
   else
      rem if b# is first intersection
      if b# < 1
         if b# < a# and b# < c#
            rem set normal of reflection surface
            set vector2 2, t.y1-t.y3,-(t.x1-t.x3)
            normalize vector2 2,2
            exitfunction b#
         endif
      else
         rem if c# is first intersection
         if c# < 1
            if c# < a# and c# < b#
               rem set normal of reflection surface
               set vector2 2, t.y3-t.y2,-(t.x3-t.x2)
               normalize vector2 2,2
               exitfunction c#
            endif
         endif
      endif
   endif
endfunction -1.0
 
 
 
 
REM returns 2 if the two line segments dont intersect, between [0,1] if they do
function _line_intersect(ax#,ay#,bx#,by#,cx#,cy#,dx#,dy#)
 
   d# = (dy# - cy#)*(bx# - ax#) - (dx# - cx#)*(by# - ay#)
   Ua# = ((dx# - cx#)*(ay# - cy#) - (dy# - cy#)*(ax# - cx#)) / d#
   Ub# = ((bx# - ax#)*(ay# - cy#) - (by# - ay#)*(ax# - cx#)) / d#
   _intersect# = 2
 
   if Ua# > 0 and Ua# < 1 and Ub# > 0 and Ub# < 1 then _intersect# = Ua#
endfunction _intersect#