`Started: 17/04/2005 -> 3:20am `Description: short breakout program to help any new programmers to visualise other methods of detecting collision, ` and how to use user defined types effectively. ` not a particularly great game tho ^_^ `constant describing the force of gravity #constant grav = 0.2 #constant padSize = 50.0 #constant blockSize = 30.0 #constant tailSize = 5 `type describing a 2D vector type vector x as float y as float endtype `type describing an object with movement and position vectors type object move as vector pos as vector endtype `type describing a surface with force and position vectors type surface force as vector pos as vector endtype `type describing a entity which has a position a force and may be active or inactive `i refuse to use DarkBasic boolean as it causes many problems in some functions where they wont work `i strongly reccomend you do NOT use booleans in your program as it causes many internal bugs of darkbasic to surface type entity isActive as integer pos as vector endtype type level levelNum as integer levelScore as integer levelLife as integer wallPos as integer brickColor as integer ballSpeed as integer endtype arena as level arena.levelNum = 1 arena.levelScore = 0 arena.levelLife = 10 arena.wallPos = 5 arena.brickColor = rgb(rnd(128)+127,rnd(128)+127,rnd(128)+127) arena.ballSpeed = 15 `variable to hold the position and movement vector of the ball ball as object ball.move.x = 5 ball.move.y = -10 ball.pos.x = 400 ball.pos.y = 400 `define an array to hold the positions and forces of the walls dim wall(1) as surface `Left wall wall(0).pos.x = 10 wall(0).force.x = 10 `Right Wall wall(1).pos.x = 790 wall(1).force.x = -10 `Top Wall wall(0).pos.y = 10 wall(0).force.y = 10 `Lower Wall wall(1).pos.y = 590 wall(1).force.y = 0 `define an array to hold the positions and forces of the pads pad as surface `values for the 1st pad pad.pos.y = 500 pad.force.x = -500 pad.force.y = -1000 `define an array to hold the positions of the ball tail dim tail(tailSize) as vector for tailNum = 0 to 5 tail(tailNum).x = ball.pos.x tail(tailNum).y = ball.pos.y next tailNum `define an array for the blocks dim blocks(49) as entity for xPos = 0 to 9 for yPos = 0 to 4 blocks(blockNum).isActive = 1 blocks(blockNum).pos.x = 130 + 60 * xPos blocks(blockNum).pos.y = 120 + 40 * yPos inc blockNum next yPos next xPos dim highScore(9) as integer if file exist("tomuscore1.dat") = 0 open to write 1,"tomuscore1.dat" for score = 0 to 9 highScore(score) = 300000 / (score + 1) write file 1 , highScore(score) next score close file 1 else open to read 1,"tomuscore1.dat" for score = 0 to 9 read file 1,highScore(score) next score close file 1 endif `setup directX display set display mode 800,600,32 `define the sychronisation rate and flip the buffers twice sync on : sync rate 30 sync : sync `hide the mouse cursor hide mouse do answer = startGame() arena.levelNum = 1 arena.levelScore = 0 arena.levelLife = 10 arena.wallPos = 5 arena.brickColor = rgb(rnd(128)+127,rnd(128)+127,rnd(128)+127) arena.ballSpeed = 15 `Left wall wall(0).pos.x = 10 wall(0).force.x = 10 `Right Wall wall(1).pos.x = 790 wall(1).force.x = -10 `Top Wall wall(0).pos.y = 10 wall(0).force.y = 10 `Lower Wall wall(1).pos.y = 590 wall(1).force.y = 0 select answer case 1 playGame() endcase case 2 endGame() endcase case 3 end endcase endselect loop function playGame() `main loop repeat ink rgb(0,128,255),0 text 10,0,"Level: " + str$(arena.levelNum) text 600,0,"Score: " + str$(arena.levelScore) text 700,0,"Lives: " + str$(arena.levelLife) center text 400,0,"Press "Q" to quit..." `user controls the pad and checks for collision with the wall pad.pos.x = mousex() pad.force.x = mousemovex() if abs(pad.pos.x - wall(0).pos.x) < padSize then pad.pos.x = wall(0).pos.x + padSize if abs(pad.pos.x - wall(1).pos.x) < padSize then pad.pos.x = wall(1).pos.x - padSize `allow user to reset the ball if ball.pos.y = wall(1).pos.y if spacekey() ball.move.x = rnd(10)-5 ball.move.y = - arena.ballSpeed ball.pos.x = 400 ball.pos.y = 400 dec arena.levelLife else center text 400 , 400 , "Press Space To Reset Ball..." endif endif `calculate the users x force userX# = curveValue( (rightkey()-leftkey()) * 0.4 , userX# , 10 ) `call ball control function to refresh the ball data controlBall() `draw walls drawBox( wall(0).pos.x , wall(0).pos.y , wall(1).pos.x , wall(1).pos.y , rgb(255,0,0) ) drawBox( wall(0).pos.x + 10 , wall(0).pos.y + 10 , wall(1).pos.x - 10 , wall(1).pos.y - 10 , rgb(128,0,0) ) drawBox( wall(0).pos.x + 20 , wall(0).pos.y + 20 , wall(1).pos.x - 20 , wall(1).pos.y - 20 , rgb(64,0,0) ) drawBox( wall(0).pos.x + 30 , wall(0).pos.y + 30 , wall(1).pos.x - 30 , wall(1).pos.y - 30 , rgb(32,0,0) ) `draw tail of ball first so the ball with have priority on screen display for tailPos = 0 to 5 drawBall( tail(tailPos).x , tail(tailPos).y , 5 , 2 , rgb(255,51*tailPos,0) ) next tailPos inc tailNum `control move the pointer to the next ball if tailNum > tailSize then tailNum = 0 tail(tailNum).x = ball.pos.x tail(tailNum).y = ball.pos.y `draw ball drawBall( ball.pos.x , ball.pos.y , 10 , 3 , rgb(0,255,128) ) `draw pads drawPad( pad.pos.x , pad.pos.y , padSize , rgb(255,128,0) ) `draw blocks for blockNum = 0 to 49 if blocks(blockNum).isActive = 1 then drawPad( blocks(blockNum).pos.x , blocks(blockNum).pos.y , blockSize , arena.brickColor ) next blockNum `synchronise the screen sync `clear screen to avoid pixel dragging cls `end main loop if arena.levelLife < 0 || upper$(inkey$()) = "Q" endGame() mainmenu = 1 endif until mainmenu = 1 endfunction `function to start game function startGame() cls size = text size() set text size size + 20 ink RGB(0,0,255) , 0 center text 400 , 100 , "Tomu Breakout!" drawPad(400,115,200,RGB(0,128,255)) set text size size ink RGB(0,128,255) , 0 center text 400 , 200 , "1 - Play Game" center text 400 , 250 , "2 - High Scores" center text 400 , 300 , "3 - Exit" sync repeat answer = val(inkey$()) until answer > 0 endfunction answer `function to end the game function endGame() if arena.levelScore > highScore(9) highScore(9) = arena.levelScore place = 9 for score = 0 to 8 pos = 9 - score if highScore(pos) > highScore(pos - 1) temp = highScore(pos - 1) highScore(pos - 1) = highScore(pos) highScore(pos) = temp dec place endif next score delete file "tomuscore1.dat" open to write 1 , "tomuscore1.dat" for score = 0 to 9 write file 1 , highScore(score) next score close file 1 endif cls center text 400 , 100 , "Scores:" for score = 0 to 9 if score = place ink RGB(0,0,255),0o else if score = 0 ink RGB(255,128,0),0 else ink RGB(0,128,255),0 endif endif center text 400 , 150 + score * 30 , str$(score+1) + ": " + str$(highScore(score)) next score if arena.levelScore > 0 then center text 400 , 100 + (score + 2) * 30 , "Your Score: " + str$(arena.levelScore) center text 400 , 100 + (score + 3) * 30 , "press any key to end..." sync wait key endfunction `function to control movement of the ball function controlBall() null = make vector2(1) set vector2 1 , ball.move.x , ball.move.y magnitude# = length vector2(1) divide vector2 1 , magnitude# repeat for blockNum = 0 to 49 if blocks(blockNum).isActive = 1 if ( abs(ball.pos.x - blocks(blockNum).pos.x) <= blockSize ) && ( abs(ball.pos.y - blocks(blockNum).pos.y) <= blockSize / 4 ) blocks(blockNum).isActive = 0 inc arena.levelScore , 100 * arena.levelNum ball.move.y = - ball.move.y endif inc totalBlocks endif next blockNum if totalBlocks = 0 for blockNum = 0 to 49 blocks(blockNum).isActive = 1 next blockNum if arena.levelNum < 13 inc wall(0).pos.x , arena.wallPos inc wall(0).pos.y , arena.wallPos dec wall(1).pos.x , arena.wallPos dec wall(1).pos.y , arena.wallPos endif inc arena.ballSpeed , 2 inc arena.levelNum , 1 arena.brickColor = rgb(rnd(128)+127,rnd(128)+127,rnd(128)+127) endif if ( abs(ball.pos.x - pad.pos.x) <= padSize ) && ( abs(ball.pos.y - pad.pos.y) <= padSize / 4 ) ball.move.y = - arena.ballSpeed inc ball.move.x , ( ball.pos.x - pad.pos.x ) / magnitude# `swept collision hack :D inc ball.move.x , pad.force.x / magnitude# / 12 endif `work out the inverse square law of the forces on the walls and add pad force `inverse square law = ( 1 / distance^2 ) * force xForce# = ((1 / (3+abs(ball.pos.x - wall(0).pos.x))^2) * wall(0).force.x) + ((1 / (1+abs(ball.pos.x - wall(1).pos.x))^2) * wall(1).force.x / magnitude#) yForce# = ((3 / (1+abs(ball.pos.y - wall(0).pos.y))^2) * wall(0).force.y) + ((1 / (1+abs(ball.pos.y - wall(1).pos.y))^2) * wall(1).force.y / magnitude#) `add the wall force to the ball movement vectors. add gravity inc ball.move.x , xForce# inc ball.move.y , yForce# + grav / magnitude# `add movement vector and user input to the ball position inc ball.pos.x , ball.move.x / magnitude# inc ball.pos.y , ball.move.y / magnitude# `check for actual wall collision if ball.pos.x < wall(0).pos.x ball.pos.x = wall(0).pos.x endif if ball.pos.x > wall(1).pos.x ball.pos.x = wall(1).pos.x endif if ball.pos.y < wall(0).pos.y ball.pos.y = wall(0).pos.y endif if ball.pos.y > wall(1).pos.y ball.pos.y = wall(1).pos.y endif inc count# , 1 / magnitude# until count# > 1 null = delete vector2(1) endfunction `function to draw the ball function drawBall( xPos , yPos , size# , segments , color) increment# = size# / segments for seg = 1 to segments ink rgb( rgbr(color)/seg , rgbg(color)/seg , rgbb(color)/seg ) , 0 circle xPos , yPos , increment# * seg next seg endfunction `function to draw a box function drawBox( lf , up , rt , dn , color) ink color , 0 line lf , up , rt , up line rt , up , rt , dn line rt , dn , lf , dn line lf , dn , lf , up endfunction `function to draw a pad function drawPad( xPos , yPos , size# , color ) ink color , 0 drawBox( xPos - size# , yPos - size# / 4 , xPos + size# , yPos + size# / 4 , rgb( rgbr(color)/2 , rgbg(color)/2 , rgbb(color)/2 ) ) drawBox( xPos - (size# * 0.5) , yPos - (size# * 0.5) / 4 , xPos + (size# * 0.5) , yPos + (size# * 0.5) / 4 , color ) endfunction