249 lines
5.5 KiB
Text
249 lines
5.5 KiB
Text
-- Lesson 12: Score, Lives, And Game Over. The finished script, exactly as the lesson ends.
|
|
dofile("Singe/Framework.singe")
|
|
|
|
local SHIP_WIDTH = 32
|
|
local SHIP_HEIGHT = 24
|
|
local SHIP_PAD_X = 6
|
|
local SHIP_PAD_Y = 5
|
|
local SHIP_SPEED = 3
|
|
local ROCK_WIDTH = 24
|
|
local ROCK_HEIGHT = 24
|
|
local ROCK_PAD = 4
|
|
local ROCK_SPEED = 1
|
|
local ROCK_CHANCE = 40
|
|
local ROCK_POINTS = 10
|
|
local SHOT_WIDTH = 4
|
|
local SHOT_HEIGHT = 10
|
|
local SHOT_SPEED = 6
|
|
local START_LIVES = 3
|
|
|
|
local TITLE = "title"
|
|
local PLAYING = "playing"
|
|
local OVER = "over"
|
|
|
|
local shipSprite = spriteLoad(DIR .. "art/ship.png")
|
|
local rockSprite = spriteLoad(DIR .. "art/rock.png")
|
|
local shotSprite = spriteLoad(DIR .. "art/shot.png")
|
|
local shootSound = soundLoad(DIR .. "art/shoot.wav")
|
|
local boomSound = soundLoad(DIR .. "art/boom.wav")
|
|
|
|
local state = TITLE
|
|
local score = 0
|
|
local lives = START_LIVES
|
|
local best = saveGet("highScore", 0)
|
|
local shipX = (overlayGetWidth() - SHIP_WIDTH) / 2
|
|
local shipY = overlayGetHeight() - SHIP_HEIGHT - 8
|
|
local movingLeft = false
|
|
local movingRight = false
|
|
local rocks = {}
|
|
local shots = {}
|
|
|
|
|
|
local function addRock()
|
|
local rock = {}
|
|
rock.x = math.random(0, overlayGetWidth() - ROCK_WIDTH)
|
|
rock.y = -ROCK_HEIGHT
|
|
rocks[#rocks + 1] = rock
|
|
end
|
|
|
|
|
|
local function fireShot()
|
|
local shot = {}
|
|
shot.x = shipX + SHIP_WIDTH / 2 - SHOT_WIDTH / 2
|
|
shot.y = shipY - SHOT_HEIGHT
|
|
shots[#shots + 1] = shot
|
|
soundPlay(shootSound)
|
|
end
|
|
|
|
|
|
local function rockBox(rock)
|
|
return rock.x + ROCK_PAD, rock.y + ROCK_PAD, ROCK_WIDTH - ROCK_PAD * 2, ROCK_HEIGHT - ROCK_PAD * 2
|
|
end
|
|
|
|
|
|
local function shipBox()
|
|
return shipX + SHIP_PAD_X, shipY + SHIP_PAD_Y, SHIP_WIDTH - SHIP_PAD_X * 2, SHIP_HEIGHT - SHIP_PAD_Y * 2
|
|
end
|
|
|
|
|
|
local function shipHitsRock(rock)
|
|
local sx, sy, sw, sh = shipBox()
|
|
local rx, ry, rw, rh = rockBox(rock)
|
|
return collideRects(sx, sy, sw, sh, rx, ry, rw, rh)
|
|
end
|
|
|
|
|
|
local function shotHitsRock(shot, rock)
|
|
local rx, ry, rw, rh = rockBox(rock)
|
|
return collidePointRect(shot.x + SHOT_WIDTH / 2, shot.y, rx, ry, rw, rh)
|
|
end
|
|
|
|
|
|
local function startGame()
|
|
score = 0
|
|
lives = START_LIVES
|
|
rocks = {}
|
|
shots = {}
|
|
shipX = (overlayGetWidth() - SHIP_WIDTH) / 2
|
|
movingLeft = false
|
|
movingRight = false
|
|
state = PLAYING
|
|
end
|
|
|
|
|
|
local function endGame()
|
|
if score > best then
|
|
best = score
|
|
saveSet("highScore", best)
|
|
saveFlush()
|
|
end
|
|
state = OVER
|
|
end
|
|
|
|
|
|
local function moveShip()
|
|
if movingLeft then
|
|
shipX = shipX - SHIP_SPEED
|
|
end
|
|
if movingRight then
|
|
shipX = shipX + SHIP_SPEED
|
|
end
|
|
if shipX < 0 then
|
|
shipX = 0
|
|
end
|
|
if shipX > overlayGetWidth() - SHIP_WIDTH then
|
|
shipX = overlayGetWidth() - SHIP_WIDTH
|
|
end
|
|
end
|
|
|
|
|
|
local function moveRocks()
|
|
if math.random(ROCK_CHANCE) == 1 then
|
|
addRock()
|
|
end
|
|
for i = #rocks, 1, -1 do
|
|
local rock = rocks[i]
|
|
rock.y = rock.y + ROCK_SPEED
|
|
if rock.y > overlayGetHeight() then
|
|
table.remove(rocks, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function moveShots()
|
|
for i = #shots, 1, -1 do
|
|
local shot = shots[i]
|
|
shot.y = shot.y - SHOT_SPEED
|
|
if shot.y + SHOT_HEIGHT < 0 then
|
|
table.remove(shots, i)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function checkHits()
|
|
for s = #shots, 1, -1 do
|
|
for r = #rocks, 1, -1 do
|
|
if shotHitsRock(shots[s], rocks[r]) then
|
|
table.remove(rocks, r)
|
|
table.remove(shots, s)
|
|
soundPlay(boomSound)
|
|
score = score + ROCK_POINTS
|
|
break
|
|
end
|
|
end
|
|
end
|
|
for r = #rocks, 1, -1 do
|
|
if shipHitsRock(rocks[r]) then
|
|
table.remove(rocks, r)
|
|
soundPlay(boomSound)
|
|
lives = lives - 1
|
|
if lives <= 0 then
|
|
endGame()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function drawWorld()
|
|
spriteDraw(shipSprite, shipX, shipY)
|
|
for _, rock in ipairs(rocks) do
|
|
spriteDraw(rockSprite, rock.x, rock.y)
|
|
end
|
|
for _, shot in ipairs(shots) do
|
|
spriteDraw(shotSprite, shot.x, shot.y)
|
|
end
|
|
end
|
|
|
|
|
|
local function drawScore()
|
|
overlayPrint(1, 1, "SCORE " .. score)
|
|
overlayPrint(25, 1, "BEST " .. best)
|
|
overlayPrint(48, 1, "LIVES " .. lives)
|
|
end
|
|
|
|
|
|
local function updateTitle()
|
|
overlayPrint(25, 5, "R O C K S")
|
|
overlayPrint(24, 8, "BEST " .. best)
|
|
overlayPrint(21, 11, "PRESS FIRE TO PLAY")
|
|
end
|
|
|
|
|
|
local function updatePlaying()
|
|
moveShip()
|
|
moveRocks()
|
|
moveShots()
|
|
checkHits()
|
|
drawWorld()
|
|
drawScore()
|
|
end
|
|
|
|
|
|
local function updateOver()
|
|
drawWorld()
|
|
drawScore()
|
|
overlayPrint(25, 8, "GAME OVER")
|
|
overlayPrint(21, 11, "PRESS FIRE TO PLAY")
|
|
end
|
|
|
|
|
|
function onInputPressed(what)
|
|
if state == PLAYING then
|
|
if what == SWITCH_LEFT then
|
|
movingLeft = true
|
|
elseif what == SWITCH_RIGHT then
|
|
movingRight = true
|
|
elseif what == SWITCH_BUTTON1 then
|
|
fireShot()
|
|
end
|
|
elseif what == SWITCH_BUTTON1 or what == SWITCH_START1 then
|
|
startGame()
|
|
end
|
|
end
|
|
|
|
|
|
function onInputReleased(what)
|
|
if what == SWITCH_LEFT then
|
|
movingLeft = false
|
|
elseif what == SWITCH_RIGHT then
|
|
movingRight = false
|
|
end
|
|
end
|
|
|
|
|
|
function onOverlayUpdate()
|
|
overlayClear()
|
|
|
|
if state == TITLE then
|
|
updateTitle()
|
|
elseif state == PLAYING then
|
|
updatePlaying()
|
|
else
|
|
updateOver()
|
|
end
|
|
|
|
return OVERLAY_UPDATED
|
|
end
|