let state: string let timer: number let gesturesRunning: boolean let wasShake: boolean let wasLogoUp: boolean let wasLogoDown: boolean let wasScreenUp: boolean let wasScreenDown: boolean while (true) { splashScreen() if (input.buttonIsPressed(Button.B)) { // animate: add pancake basic.showAnimation(` # # # # # # . . . # . . . . . . . . . . . . . . . . . . . . . # # # . . # # # . . . . . . . . . . . . . . . . . . . . . # . . . # # . . . # . . . . . . . . . . . . . . . . . . . . . # # # . . # # # . . . . . . . . . . . . . . . . . . . . . # . . . # `, 250) runGameOnce() // animate: pancake done basic.showAnimation(` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . # # # # # # # . . . # . . . . . . . . . . . # . # . . . . . . . # . # . . . . . . . . . . . . . . . . . # # # . # # # # # . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . # # # # # # # . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . `, 250) } else if (input.buttonIsPressed(Button.A)) { testShake() } } /** * Runs one complete game from start to end */ function runGameOnce() { let score = 0 let cooks = 0 let target_time = 0 // make sure no gestures are outstanding from last game wasShake = false wasLogoUp = false wasLogoDown = false wasScreenUp = false wasScreenDown = false state = "NEWSIDE" while (true) { // Handle any gestures that can happen at any time let gesture = getGesture() if (gesture == "FLOOR") { state = "DROPPED" } // Run code appropriate to the present state of the game if (state == "NEWSIDE") { target_time = 5 + Math.random(5) state = "COOKING" startTimer() } else if (state == "COOKING") { // animate: cooking basic.showAnimation(` . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # # # # # . # # # # # # # # # # # # # . `, 100) if (gesture == "FLIP") { state = "FLIPPING" } else if (getTimerSec() >= target_time) { state = "READY" score = score + 1 startTimer() } } else if (state == "READY") { // animate: ready basic.showAnimation(` . . . . . . . . . . . . . . . # . . . # . # # # . `, 100) if (getTimerSec() > 2) { state = "BURNING" score = score - 1 startTimer() } else if (gesture == "FLIP") { state = "FLIPPING" } } else if (state == "BURNING") { // animate: burning basic.showAnimation(` . . . . . . . . . . . . . # . . . . # . . . . . . . . . # . . # . # . . # . . . . . . . . . # . # . . # . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # # # # # # # # # # # # # # # # # # # `, 100) if (gesture == "SKY") { state = "NEWSIDE" } else if (getTimerSec() > 2) { state = "BURNT" } } else if (state == "FLIPPING") { // animate: flipping basic.showAnimation(` . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # # # . # # . . . # # # . . . # # . # # # # # . . . . . . . . . . . . . . . . . . . . # # # # # . . . . . . . . # # . # # # . # # . . . . . . . . # # # # # . . . . . . . . . . # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # # # # # # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . `, 100) // Prevent a spurious double-flip from happening wasShake = false cooks = cooks + 1 if (cooks == 5) { state = "GAMEOVER" } else { state = "NEWSIDE" } } else if (state == "DROPPED") { // animate: dropped basic.showAnimation(` # . . . # . . . . . # . . . # . . . . . . # . # . . . . . . . # . # . . . . . . . . # . . . . . . . . . # . . . . . . . . # . # . . . . . . . # . # . . . . . . # . . . # . . . . . # . . . # . . . . . `, 250) score = 0 state = "GAMEOVER" } else if (state == "BURNT") { // animate: burnt basic.showAnimation(` . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . # . # . . . . . . . # # # . . . . . . . . . . . . . . . . . . # . . . . . . . . # . # . . . . . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . # # # . . . . . . . . . . . . . . . . . # . # . . # # # . . # . # . . . . . . . # # # . . . . . . . . . . . . . . . . # # # # # . # # # . . # # # . . # # # . . # # # . . . . . . . . . . . . . . . . . . . . . `, 250) score = 0 state = "GAMEOVER" } else if (state == "GAMEOVER") { animateScore(score) state = "WAITEJECT" } else if (state == "WAITEJECT") { if (gesture == "UPSIDEDOWN") { return } } } } /** * show score (0..9) flashing * @param score TODO */ function animateScore(score: number) { score = Math.clamp(0, 9, score) for (let i = 0; i < 5; i++) { basic.showNumber(score, 0) basic.pause(500) basic.clearScreen() basic.pause(500) } basic.showNumber(score, 0) } /** * NOTE: Eventually this will move into a gesture library * It hides all the nasty detail of detecting gestures */ function getGesture(): string { if (!gesturesRunning) { input.onShake(() => { wasShake = true }) input.onLogoUp(() => { wasLogoUp = true }) input.onLogoDown(() => { wasLogoDown = true }) input.onScreenUp(() => { wasScreenUp = true }) input.onScreenDown(() => { wasScreenDown = true }) gesturesRunning = true } // work out which of a possible set of gestures has occurred: // Button gestures and movement gestures both handled // This is so that it is easy to also use this on the simulator too // Generally, B is used for normal OK, A is used for abnormal RECOVERY // (flip is a normal action, touch sky to turn off smoke alarm is recovery) let a = input.buttonIsPressed(Button.A) let b = input.buttonIsPressed(Button.B) if (state == "COOKING" || state == "READY") { if (b || wasShake) { wasShake = false return "FLIP" } } else if (state == "FLIPPING") { if (a || wasLogoDown) { wasLogoDown = false return "FLOOR" } } else if (state == "BURNING") { if (a || wasLogoUp) { wasLogoUp = false return "SKY" } } else if (state == "GAMEOVER" || state == "WAITEJECT") { if (b || wasScreenDown) { wasScreenDown = false return "UPSIDEDOWN" } } return "NONE" } /** * start timer by sampling runningtime and storing into starttime */ function startTimer() { timer = input.runningTime() } /** * get the elapsed time from the global starttime with ref to running time * in seconds. */ function getTimerSec(): number { let t = (input.runningTime() - timer) / 1000 return t } /** * Show a splash screen "Perfect Pancakes >>>" * Splash screen "PP" with little arrow pointing to the start button */ function splashScreen() { let splash = images.createImage(` # # # # . . . . . . # # # # . . . . . . . . . . . . . . . . . . . . . # . . . # . . . . . # . . . # # . . . . . # . . . . . # . . . . . # . # # # # . . . . . . # # # # . . # . . . . . # . . . . . # . . . . . # # . . . . . . . . . # . . . . # . . . . . # . . . . . # . . . . . # . # . . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . `) // use show image (not show animation) so that button press is more responsive let index = 0 // Any button press finishes the splash screen while (!input.buttonIsPressed(Button.B) && !input.buttonIsPressed(Button.A)) { splash.showImage(index * 5) index = index + 1 if (index > splash.width() / 5) { index = 0 } basic.pause(250) } } function testShake() { }