singe/docs/learn/11-hitting-things.singe
2026-09-22 21:57:42 -05:00

188 lines
4.2 KiB
Text

-- Lesson 11: Hitting Things. 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 SHOT_WIDTH = 4
local SHOT_HEIGHT = 10
local SHOT_SPEED = 6
local SHOW_BOXES = false
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 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 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)
break
end
end
end
for r = #rocks, 1, -1 do
if shipHitsRock(rocks[r]) then
table.remove(rocks, r)
soundPlay(boomSound)
end
end
end
local function drawBox(x, y, width, height)
overlayBox(x, y, x + width - 1, y + height - 1)
end
local function drawBoxes()
colorForeground(0, 255, 0, 255)
drawBox(shipBox())
for _, rock in ipairs(rocks) do
drawBox(rockBox(rock))
end
end
function onInputPressed(what)
if what == SWITCH_LEFT then
movingLeft = true
elseif what == SWITCH_RIGHT then
movingRight = true
elseif what == SWITCH_BUTTON1 then
fireShot()
end
end
function onInputReleased(what)
if what == SWITCH_LEFT then
movingLeft = false
elseif what == SWITCH_RIGHT then
movingRight = false
end
end
function onOverlayUpdate()
overlayClear()
moveShip()
moveRocks()
moveShots()
checkHits()
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
if SHOW_BOXES then
drawBoxes()
end
return OVERLAY_UPDATED
end