-- Breakout Game for SimpleOS
-- CC: Tweaked compatible
local w, h = term.getSize()
h = h - 1
-- Game state
local paddleX = math.floor(w/2) - 3
local paddleWidth = 7
local ballX, ballY = math.floor(w/2), h - 3
local ballDX, ballDY = 1, -1
local bricks = {}
local score = 0
local lives = 3
local gameOver = false
local gameWon = false
local speed = 0.05
local ballActive = false
-- Brick settings
local brickRows = 5
local brickCols = math.floor((w - 4) / 4)
local brickWidth = 3
local brickStartY = 3
-- Brick colors
local brickColors = {
colors.red,
colors.orange,
colors.yellow,
colors.green,
colors.cyan
}
-- Initialize bricks
local function initBricks()
bricks = {}
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickCols do
bricks[row][col] = true
end
end
end
-- Count remaining bricks
local function countBricks()
local count = 0
for row = 1, brickRows do
for col = 1, brickCols do
if bricks[row][col] then count = count + 1 end
end
end
return count
end
-- Reset ball
local function resetBall()
ballX = paddleX + paddleWidth / 2
ballY = h - 3
ballDX = (math.random(2) == 1) and 1 or -1
ballDY = -1
ballActive = false
end
-- Draw game
local function draw()
term.setBackgroundColor(colors.black)
term.clear()
-- Draw bricks
for row = 1, brickRows do
for col = 1, brickCols do
if bricks[row][col] then
local x = 2 + (col - 1) * (brickWidth + 1)
local y = brickStartY + row - 1
term.setBackgroundColor(brickColors[row] or colors.white)
term.setCursorPos(x, y)
term.write(string.rep(" ", brickWidth))
end
end
end
-- Draw paddle
term.setBackgroundColor(colors.white)
term.setCursorPos(paddleX, h - 1)
term.write(string.rep(" ", paddleWidth))
-- Draw ball
term.setBackgroundColor(colors.black)
term.setTextColor(colors.yellow)
term.setCursorPos(math.floor(ballX), math.floor(ballY))
term.write("O")
-- Draw info bar
term.setBackgroundColor(colors.gray)
for x = 1, w do
term.setCursorPos(x, h + 1)
term.write(" ")
end
term.setTextColor(colors.white)
term.setCursorPos(2, h + 1)
term.write("Score: " .. score .. " Lives: " .. lives)
term.setCursorPos(w - 7, h + 1)
term.write("[Q]uit")
-- Instructions
if not ballActive and not gameOver and not gameWon then
term.setBackgroundColor(colors.black)
term.setTextColor(colors.gray)
term.setCursorPos(math.floor(w/2) - 8, math.floor(h/2))
term.write("Press SPACE to launch")
end
end
-- Update ball
local function update()
if not ballActive then
ballX = paddleX + paddleWidth / 2
return
end
ballX = ballX + ballDX
ballY = ballY + ballDY
-- Wall collisions
if ballX <= 1 then
ballX = 1
ballDX = math.abs(ballDX)
elseif ballX >= w then
ballX = w
ballDX = -math.abs(ballDX)
end
if ballY <= 1 then
ballY = 1
ballDY = math.abs(ballDY)
end
-- Paddle collision
if ballY >= h - 2 and ballY <= h - 1 then
if ballX >= paddleX and ballX <= paddleX + paddleWidth then
ballDY = -math.abs(ballDY)
-- Adjust angle based on hit position
local hitPos = (ballX - paddleX) / paddleWidth
ballDX = (hitPos - 0.5) * 3
if math.abs(ballDX) < 0.5 then
ballDX = (ballDX >= 0) and 0.5 or -0.5
end
end
end
-- Brick collisions
for row = 1, brickRows do
for col = 1, brickCols do
if bricks[row][col] then
local bx = 2 + (col - 1) * (brickWidth + 1)
local by = brickStartY + row - 1
if ballX >= bx and ballX < bx + brickWidth and
math.floor(ballY) == by then
bricks[row][col] = false
score = score + (brickRows - row + 1) * 10
ballDY = -ballDY
if countBricks() == 0 then
gameWon = true
end
end
end
end
end
-- Ball lost
if ballY > h then
lives = lives - 1
if lives <= 0 then
gameOver = true
else
resetBall()
end
end
end
-- Game over screen
local function showGameOver()
term.setBackgroundColor(colors.black)
term.setTextColor(colors.red)
term.setCursorPos(math.floor(w/2) - 4, math.floor(h/2))
term.write("GAME OVER")
term.setTextColor(colors.white)
term.setCursorPos(math.floor(w/2) - 6, math.floor(h/2) + 1)
term.write("Score: " .. score)
term.setCursorPos(math.floor(w/2) - 8, math.floor(h/2) + 3)
term.write("ENTER=Restart Q=Quit")
end
-- Win screen
local function showWin()
term.setBackgroundColor(colors.black)
term.setTextColor(colors.lime)
term.setCursorPos(math.floor(w/2) - 4, math.floor(h/2))
term.write("YOU WIN!")
term.setTextColor(colors.white)
term.setCursorPos(math.floor(w/2) - 6, math.floor(h/2) + 1)
term.write("Score: " .. score)
term.setCursorPos(math.floor(w/2) - 8, math.floor(h/2) + 3)
term.write("ENTER=Restart Q=Quit")
end
-- Main game loop
local function run()
initBricks()
resetBall()
score = 0
lives = 3
gameOver = false
gameWon = false
paddleX = math.floor(w/2) - 3
while true do
draw()
if gameOver then
showGameOver()
elseif gameWon then
showWin()
end
local timer = os.startTimer(speed)
while true do
local event, p1 = os.pullEvent()
if event == "key" then
if gameOver or gameWon then
if p1 == keys.enter then
initBricks()
resetBall()
score = 0
lives = 3
gameOver = false
gameWon = false
paddleX = math.floor(w/2) - 3
break
elseif p1 == keys.q then
return
end
else
if p1 == keys.left then
paddleX = math.max(1, paddleX - 2)
elseif p1 == keys.right then
paddleX = math.min(w - paddleWidth, paddleX + 2)
elseif p1 == keys.space then
ballActive = true
elseif p1 == keys.q then
return
end
end
if not (gameOver or gameWon) then
draw()
end
elseif event == "timer" and p1 == timer then
break
end
end
if not (gameOver or gameWon) then
update()
end
end
end
run()