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; 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;