singe/docs/learn/17-light-guns.singe
2026-09-22 21:57:42 -05:00

123 lines
2.8 KiB
Text

-- Learn to Program with Singe -- Lesson 17: Light Guns
dofile("Singe/Framework.singe")
overlaySetResolution(discGetWidth(), discGetHeight())
local FIRST_FRAME = 20
local LAST_FRAME = 400
local TARGET_SIZE = 96
local HIT_SCORE = 100
local FLASH_TIME = 12
local targets = {
{ first = 40, last = 110, x = 80, y = 110 },
{ first = 120, last = 190, x = 470, y = 140 },
{ first = 200, last = 270, x = 290, y = 250 },
{ first = 280, last = 360, x = 150, y = 300 },
}
local aimX = overlayGetWidth() / 2
local aimY = overlayGetHeight() / 2
local score = 0
local shots = 0
local hits = 0
local flash = 0
local flashX = 0
local flashY = 0
local drawAim = singeWantsCrosshairs()
local function drawCrosshair(x, y)
colorForeground(255, 255, 255, 255)
overlayCircle(x, y, 10)
overlayLine(x - 18, y, x - 4, y)
overlayLine(x + 4, y, x + 18, y)
overlayLine(x, y - 18, x, y - 4)
overlayLine(x, y + 4, x, y + 18)
end
local function targetIsUp(target, frame)
return not target.hit and frame >= target.first and frame <= target.last
end
local function startRound()
score = 0
shots = 0
hits = 0
flash = 0
for _, target in ipairs(targets) do
target.hit = false
end
discSkipToFrame(FIRST_FRAME)
end
function onInputPressed(what, device)
if what == SWITCH_START1 then
startRound()
return
end
if what ~= SWITCH_BUTTON3 then
return
end
local x, y = mouseGetPosition(device or 0)
local frame = discGetFrame()
shots = shots + 1
for _, target in ipairs(targets) do
if targetIsUp(target, frame) and collidePointRect(x, y, target.x, target.y, TARGET_SIZE, TARGET_SIZE) then
target.hit = true
hits = hits + 1
score = score + HIT_SCORE
flash = FLASH_TIME
flashX = x
flashY = y
return
end
end
end
function onOverlayUpdate()
local frame = discGetFrame()
if frame >= LAST_FRAME then
startRound()
frame = FIRST_FRAME
end
aimX, aimY = mouseGetPosition(0)
overlayClear()
for _, target in ipairs(targets) do
if targetIsUp(target, frame) then
colorForeground(255, 200, 0, 255)
overlayBox(target.x, target.y, target.x + TARGET_SIZE - 1, target.y + TARGET_SIZE - 1)
overlayCircle(target.x + TARGET_SIZE / 2, target.y + TARGET_SIZE / 2, TARGET_SIZE / 3)
end
end
if flash > 0 then
colorForeground(255, 255, 255, 255)
overlayCircle(flashX, flashY, 30 - flash * 2)
flash = flash - 1
end
overlayPrint(2, 1, "SCORE " .. score .. " HITS " .. hits .. "/" .. shots .. " FRAME " .. frame)
if drawAim then
drawCrosshair(aimX, aimY)
end
return OVERLAY_UPDATED
end
startRound()