BALL_SPEED = 3; VERT_MARGIN = 60; HORIZ_MARGIN = 40; BLOCK_PADDING = 5; MAX_DX = 4; COLL_LEFT = 1; COLL_RIGHT = 2; COLL_TOP = 3; COLL_BOTTOM = 4; lastScore = 0; highScore = 0; ballImage = loadImage("ball.png"); blockImage = loadImage("block.png"); batImage = loadImage("bat.png"); ballSprite = toSprite(ballImage); batSprite = toSprite(batImage); blocksPerLine = (width() - 2 * HORIZ_MARGIN) / (width(blockImage) + BLOCK_PADDING); firstBlockX = (width() - blocksPerLine * width(blockImage) - (blocksPerLine - 1) * BLOCK_PADDING) / 2; index = 1; for y = 1 to 6 do blockX = firstBlockX; blockY = height() - (VERT_MARGIN + (y - 1) * (height(blockImage) + BLOCK_PADDING)); for x = 1 to blocksPerLine do blockSprite[index] = toSprite(blockImage); spriteMove(blockSprite[index], blockX, blockY); blockX = blockX + width(blockImage) + BLOCK_PADDING; index = index + 1; done; done; function setupNewWall() numVisible = 0; for q = 1 to maxIndex(blockSprite) do spriteVisible(blockSprite[q], TRUE); numVisible = numVisible + 1; done; endfunc; function showScore() cls(); println("Score: ", score, " Lives: ", lives); endfunc; function setupNewGame() score = 0; lives = 3; showScore(); setupNewWall(); batX = (width() - width(batSprite)) / 2; batY = 20; spriteMove(batSprite, batX, batY); spriteVisible(ballSprite, TRUE); spriteVisible(batSprite, TRUE); endfunc; function setupNewRound() ballX = (width() - width(ballSprite)) / 2; ballY = (height() - height(ballSprite)) / 2; spriteMove(ballSprite, ballX, ballY); ballDX = 1; ballDY = -2; showScore(); showMessage("Get ready!"); wait(3000); showScore(); endfunc; function getOneCollidedBlockIndex() for q = 1 to maxIndex(blockSprite) do if spriteCollision(ballSprite, blockSprite[q]) then return q; endif; done; return -1; endfunc; function getCollisionSide(index) local ballBottom = spriteY(ballSprite); local ballTop = ballBottom + height(ballSprite); local ballLeft = spriteX(ballSprite); local ballRight = ballLeft + width(ballSprite); local blockBottom = spriteY(blockSprite[index]); local blockTop = blockBottom + height(blockSprite[index]); local blockLeft = spriteX(blockSprite[index]); local blockRight = blockLeft + width(blockSprite[index]); if ballRight >= blockLeft and ballRight < blockLeft + 3 then return COLL_LEFT; elseif ballLeft <= blockRight and ballLeft > blockRight - 3 then return COLL_RIGHT; elseif ballTop >= blockBottom and ballBottom < blockBottom then return COLL_BOTTOM; elseif ballBottom <= blockTop and ballTop > blockTop then return COLL_TOP; endif; return COLL_BOTTOM; // just in case endfunc; function updateBallPos() ballX = ballX + BALL_SPEED * ballDX; if ballX < 0 or ballX > width() - width(ballSprite) then ballDX = -ballDX; ballX = ballX + 2 * BALL_SPEED * ballDX; endif; ballY = ballY + BALL_SPEED * ballDY; if ballY > height() - height(ballSprite) then ballDY = -ballDY; ballY = ballY + 2 * BALL_SPEED * ballDY; endif; spriteMove(ballSprite, ballX, ballY); if spriteCollision(ballSprite, batSprite) then local ballCenterX = ballX + width(ballSprite) / 2; local batCenterX = batX + width(batSprite) / 2; local dx = (ballCenterX - batCenterX) / 7; ballDX = ballDX + dx; if ballDX > MAX_DX then ballDX = MAX_DX; elseif ballDX < -MAX_DX then ballDX = -MAX_DX; endif; ballDY = -ballDY; ballX = ballX + 2 * BALL_SPEED * ballDX; ballY = ballY + 2 * BALL_SPEED * ballDY; spriteMove(ballSprite, ballX, ballY); endif; local collidedBlockIndex = getOneCollidedBlockIndex(); while collidedBlockIndex > 0 do local collisionSide = getCollisionSide(collidedBlockIndex); if collisionSide == COLL_LEFT or collisionSide == COLL_RIGHT then ballDX = -ballDX; elseif collisionSide == COLL_TOP or collisionSide == COLL_BOTTOM then ballDY = -ballDY; endif; spriteVisible(blockSprite[collidedBlockIndex], FALSE); score = score + 10; showScore(); numVisible = numVisible - 1; collidedBlockIndex = getOneCollidedBlockIndex(); done; spriteMove(ballSprite, ballX, ballY); endfunc; function showMessage(message) println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + " ", message); flush(); endfunc; function gameOver() lastScore = score; if score > highScore then highScore = score; endif; showMessage("Game over"); wait(3000); endfunc; function playRound() setupNewRound(); local finished = FALSE; while not finished do local t = time(); batX = mouseX() - width(batSprite) / 2; spriteMove(batSprite, batX, batY); updateBallPos(); if ballY < 0 then lives = lives - 1; showScore(); if lives == 0 then gameOver(); finished = TRUE; else setupNewRound(); endif; elseif numVisible == 0 then setupNewWall(); setupNewRound(); endif; flush(); t = time() - t; wait(30 - t); done; endfunc; function playGame() for q = 1 to maxIndex(blockSprite) do spriteVisible(blockSprite[q], FALSE); done; spriteVisible(batSprite, FALSE); spriteVisible(ballSprite, FALSE); cls(); println("\n\n --- BREAKOUT ---"); println("\n\n Last score: ", lastScore, " Highscore: ", highScore); println("\n\n Use the mouse to control the \"bat\""); println(" Press F12 to quit"); println("\n\n Press any key to start"); flush(); waitKey(); setupNewGame(); playRound(); endfunc; autoFlush(FALSE); while TRUE do playGame(); done;