` Pong (gbark) ` DBPro Coding Challenge ` 01/11/08 - 01/20/08 ` Screen settings sync on : sync rate 60 set display mode 640, 480, 32 backdrop on : color backdrop 0 set ambient light 35 : hide light 0 autocam off set text font "Terminal" : set text size 72 hide mouse ` Create textures for objects gosub MakeTextures ` Create game objects ` (Player) make object box 1, 30, 70, 16 texture object 1, 1 ` (Cpu) make object box 2, 30, 70, 16 texture object 2, 2 ` (Ball) make object sphere 3, 30 texture object 3, 3 ` (Ball Light) make light 1 set light range 1, 300 ` (Ball Glow Object) make object plain 4, 300, 300 set object ambient 4, 0 set object light 4, 0 texture object 4, 4 ghost object on 4 disable object zdepth 4 ` Set camera position camera 0, 0, -500 point camera 0, 0, 0 ` Prepare for main menu gameMode = 0 ` Main loop do ` Run menu or game loop, depending on current game mode if gameMode = 0 then gosub MenuLoop else gosub GameLoop sync loop ` Main menu loop MenuLoop: ` Show the title gosub DrawTitle ` Check for game start gosub StartGame return ` Main game loop GameLoop: ` Move player's paddle gosub MovePlayer ` Move cpu's paddle gosub MoveCpu ` Update the ball gosub UpdateBall ` Draw scores gosub DrawScore return ` Prepare variables for a new game NewGame: ` Reset scores playerScore = 0 cpuScore = 0 ` Prepare for first round gosub NextRound ` Spawn ball in the field center for the first round ballX = 0 ballY = 0 ballServe = 0 ` Set the ball in a random direction ballXSpeed = rnd(2)+1 : if rnd(1)=1 then ballXSpeed = -ballXSpeed ballYSpeed = rnd(2)+1 : if rnd(1)=1 then ballYSpeed = -ballYSpeed return ` Reset paddles and ball for a new round NextRound: ` Reset paddle positions playerY = 0 : playerKick = 0 cpuY = 0 : cpuKick = 0 ` Reset ball speeds ballXSpeed = 0 ballYSpeed = 0 ` Set cpu difficulty based on score difference ` (1 = Easy, 5 = Normal, 10 = Hard) cpuLevel = 5 + (playerScore - cpuScore) if cpuLevel > 10 then cpuLevel = 10 if cpuLevel < 1 then cpuLevel = 1 ` Ball is moving slowly at the beginning of the round, so cpu should not miss cpuError = 0 return ` Control player's paddle MovePlayer: ` Determine where to move based on arrow keys playerYSpeed = (upkey()-downkey())*5 ` No movement if the ball went past if ballX < -300 then playerYSpeed = 0 ` Move player paddle inc playerY, playerYSpeed ` Keep paddle onscreen if playerY > 260 then playerY = 260 if playerY < -260 then playerY = -260 ` Kick paddle with space sp = spacekey() if sp = 1 and keySpace = 0 and playerKick = 0 then playerKick = 1 keySpace = sp ` Update paddle kick if playerKick > 0 then inc playerKick, 35 if playerKick > 180 then playerKick = 0 ` Update paddle position position object 1, -300+sin(playerKick)*40, playerY, 0 return ` Control cpu's paddle MoveCpu: ` Guess where the ball will end up if ballXSpeed > 0 or cpuLevel >= 6 and ballServe = 0 ` Move to where the ball will end up cpuGuessY = PredictBall(ballX, ballY, ballXSpeed, ballYSpeed, 270, (cpuLevel+10)*10) ` Add some error to the cpu's judgement (more error if the cpu is winning) inc cpuGuessY, cpuError else ` Return to center screen if ballServe = 0 then cpuGuessY = 0 endif ` Determine where to move based on guess if cpuY > cpuGuessY then cpuYSpeed = -5 if cpuY < cpuGuessY then cpuYSpeed = 5 if abs(cpuY - cpuGuessY) < 5 then cpuYSpeed = 0 ` No movement if the ball went past if ballX > 300 then cpuYSpeed = 0 ` Move cpu paddle inc cpuY, cpuYSpeed ` Keep paddle onscreen if cpuY > 260 then cpuY = 260 if cpuY < -260 then cpuY = -260 ` Kick the ball if it is close (and the cpu is a high enough level) if cpuLevel >= 7 and ballXSpeed > 0 and ballX+ballXSpeed > 260 and ballY > cpuY-50 and ballY < cpuY+50 and cpuKick = 0 and ballServe = 0 cpuKick = 1 endif ` Also kick the ball if it is time to serve if ballServe = -1 and abs(cpuY-cpuGuessY)<5 and cpuKick = 0 cpuKick = 1 endif ` Update paddle kick if cpuKick > 0 then inc cpuKick, 35 if cpuKick > 180 then cpuKick = 0 ` Update paddle position position object 2, 300-sin(cpuKick)*40, cpuY, 0 return ` Move the ball around the field UpdateBall: ` Check if a player is serving or not if ballServe <> 0 ` A player is serving the ball gosub ServeBall else ` The ball is moving freely around the field gosub MoveBall endif ` Update ball position position object 3, ballX, ballY, 0 position light 1, ballX, ballY, -50 position object 4, ballX, ballY, 0 return ` Ball is in SERVE MODE ServeBall: ` Who is serving the ball? if ballServe = 1 ` Player serving ballX = -270 ballY = playerY ` When player kicks, ball has been served if playerKick > 0 ` Ball should be in normal movement mode ballServe = 0 ` Send the ball to the right ballXSpeed = 1 ` Vertical direction should be the same as the paddle's ballYSpeed = rnd(3)+2 if (rnd(1) = 1 or SignVal(playerYSpeed) = -1) and SignVal(playerYSpeed) <> 1 then ballYSpeed = -ballYSpeed endif else ` Cpu serving ballX = 270 ballY = cpuY ` When cpu kicks, ball has been served if cpuKick > 0 ` Ball should be in normal movement mode ballServe = 0 ` Send the ball to the left ballXSpeed = -1 ` Vertical direction should be the same as the paddle's ballYSpeed = rnd(3)+2 if (rnd(1) = 1 or SignVal(cpuYSpeed) = -1) and SignVal(cpuYSpeed) <> 1 then ballYSpeed = -ballYSpeed endif endif return ` Ball is in NORMAL MOVE MODE MoveBall: ` Move ball inc ballX, ballXSpeed inc ballY, ballYSpeed ` Bounce off the top and bottom edges if ballY > 280 or ballY < -280 ballYSpeed = -ballYSpeed dec ballY, ballY mod 280 endif ` Bounce off player paddle if ballX < -270+sin(playerKick)*40 and ballX > -300 and ballY > playerY-50 and ballY < playerY+50 ` Bounce towards the right ballX = -270+(playerKick>0)*40 : ballXSpeed = abs(ballXSpeed) ` Bounce faster if player is kicking if playerKick > 0 then inc ballXSpeed, SignVal(ballXSpeed)*5 ` Bounce vertically if ball and paddle are moving in the same direction if playerYSpeed * ballYSpeed > 0 dec ballXSpeed, SignVal(ballXSpeed) inc ballYSpeed, SignVal(ballYSpeed) endif ` Bounce horizontally if ball and paddle are moving in the opposite direction if playerYSpeed * ballYSpeed < 0 inc ballXSpeed, SignVal(ballXSpeed) dec ballYSpeed, SignVal(ballYSpeed) endif endif ` Bounce off cpu paddle if ballX > 270-sin(cpuKick)*40 and ballX < 300 and ballY > cpuY-50 and ballY < cpuY+50 ` Bounce towards the left ballX = 270-(cpuKick>0)*40 : ballXSpeed = -abs(ballXSpeed) ` Bounce faster if cpu is kicking if cpuKick > 0 then inc ballXSpeed, SignVal(ballXSpeed)*5 ` Bounce vertically if ball and paddle are moving in the same direction if cpuYSpeed * ballYSpeed > 0 dec ballXSpeed, SignVal(ballXSpeed) inc ballYSpeed, SignVal(ballYSpeed) endif ` Bounce horizontally if ball and paddle are moving in the opposite direction if cpuYSpeed * ballYSpeed < 0 inc ballXSpeed, SignVal(ballXSpeed) dec ballYSpeed, SignVal(ballYSpeed) endif ` Set some error for the cpu so it's not "perfect" cpuError = (rnd(30-cpuLevel*2)-rnd(30-cpuLevel*2))*(3+rnd(abs(ballYSpeed)/3)) endif ` Keep ball from moving too fast or too slow if abs(ballXSpeed) < 2 then inc ballXSpeed, ballXSpeed mod 2 ` Min X speed if abs(ballYSpeed) < 2 then inc ballYSpeed, ballYSpeed mod 2 ` Min Y speed if abs(ballXSpeed) > 20 then dec ballXSpeed, ballXSpeed mod 20 ` Max X speed if abs(ballYSpeed) > 20 then dec ballYSpeed, ballYSpeed mod 20 ` Max Y speed ` Check for a score if abs(ballX) > 550 ` Check who scored if ballX > 550 ` Player scored inc playerScore ` Cpu to serve ballServe = -1 cpuGuessY = rnd(260)-rnd(260) else ` Cpu scored inc cpuScore ` Player to serve ballServe = 1 ` Cpu to wait cpuGuessY = 0 endif ` Update stats gosub DrawScore ` Update screen and sleep sync : sleep 1500 ` Check if anybody has won yet if playerScore < 10 and cpuScore < 10 ` No win yet, next round gosub NextRound else ` Game over, display who won if playerScore = 10 ` Player won center text 320, 100, "You Win!" else ` Cpu won center text 320, 100, "You Lose." endif ` Update the screen and sleep sync : sleep 3000 ` Return to title screen gameMode = 0 set text size 72 endif endif return ` Guess where ball will end up when it reached the cpu function PredictBall(x, y, xSpeed, ySpeed, targetX, maxLook) ` Assume the ball is moving to the right (from the player) xSpeed = abs(xSpeed) ` Determine distance from ball to target dist = abs(targetX-x) if dist > maxLook then dist = maxLook ` Guess where the ball will end up if xSpeed <> 0 then guessY = y + (ySpeed*dist/xSpeed) ` "Bounce" the guess off the screen edges if guessY > 280 then guessY = (280-guessY)+280 if guessY < -280 then guessY = (-280-guessY)-280 endfunction guessY ` Draw each player's score DrawScore: ink rgb(200, 200, 200), 0 ` Player score text 200, 30, str$(playerScore) ` Cpu score text 400, 30, str$(cpuScore) return ` Draw the title screen DrawTitle: ` Title ink rgb(255, 255, 255), 0 center text 320, 50, "Pong" ` Space to start ink rgb(200, 200, 200), 0 center text 320, 400, "SPACE To Start" ` Position paddles and ball position object 1, -300, 0, 0 ` Player paddle position object 2, 300, 0, 0 ` Cpu paddle position object 3, 0, 0, 0 ` Ball position object 4, 0, 0, 0 ` Ball glow position light 1, 0, 0, 0 ` Ball light return ` Start the game when space is pressed StartGame: ` Check for space key sp = spacekey() if sp = 1 and keySpace = 0 ` Prepare main game gameMode = 1 set text size 48 gosub NewGame endif keySpace = sp return ` Make textures for game objects MakeTextures: ` Player paddle create bitmap 1, 30, 70 ` Green background ink rgb(0, 255, 0), 0 box 0, 0, 30, 70 ` Dark green lines ink rgb(0, 128, 0), 0 line 5, 5, 25, 5 : line 25, 5, 25, 65 : line 25, 65, 5, 65 : line 5, 65, 5, 5 line 10, 10, 20, 10 : line 20, 10, 20, 60 : line 20, 60, 10, 60 : line 10, 60, 10, 10 ` Store image get image 1, 0, 0, 30, 70 delete bitmap 1 ` Cpu paddle create bitmap 1, 30, 70 ` Red background ink rgb(255, 0, 0), 0 box 0, 0, 30, 70 ` Dark red lines ink rgb(128, 0, 0), 0 line 5, 5, 25, 5 : line 25, 5, 25, 65 : line 25, 65, 5, 65 : line 5, 65, 5, 5 line 10, 10, 20, 10 : line 20, 10, 20, 60 : line 20, 60, 10, 60 : line 10, 60, 10, 10 ` Store image get image 2, 0, 0, 30, 70 delete bitmap 1 ` Ball create bitmap 1, 8, 8 ` Yellow background ink rgb(255, 255, 0), 0 box 0, 0, 8, 8 ` Store image get image 3, 0, 0, 8, 8 delete bitmap 1 ` Ball glow create bitmap 1, 64, 64 ` Black background ink 0, 0 box 0, 0, 64, 64 ` Add glow for x = 0 to 64 for y = 0 to 64 d# = sqrt((32-x)*(32-x) + (32-y)*(32-y)) c = 255-(d#/32)*255 if d# < 32 then dot x, y, rgb(c, c, 0) next y next x ` Store image get image 4, 0, 0, 64, 64 delete bitmap 1 return ` Return the positive/negative sign of any integer function SignVal(n) if n < 0 then exitfunction -1 if n > 0 then exitfunction 1 endfunction 0