-- Learn to Program with Singe -- Lesson 18: Quick-Time Events dofile("Singe/Framework.singe") overlaySetResolution(discGetWidth(), discGetHeight()) local FIRST_FRAME = 20 local WRONG_FRAME = 362 local LATE_FRAME = 388 local LAST_FRAME = 415 local PROMPT_COL = 54 local PROMPT_ROW = 22 local GAUGE_X = 210 local GAUGE_Y = 330 local GAUGE_W = 300 local GAUGE_H = 18 local RIGHT_SCORE = 100 local moves = { { first = 60, last = 105, switch = SWITCH_LEFT, name = "LEFT" }, { first = 140, last = 185, switch = SWITCH_UP, name = "UP" }, { first = 220, last = 265, switch = SWITCH_RIGHT, name = "RIGHT" }, { first = 300, last = 345, switch = SWITCH_DOWN, name = "DOWN" }, } local score = 0 local runOver = false local verdict = "" local function fillBar(x, y, width, height) if width < 1 then return end for row = 0, height - 1 do overlayLine(x, y + row, x + width - 1, y + row) end end local function isDirection(what) return what == SWITCH_UP or what == SWITCH_DOWN or what == SWITCH_LEFT or what == SWITCH_RIGHT end local function moveAt(frame) for _, move in ipairs(moves) do if move.answer == nil and frame >= move.first and frame <= move.last then return move end end return nil end local function startRun() score = 0 runOver = false verdict = "" for _, move in ipairs(moves) do move.answer = nil end discSkipToFrame(FIRST_FRAME) end local function endRun(reason, frame) verdict = reason runOver = true discSkipToFrame(frame) end function onInputPressed(what) if runOver then if what == SWITCH_START1 then startRun() end return end if not isDirection(what) then return end local move = moveAt(discGetFrame()) if move == nil then return end if what == move.switch then move.answer = "right" score = score + RIGHT_SCORE else move.answer = "wrong" endRun("WRONG WAY", WRONG_FRAME) end end function onOverlayUpdate() local frame = discGetFrame() if not runOver then for _, move in ipairs(moves) do if move.answer == nil and frame > move.last then move.answer = "late" endRun("TOO SLOW", LATE_FRAME) break end end end if frame >= LAST_FRAME and discGetState() == DISC_PLAYING then if not runOver then verdict = "CLEAR" runOver = true end discSearch(LAST_FRAME) end overlayClear() local move = nil if not runOver then move = moveAt(frame) end if move ~= nil then local left = move.last - frame local span = move.last - move.first overlayPrint(PROMPT_COL, PROMPT_ROW, "PRESS " .. move.name) colorForeground(255, 255, 255, 255) overlayBox(GAUGE_X - 2, GAUGE_Y - 2, GAUGE_X + GAUGE_W + 1, GAUGE_Y + GAUGE_H + 1) if left * 3 < span then colorForeground(255, 60, 60, 255) else colorForeground(255, 200, 0, 255) end fillBar(GAUGE_X, GAUGE_Y, GAUGE_W * left // span, GAUGE_H) end overlayPrint(2, 1, "SCORE " .. score .. " FRAME " .. frame) if runOver then overlayPrint(2, 3, verdict) overlayPrint(2, 4, "PRESS 1 TO RUN IT AGAIN") end return OVERLAY_UPDATED end startRun()