User prompt
New drink toggle: no drink, bird drink, drink 2
User prompt
New drink for toggle, do not say FAILURE: Integration failed, target source not found. Please try again.
User prompt
Make all pipes be random flip orientation but always point up and down
User prompt
Please fix the bug: 'ReferenceError: birdDrinkSprite is not defined' in or related to this line: 'storage.lastDrink = bird && birdDrinkSprite && birdDrinkSprite.visible ? true : false;' Line Number: 294
User prompt
Make save when death so keep score and drink work ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make save when death so keep score and drink ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make save when death ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Use game death screen instead of pre-made
User prompt
Make save when death ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Add pause asset
User prompt
I MEANT TO FIX PAUSE VISIBILITY
User prompt
Where is pause fix it
User prompt
Add pause button
User prompt
In front of bird, not replacing
User prompt
Add bird drink toggle in top right, toggles drink in front of bird
User prompt
MAKE SHOP BUTTON VISIBLE
User prompt
Replace with shopbutton asset and make it be only is game over under tap to restart text
User prompt
Replace upit game over with game's game over, and shop button to shop, other place to restart.
User prompt
Bird drink should just be right in front of bird when on. Also make shop button seeable
User prompt
Add shop, bird drink for 10 score, score saves per death. Bird drink togglable on and off in shop ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Make everything slower
User prompt
Make falling slower
Code edit (1 edits merged)
Please save this source code
User prompt
Flappy Bird: Pipe Dash
Initial prompt
Make flappy bird, exact code from random import randint class FlappyBirdGame: def __init__(self): self.reset() def reset(self): self.bird_y = 300 self.bird_vy = 0 self.gravity = 0.5 self.jump_power = -8 self.bird_radius = 20 self.pipes = [] self.pipe_gap = 160 self.pipe_width = 60 self.pipe_speed = 4 self.pipe_timer = 0 self.score = 0 self.alive = True def on_touch(self, x, y): if self.alive: self.bird_vy = self.jump_power else: self.reset() def update(self): if not self.alive: return # Bird physics self.bird_vy += self.gravity self.bird_y += self.bird_vy # Floor and ceiling collision if self.bird_y < 0 or self.bird_y > 600: self.alive = False # Pipe movement for pipe in self.pipes: pipe['x'] -= self.pipe_speed # Remove off-screen pipes self.pipes = [pipe for pipe in self.pipes if pipe['x'] + self.pipe_width > 0] # Pipe generation self.pipe_timer += 1 if self.pipe_timer >= 90: gap_y = randint(100, 500) self.pipes.append({'x': 800, 'gap_y': gap_y}) self.pipe_timer = 0 # Collision detection & scoring bird_x = 100 for pipe in self.pipes: if pipe['x'] < bird_x < pipe['x'] + self.pipe_width: if not (pipe['gap_y'] - self.pipe_gap/2 < self.bird_y < pipe['gap_y'] + self.pipe_gap/2): self.alive = False if pipe['x'] + self.pipe_width == bird_x: self.score += 1 def draw(self, canvas): # Background canvas.color(135, 206, 235) # Sky blue canvas.rect(0, 0, 800, 600) # Bird canvas.color(255, 255, 0) # Yellow canvas.circle(100, self.bird_y, self.bird_radius) # Pipes canvas.color(34, 139, 34) # Green for pipe in self.pipes: top = pipe['gap_y'] - self.pipe_gap / 2 bottom = pipe['gap_y'] + self.pipe_gap / 2 canvas.rect(pipe['x'], 0, self.pipe_width, top) canvas.rect(pipe['x'], bottom, self.pipe_width, 600 - bottom) # Score canvas.color(0, 0, 0) canvas.text(str(self.score), 20, 20, size=30) # Game over if not self.alive: canvas.text("Game Over", 300, 250, size=40) canvas.text("Tap to restart", 280, 300, size=25)
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); var birdSprite = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); var birdDrinkSprite = self.attachAsset('Bird_drink', { anchorX: 0.5, anchorY: 0.5, visible: false }); var drink2Sprite = self.attachAsset('Drink_2', { anchorX: 0.5, anchorY: 0.5, visible: false }); var drink3Sprite = self.attachAsset('Drink3', { anchorX: 0.5, anchorY: 0.5, visible: false }); // Position drink in front of bird birdDrinkSprite.x = birdSprite.width * 0.7; // Offset to the right (in front) drink2Sprite.x = birdDrinkSprite.x; // Align drink2Sprite with birdDrinkSprite drink3Sprite.x = birdDrinkSprite.x; // Align drink3Sprite with birdDrinkSprite self.currentSprite = birdSprite; self.radius = birdSprite.width * 0.5 * 0.85; // for collision self.vy = 0; // vertical speed self.gravity = 0.6; // gravity per frame (slower fall) self.flapStrength = -22; // negative = up, less strong flap // Flap method self.flap = function () { self.vy = self.flapStrength; LK.getSound('flap').play(); }; // Toggle drink method self.toggleDrink = function () { // Cycle through no drink, bird drink, drink 2, and drink 3 if (!birdDrinkSprite.visible && !drink2Sprite.visible && !drink3Sprite.visible) { birdDrinkSprite.visible = true; drink2Sprite.visible = false; drink3Sprite.visible = false; } else if (birdDrinkSprite.visible) { birdDrinkSprite.visible = false; drink2Sprite.visible = true; drink3Sprite.visible = false; } else if (drink2Sprite.visible) { birdDrinkSprite.visible = false; drink2Sprite.visible = false; drink3Sprite.visible = true; } else { birdDrinkSprite.visible = false; drink2Sprite.visible = false; drink3Sprite.visible = false; } // Save the current drink state to storage storage.lastDrink = birdDrinkSprite.visible ? 1 : drink2Sprite.visible ? 2 : 0; }; // Update method self.update = function () { self.vy += self.gravity * (slowTimeActive ? slowTimeMultiplier : 1); self.y += self.vy; // Rotate bird based on velocity (visual only) var maxAngle = Math.PI / 4; var minAngle = -Math.PI / 6; var angle = self.vy / 40 * maxAngle; if (angle > maxAngle) angle = maxAngle; if (angle < minAngle) angle = minAngle; birdSprite.rotation = angle; // Keep drink upright and in front birdDrinkSprite.rotation = 0; }; return self; }); // Fire class for standalone fire effects var Fire = Container.expand(function () { var self = Container.call(this); var fireSprite = self.attachAsset('fire', { anchorX: 0.5, anchorY: 0.5, visible: false, alpha: 0.5 }); self.shootFire = function () { fireSprite.visible = true; fireSprite.x = 0; // Reset position when shooting fireSprite.y = 0; tween(fireSprite, { alpha: 1 }, { duration: 500, easing: tween.linear, onFinish: function onFinish() { tween(fireSprite, { alpha: 0.5 }, { duration: 500, easing: tween.linear }); } }); }; self.getBoundingRect = function () { if (!fireSprite.visible) return null; return { x: self.x + fireSprite.x - fireSprite.width * 0.5, y: self.y + fireSprite.y - fireSprite.height * 0.5, width: fireSprite.width, height: fireSprite.height }; }; self.update = function () { if (fireSprite.visible) { fireSprite.x -= pipeSpeed; if (fireSprite.x < -fireSprite.width) { fireSprite.visible = false; } } }; return self; }); var FirePipe = Container.expand(function () { var self = Container.call(this); var firePipeSprite = self.attachAsset('FirePipe', { anchorX: 0.5, anchorY: 0.5, visible: true, alpha: 1 }); self.movingRight = true; // Track movement direction self.startMovement = function () { // Start continuous left-right movement self.moveLeftRight(); }; self.moveLeftRight = function () { // Check if this pipe is frozen if (self.frozen) return; var targetX = self.movingRight ? 300 : -300; // Move 300px in each direction tween(firePipeSprite, { x: targetX }, { duration: 2000, // 2 seconds to move in one direction easing: tween.easeInOut, onFinish: function onFinish() { // Reverse direction and continue moving self.movingRight = !self.movingRight; self.moveLeftRight(); } }); }; self.freeze = function () { self.frozen = true; // Add visual effect for frozen state tween(firePipeSprite, { tint: 0x88ccff }, { duration: 300, easing: tween.easeOut }); }; self.unfreeze = function () { self.frozen = false; // Remove visual effect tween(firePipeSprite, { tint: 0xffffff }, { duration: 300, easing: tween.easeOut }); // Resume movement self.moveLeftRight(); }; self.getBoundingRect = function () { if (!firePipeSprite.visible) return null; return { x: self.x + firePipeSprite.x - firePipeSprite.width * 0.5, y: self.y + firePipeSprite.y - firePipeSprite.height * 0.5, width: firePipeSprite.width, height: firePipeSprite.height }; }; self.update = function () { // Movement is now handled by tween }; return self; }); // PipePair class (top and bottom pipes) var PipePair = Container.expand(function () { var self = Container.call(this); // Pipe config var pipeWidth = 200; var pipeHeight = 1200; var gapHeight = 480; // vertical gap between pipes // Randomly decide if pipes are flipped (top/bottom swap orientation) var flip = Math.random() < 0.5; // Randomly decide pipe type: normal (70%) or fire (30%) var isFirePipe = Math.random() < 0.3; // For fire pipes, always single pipe. For regular pipes, 30% chance of single pipe var isSinglePipe = isFirePipe || Math.random() < 0.3; var pipeAsset = isFirePipe ? 'FirePipe' : 'pipe'; var topPipe = null; var bottomPipe = null; // Create pipes based on configuration if (isSinglePipe) { // Single pipe - randomly choose top or bottom position var isTopPosition = Math.random() < 0.5; if (isTopPosition) { topPipe = self.attachAsset(pipeAsset, { anchorX: 0, anchorY: flip ? 0 : 1, width: pipeWidth, height: pipeHeight, rotation: flip ? Math.PI : 0 }); } else { bottomPipe = self.attachAsset(pipeAsset, { anchorX: 0, anchorY: flip ? 1 : 0, width: pipeWidth, height: pipeHeight, rotation: flip ? Math.PI : 0 }); } } else { // Double pipes (traditional setup) topPipe = self.attachAsset(pipeAsset, { anchorX: 0, anchorY: flip ? 0 : 1, width: pipeWidth, height: pipeHeight, rotation: flip ? Math.PI : 0 }); bottomPipe = self.attachAsset(pipeAsset, { anchorX: 0, anchorY: flip ? 1 : 0, width: pipeWidth, height: pipeHeight, rotation: flip ? Math.PI : 0 }); } self.pipeWidth = pipeWidth; self.gapHeight = gapHeight; self.passed = false; // for scoring self.isFirePipe = isFirePipe; self.isSinglePipe = isSinglePipe; self.fireTimer = 0; self.topPipe = topPipe; self.bottomPipe = bottomPipe; // Set pipes' vertical positions based on gapY (top of gap) self.setGap = function (gapY) { // gapY: y position of top of gap if (topPipe) topPipe.y = gapY; if (bottomPipe) bottomPipe.y = gapY + gapHeight; }; // Move pipes left self.update = function () { self.x -= pipeSpeed; }; // Get bounding rects for collision self.getTopRect = function () { if (!topPipe) return null; return { x: self.x, y: topPipe.y - pipeHeight, width: pipeWidth, height: pipeHeight }; }; self.getBottomRect = function () { if (!bottomPipe) return null; return { x: self.x, y: bottomPipe.y, width: pipeWidth, height: pipeHeight }; }; // Add fire shooting capability for fire pipes if (isFirePipe) { var firePipe = new FirePipe(); self.addChild(firePipe); self.firePipe = firePipe; self.fireStarted = false; // Track if fire has been started } self.update = function () { self.x -= pipeSpeed * (slowTimeActive ? slowTimeMultiplier : 1); // Update fire pipe if this is a fire pipe if (self.isFirePipe && self.firePipe) { self.firePipe.x = self.x; // Position fire at pipe position // Center fire in the gap or at pipe level for single pipes var fireY = bottomPipe ? bottomPipe.y - gapHeight / 2 : topPipe ? topPipe.y + gapHeight / 2 : 1366; self.firePipe.y = fireY; self.firePipe.update(); // Start movement when pipe enters screen (only once) if (!self.fireStarted && self.x < 2048) { self.fireStarted = true; // Check if power-up is active and freeze immediately if (slowTimeActive) { self.firePipe.freeze(); frozenPipes.push(self.firePipe); } else { self.firePipe.startMovement(); } } } }; return self; }); // PowerUp class var PowerUp = Container.expand(function () { var self = Container.call(this); // Create a star-shaped power-up visual using new asset var powerUpSprite = self.attachAsset('powerUpStar', { anchorX: 0.5, anchorY: 0.5, tint: 0x00ffff // Cyan color for freeze power-up }); // Add pulsing effect self.pulse = function () { tween(powerUpSprite, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(powerUpSprite, { scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { self.pulse(); } }); } }); }; self.collected = false; self.update = function () { if (!self.collected) { self.x -= pipeSpeed * (slowTimeActive ? slowTimeMultiplier : 1); } }; self.getBoundingRect = function () { return { x: self.x - powerUpSprite.width * 0.5, y: self.y - powerUpSprite.height * 0.5, width: powerUpSprite.width, height: powerUpSprite.height }; }; // Start pulsing animation self.pulse(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // sky blue }); /**** * Game Code ****/ // Sound: Hit // Sound: Score // Sound: Flap // Ground: brown box // Pipe: green box // Bird: yellow ellipse // Game constants var BIRD_START_X = 600; var BIRD_START_Y = 1200; var PIPE_INTERVAL = 1300; // px between pipes horizontally (slower spawn rate) var PIPE_MIN_Y = 350; // min y for top of gap var PIPE_MAX_Y = 1800; // max y for top of gap var GROUND_Y = 2732 - 120; // ground top y var pipeSpeed = 8; // px per frame (slower pipes) var POWERUP_DURATION = 30000; // 30 seconds in milliseconds var slowTimeMultiplier = 0.3; // 30% speed during slow time // Game state var bird; var pipes = []; var powerUps = []; var ground; var score = 0; var scoreTxt; var gameOver = false; var started = false; var lastPipeX = 0; var slowTimeActive = false; var slowTimeTimer = null; var frozenPipes = []; // GUI: Score scoreTxt = new Text2('0', { size: 160, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // GUI: Game Over text var gameOverTxt = new Text2('Game Over', { size: 180, fill: 0xFF4444 }); gameOverTxt.anchor.set(0.5, 0.5); gameOverTxt.visible = false; LK.gui.center.addChild(gameOverTxt); // GUI: Tap to restart var restartTxt = new Text2('Tap to restart', { size: 100, fill: 0xFFFFFF }); restartTxt.anchor.set(0.5, 0.5); restartTxt.visible = false; LK.gui.center.addChild(restartTxt); // GUI: Drink toggle button var drinkToggleBtn = new Container(); var drinkBtnBg = drinkToggleBtn.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150, tint: 0x4444ff }); var drinkBtnText = new Text2('🥤', { size: 80, fill: 0xFFFFFF }); drinkBtnText.anchor.set(0.5, 0.5); drinkToggleBtn.addChild(drinkBtnText); drinkToggleBtn.x = -100; drinkToggleBtn.y = 100; LK.gui.topRight.addChild(drinkToggleBtn); // GUI: Reset score button var resetScoreBtn = new Container(); var resetBtnBg = resetScoreBtn.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150, tint: 0xff4444 }); var resetBtnText = new Text2('Ø', { size: 100, fill: 0xFFFFFF }); resetBtnText.anchor.set(0.5, 0.5); resetScoreBtn.addChild(resetBtnText); resetScoreBtn.x = -100; resetScoreBtn.y = 280; LK.gui.topRight.addChild(resetScoreBtn); // GUI: Bird swapper button var birdSwapBtn = new Container(); var birdSwapBtnBg = birdSwapBtn.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150, tint: 0x44ff44 }); var birdSwapIcon = birdSwapBtn.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); birdSwapBtn.x = -100; birdSwapBtn.y = 460; LK.gui.topRight.addChild(birdSwapBtn); // Start spinning animation for reset button function spinResetButton() { tween(resetBtnText, { rotation: resetBtnText.rotation + Math.PI * 2 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { spinResetButton(); } }); } spinResetButton(); // GUI: Power-up indicator var powerUpIndicator = new Container(); var powerUpBg = powerUpIndicator.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, width: 200, height: 80, tint: 0x00ffff }); var powerUpText = new Text2('FREEZE: 30s', { size: 40, fill: 0xFFFFFF }); powerUpText.anchor.set(0.5, 0.5); powerUpIndicator.addChild(powerUpText); powerUpIndicator.x = 0; powerUpIndicator.y = 200; powerUpIndicator.visible = false; LK.gui.top.addChild(powerUpIndicator); // Drink toggle handler drinkToggleBtn.down = function () { if (bird) { bird.toggleDrink(); } }; // Reset score handler resetScoreBtn.down = function () { score = 0; scoreTxt.setText('0'); storage.lastScore = 0; // Flash effect to indicate reset LK.effects.flashObject(resetScoreBtn, 0xffffff, 300); }; // Bird swap handler birdSwapBtn.down = function () { if (bird) { // Get current bird type from storage or default to 'bird' var currentBirdType = storage.currentBirdType || 'bird'; var newBirdType = currentBirdType === 'bird' ? 'Bird2' : 'bird'; // Store current drink state var drinkState = { drink1: bird.children[1].visible, drink2: bird.children[2].visible, drink3: bird.children[3].visible }; // Remove current main bird sprite var currentBird = bird.children[0]; bird.removeChild(currentBird); // Create new bird sprite var newBird = LK.getAsset(newBirdType, { anchorX: 0.5, anchorY: 0.5 }); bird.addChildAt(newBird, 0); bird.currentSprite = newBird; // Update rotation to match current velocity var maxAngle = Math.PI / 4; var minAngle = -Math.PI / 6; var angle = bird.vy / 40 * maxAngle; if (angle > maxAngle) angle = maxAngle; if (angle < minAngle) angle = minAngle; newBird.rotation = angle; // Restore drink state bird.children[1].visible = drinkState.drink1; bird.children[2].visible = drinkState.drink2; bird.children[3].visible = drinkState.drink3; // Save new bird type storage.currentBirdType = newBirdType; // Flash effect to indicate swap LK.effects.flashObject(birdSwapBtn, 0xffffff, 300); } }; // Add ground ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: GROUND_Y }); game.addChild(ground); // Helper: Reset game state function resetGame() { // Remove pipes for (var i = 0; i < pipes.length; i++) { pipes[i].destroy(); } pipes = []; // Remove power-ups for (var i = 0; i < powerUps.length; i++) { powerUps[i].destroy(); } powerUps = []; // Clear power-up state if (slowTimeTimer) { LK.clearTimeout(slowTimeTimer); slowTimeTimer = null; } slowTimeActive = false; powerUpIndicator.visible = false; frozenPipes = []; // Remove bird if exists if (bird) bird.destroy(); // Reset variables score = 0; scoreTxt.setText('0'); gameOver = false; started = false; lastPipeX = 0; // Hide game over gameOverTxt.visible = false; restartTxt.visible = false; // Add bird bird = new Bird(); bird.x = BIRD_START_X; bird.y = BIRD_START_Y; game.addChild(bird); // Restore score if available if (typeof storage.lastScore !== "undefined") { score = storage.lastScore; scoreTxt.setText(score + ''); } // Restore bird type if available if (typeof storage.currentBirdType !== "undefined" && storage.currentBirdType === 'Bird2') { var currentBird = bird.children[0]; var newBird = LK.getAsset('Bird2', { anchorX: 0.5, anchorY: 0.5 }); bird.removeChild(currentBird); bird.addChildAt(newBird, 0); bird.currentSprite = newBird; } // Restore drink state if available if (typeof storage.lastDrink !== "undefined") { if (storage.lastDrink === 1) { bird.children[1].visible = true; bird.children[2].visible = false; } else if (storage.lastDrink === 2) { bird.children[1].visible = false; bird.children[2].visible = true; } else if (storage.lastDrink === 3) { bird.children[1].visible = false; bird.children[2].visible = false; bird.children[3].visible = true; } else { bird.children[1].visible = false; bird.children[2].visible = false; bird.children[3].visible = false; } } // Add first pipes for (var i = 0; i < 3; i++) { spawnPipe(2048 + i * PIPE_INTERVAL); } } // Helper: Spawn a pipe pair at x function spawnPipe(x) { var gapY = PIPE_MIN_Y + Math.floor(Math.random() * (PIPE_MAX_Y - PIPE_MIN_Y)); var pipePair = new PipePair(); pipePair.x = x; pipePair.setGap(gapY); pipes.push(pipePair); game.addChild(pipePair); lastPipeX = x; // 10% chance to spawn power-up with pipe if (Math.random() < 0.1 && !slowTimeActive) { var powerUp = new PowerUp(); powerUp.x = x + pipePair.pipeWidth / 2; powerUp.y = gapY + pipePair.gapHeight / 2; powerUps.push(powerUp); game.addChild(powerUp); } } // Helper: Check collision between bird and a pipe rect function birdHitsRect(rect) { // Return false if rect is null (e.g., when fire sprite is not visible) if (!rect) return false; // Bird is a circle, rect is {x, y, width, height} var cx = bird.x; var cy = bird.y; var r = bird.radius; // Find closest point in rect to bird center var closestX = cx; if (cx < rect.x) closestX = rect.x;else if (cx > rect.x + rect.width) closestX = rect.x + rect.width; var closestY = cy; if (cy < rect.y) closestY = rect.y;else if (cy > rect.y + rect.height) closestY = rect.y + rect.height; var dx = cx - closestX; var dy = cy - closestY; return dx * dx + dy * dy < r * r; } // Helper: Activate power-up function activatePowerUp() { slowTimeActive = true; powerUpIndicator.visible = true; // Freeze all fire pipes for (var i = 0; i < pipes.length; i++) { if (pipes[i].isFirePipe && pipes[i].firePipe) { pipes[i].firePipe.freeze(); frozenPipes.push(pipes[i].firePipe); } } // Start countdown var timeLeft = POWERUP_DURATION / 1000; var countdownInterval = LK.setInterval(function () { timeLeft--; powerUpText.setText('FREEZE: ' + timeLeft + 's'); if (timeLeft <= 0) { LK.clearInterval(countdownInterval); } }, 1000); // Set timer to deactivate power-up if (slowTimeTimer) { LK.clearTimeout(slowTimeTimer); } slowTimeTimer = LK.setTimeout(function () { slowTimeActive = false; powerUpIndicator.visible = false; // Unfreeze all frozen pipes for (var i = 0; i < frozenPipes.length; i++) { frozenPipes[i].unfreeze(); } frozenPipes = []; LK.clearInterval(countdownInterval); }, POWERUP_DURATION); } // Helper: End game function triggerGameOver() { if (gameOver) return; gameOver = true; // Save score and drink state to storage storage.lastScore = score; // Access birdDrinkSprite via bird instance if available storage.lastDrink = bird && bird.hasOwnProperty('children') && bird.children.length > 1 ? bird.children[1].visible ? 1 : bird.children[2].visible ? 2 : bird.children[3].visible ? 3 : 0 : 0; LK.getSound('hit').play(); gameOverTxt.visible = true; restartTxt.visible = true; // Flash screen LK.effects.flashScreen(0xff0000, 600); // Show Game Over popup (will pause game) // LK.showGameOver(); } // Game tap/flap handler function handleTap(x, y, obj) { if (gameOver) { resetGame(); return; } if (!started) { started = true; } bird.flap(); } // Attach tap handler game.down = handleTap; // Main update loop game.update = function () { if (gameOver) return; // Bird update bird.update(); // Pipes update for (var i = pipes.length - 1; i >= 0; i--) { var pipe = pipes[i]; pipe.update(); // Remove pipes off screen if (pipe.x + pipe.pipeWidth < 0) { pipe.destroy(); pipes.splice(i, 1); continue; } // Scoring: passed pipe if (!pipe.passed && pipe.x + pipe.pipeWidth < bird.x) { pipe.passed = true; score += 1; scoreTxt.setText(score + ''); LK.getSound('score').play(); } } // Spawn new pipes if (pipes.length > 0) { var rightmost = pipes[pipes.length - 1]; if (2048 - (rightmost.x + rightmost.pipeWidth) >= PIPE_INTERVAL - 10) { spawnPipe(2048); } } // Power-ups update and collision for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; powerUp.update(); // Remove power-ups off screen if (powerUp.x + 40 < 0) { powerUp.destroy(); powerUps.splice(i, 1); continue; } // Check collision with bird if (!powerUp.collected && birdHitsRect(powerUp.getBoundingRect())) { powerUp.collected = true; powerUp.visible = false; activatePowerUp(); LK.getSound('score').play(); } } // Collision: pipes for (var i = 0; i < pipes.length; i++) { var pipe = pipes[i]; var hitTopPipe = birdHitsRect(pipe.getTopRect()); var hitBottomPipe = birdHitsRect(pipe.getBottomRect()); var hitPipe = hitTopPipe || hitBottomPipe; var hitFire = pipe.isFirePipe && pipe.firePipe && pipe.firePipe.getBoundingRect && birdHitsRect(pipe.firePipe.getBoundingRect()); if (hitPipe || hitFire) { triggerGameOver(); return; } } // Collision: ground if (bird.y + bird.radius > GROUND_Y) { bird.y = GROUND_Y - bird.radius; triggerGameOver(); return; } // Collision: ceiling if (bird.y - bird.radius < 0) { bird.y = bird.radius; bird.vy = 0; } // Out of bounds (left/right) if (bird.x - bird.radius < 0 || bird.x + bird.radius > 2048) { triggerGameOver(); return; } }; // Initial game state resetGame();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdSprite = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
var birdDrinkSprite = self.attachAsset('Bird_drink', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var drink2Sprite = self.attachAsset('Drink_2', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
var drink3Sprite = self.attachAsset('Drink3', {
anchorX: 0.5,
anchorY: 0.5,
visible: false
});
// Position drink in front of bird
birdDrinkSprite.x = birdSprite.width * 0.7; // Offset to the right (in front)
drink2Sprite.x = birdDrinkSprite.x; // Align drink2Sprite with birdDrinkSprite
drink3Sprite.x = birdDrinkSprite.x; // Align drink3Sprite with birdDrinkSprite
self.currentSprite = birdSprite;
self.radius = birdSprite.width * 0.5 * 0.85; // for collision
self.vy = 0; // vertical speed
self.gravity = 0.6; // gravity per frame (slower fall)
self.flapStrength = -22; // negative = up, less strong flap
// Flap method
self.flap = function () {
self.vy = self.flapStrength;
LK.getSound('flap').play();
};
// Toggle drink method
self.toggleDrink = function () {
// Cycle through no drink, bird drink, drink 2, and drink 3
if (!birdDrinkSprite.visible && !drink2Sprite.visible && !drink3Sprite.visible) {
birdDrinkSprite.visible = true;
drink2Sprite.visible = false;
drink3Sprite.visible = false;
} else if (birdDrinkSprite.visible) {
birdDrinkSprite.visible = false;
drink2Sprite.visible = true;
drink3Sprite.visible = false;
} else if (drink2Sprite.visible) {
birdDrinkSprite.visible = false;
drink2Sprite.visible = false;
drink3Sprite.visible = true;
} else {
birdDrinkSprite.visible = false;
drink2Sprite.visible = false;
drink3Sprite.visible = false;
}
// Save the current drink state to storage
storage.lastDrink = birdDrinkSprite.visible ? 1 : drink2Sprite.visible ? 2 : 0;
};
// Update method
self.update = function () {
self.vy += self.gravity * (slowTimeActive ? slowTimeMultiplier : 1);
self.y += self.vy;
// Rotate bird based on velocity (visual only)
var maxAngle = Math.PI / 4;
var minAngle = -Math.PI / 6;
var angle = self.vy / 40 * maxAngle;
if (angle > maxAngle) angle = maxAngle;
if (angle < minAngle) angle = minAngle;
birdSprite.rotation = angle;
// Keep drink upright and in front
birdDrinkSprite.rotation = 0;
};
return self;
});
// Fire class for standalone fire effects
var Fire = Container.expand(function () {
var self = Container.call(this);
var fireSprite = self.attachAsset('fire', {
anchorX: 0.5,
anchorY: 0.5,
visible: false,
alpha: 0.5
});
self.shootFire = function () {
fireSprite.visible = true;
fireSprite.x = 0; // Reset position when shooting
fireSprite.y = 0;
tween(fireSprite, {
alpha: 1
}, {
duration: 500,
easing: tween.linear,
onFinish: function onFinish() {
tween(fireSprite, {
alpha: 0.5
}, {
duration: 500,
easing: tween.linear
});
}
});
};
self.getBoundingRect = function () {
if (!fireSprite.visible) return null;
return {
x: self.x + fireSprite.x - fireSprite.width * 0.5,
y: self.y + fireSprite.y - fireSprite.height * 0.5,
width: fireSprite.width,
height: fireSprite.height
};
};
self.update = function () {
if (fireSprite.visible) {
fireSprite.x -= pipeSpeed;
if (fireSprite.x < -fireSprite.width) {
fireSprite.visible = false;
}
}
};
return self;
});
var FirePipe = Container.expand(function () {
var self = Container.call(this);
var firePipeSprite = self.attachAsset('FirePipe', {
anchorX: 0.5,
anchorY: 0.5,
visible: true,
alpha: 1
});
self.movingRight = true; // Track movement direction
self.startMovement = function () {
// Start continuous left-right movement
self.moveLeftRight();
};
self.moveLeftRight = function () {
// Check if this pipe is frozen
if (self.frozen) return;
var targetX = self.movingRight ? 300 : -300; // Move 300px in each direction
tween(firePipeSprite, {
x: targetX
}, {
duration: 2000,
// 2 seconds to move in one direction
easing: tween.easeInOut,
onFinish: function onFinish() {
// Reverse direction and continue moving
self.movingRight = !self.movingRight;
self.moveLeftRight();
}
});
};
self.freeze = function () {
self.frozen = true;
// Add visual effect for frozen state
tween(firePipeSprite, {
tint: 0x88ccff
}, {
duration: 300,
easing: tween.easeOut
});
};
self.unfreeze = function () {
self.frozen = false;
// Remove visual effect
tween(firePipeSprite, {
tint: 0xffffff
}, {
duration: 300,
easing: tween.easeOut
});
// Resume movement
self.moveLeftRight();
};
self.getBoundingRect = function () {
if (!firePipeSprite.visible) return null;
return {
x: self.x + firePipeSprite.x - firePipeSprite.width * 0.5,
y: self.y + firePipeSprite.y - firePipeSprite.height * 0.5,
width: firePipeSprite.width,
height: firePipeSprite.height
};
};
self.update = function () {
// Movement is now handled by tween
};
return self;
});
// PipePair class (top and bottom pipes)
var PipePair = Container.expand(function () {
var self = Container.call(this);
// Pipe config
var pipeWidth = 200;
var pipeHeight = 1200;
var gapHeight = 480; // vertical gap between pipes
// Randomly decide if pipes are flipped (top/bottom swap orientation)
var flip = Math.random() < 0.5;
// Randomly decide pipe type: normal (70%) or fire (30%)
var isFirePipe = Math.random() < 0.3;
// For fire pipes, always single pipe. For regular pipes, 30% chance of single pipe
var isSinglePipe = isFirePipe || Math.random() < 0.3;
var pipeAsset = isFirePipe ? 'FirePipe' : 'pipe';
var topPipe = null;
var bottomPipe = null;
// Create pipes based on configuration
if (isSinglePipe) {
// Single pipe - randomly choose top or bottom position
var isTopPosition = Math.random() < 0.5;
if (isTopPosition) {
topPipe = self.attachAsset(pipeAsset, {
anchorX: 0,
anchorY: flip ? 0 : 1,
width: pipeWidth,
height: pipeHeight,
rotation: flip ? Math.PI : 0
});
} else {
bottomPipe = self.attachAsset(pipeAsset, {
anchorX: 0,
anchorY: flip ? 1 : 0,
width: pipeWidth,
height: pipeHeight,
rotation: flip ? Math.PI : 0
});
}
} else {
// Double pipes (traditional setup)
topPipe = self.attachAsset(pipeAsset, {
anchorX: 0,
anchorY: flip ? 0 : 1,
width: pipeWidth,
height: pipeHeight,
rotation: flip ? Math.PI : 0
});
bottomPipe = self.attachAsset(pipeAsset, {
anchorX: 0,
anchorY: flip ? 1 : 0,
width: pipeWidth,
height: pipeHeight,
rotation: flip ? Math.PI : 0
});
}
self.pipeWidth = pipeWidth;
self.gapHeight = gapHeight;
self.passed = false; // for scoring
self.isFirePipe = isFirePipe;
self.isSinglePipe = isSinglePipe;
self.fireTimer = 0;
self.topPipe = topPipe;
self.bottomPipe = bottomPipe;
// Set pipes' vertical positions based on gapY (top of gap)
self.setGap = function (gapY) {
// gapY: y position of top of gap
if (topPipe) topPipe.y = gapY;
if (bottomPipe) bottomPipe.y = gapY + gapHeight;
};
// Move pipes left
self.update = function () {
self.x -= pipeSpeed;
};
// Get bounding rects for collision
self.getTopRect = function () {
if (!topPipe) return null;
return {
x: self.x,
y: topPipe.y - pipeHeight,
width: pipeWidth,
height: pipeHeight
};
};
self.getBottomRect = function () {
if (!bottomPipe) return null;
return {
x: self.x,
y: bottomPipe.y,
width: pipeWidth,
height: pipeHeight
};
};
// Add fire shooting capability for fire pipes
if (isFirePipe) {
var firePipe = new FirePipe();
self.addChild(firePipe);
self.firePipe = firePipe;
self.fireStarted = false; // Track if fire has been started
}
self.update = function () {
self.x -= pipeSpeed * (slowTimeActive ? slowTimeMultiplier : 1);
// Update fire pipe if this is a fire pipe
if (self.isFirePipe && self.firePipe) {
self.firePipe.x = self.x; // Position fire at pipe position
// Center fire in the gap or at pipe level for single pipes
var fireY = bottomPipe ? bottomPipe.y - gapHeight / 2 : topPipe ? topPipe.y + gapHeight / 2 : 1366;
self.firePipe.y = fireY;
self.firePipe.update();
// Start movement when pipe enters screen (only once)
if (!self.fireStarted && self.x < 2048) {
self.fireStarted = true;
// Check if power-up is active and freeze immediately
if (slowTimeActive) {
self.firePipe.freeze();
frozenPipes.push(self.firePipe);
} else {
self.firePipe.startMovement();
}
}
}
};
return self;
});
// PowerUp class
var PowerUp = Container.expand(function () {
var self = Container.call(this);
// Create a star-shaped power-up visual using new asset
var powerUpSprite = self.attachAsset('powerUpStar', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0x00ffff // Cyan color for freeze power-up
});
// Add pulsing effect
self.pulse = function () {
tween(powerUpSprite, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(powerUpSprite, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.pulse();
}
});
}
});
};
self.collected = false;
self.update = function () {
if (!self.collected) {
self.x -= pipeSpeed * (slowTimeActive ? slowTimeMultiplier : 1);
}
};
self.getBoundingRect = function () {
return {
x: self.x - powerUpSprite.width * 0.5,
y: self.y - powerUpSprite.height * 0.5,
width: powerUpSprite.width,
height: powerUpSprite.height
};
};
// Start pulsing animation
self.pulse();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // sky blue
});
/****
* Game Code
****/
// Sound: Hit
// Sound: Score
// Sound: Flap
// Ground: brown box
// Pipe: green box
// Bird: yellow ellipse
// Game constants
var BIRD_START_X = 600;
var BIRD_START_Y = 1200;
var PIPE_INTERVAL = 1300; // px between pipes horizontally (slower spawn rate)
var PIPE_MIN_Y = 350; // min y for top of gap
var PIPE_MAX_Y = 1800; // max y for top of gap
var GROUND_Y = 2732 - 120; // ground top y
var pipeSpeed = 8; // px per frame (slower pipes)
var POWERUP_DURATION = 30000; // 30 seconds in milliseconds
var slowTimeMultiplier = 0.3; // 30% speed during slow time
// Game state
var bird;
var pipes = [];
var powerUps = [];
var ground;
var score = 0;
var scoreTxt;
var gameOver = false;
var started = false;
var lastPipeX = 0;
var slowTimeActive = false;
var slowTimeTimer = null;
var frozenPipes = [];
// GUI: Score
scoreTxt = new Text2('0', {
size: 160,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// GUI: Game Over text
var gameOverTxt = new Text2('Game Over', {
size: 180,
fill: 0xFF4444
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.visible = false;
LK.gui.center.addChild(gameOverTxt);
// GUI: Tap to restart
var restartTxt = new Text2('Tap to restart', {
size: 100,
fill: 0xFFFFFF
});
restartTxt.anchor.set(0.5, 0.5);
restartTxt.visible = false;
LK.gui.center.addChild(restartTxt);
// GUI: Drink toggle button
var drinkToggleBtn = new Container();
var drinkBtnBg = drinkToggleBtn.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150,
tint: 0x4444ff
});
var drinkBtnText = new Text2('🥤', {
size: 80,
fill: 0xFFFFFF
});
drinkBtnText.anchor.set(0.5, 0.5);
drinkToggleBtn.addChild(drinkBtnText);
drinkToggleBtn.x = -100;
drinkToggleBtn.y = 100;
LK.gui.topRight.addChild(drinkToggleBtn);
// GUI: Reset score button
var resetScoreBtn = new Container();
var resetBtnBg = resetScoreBtn.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150,
tint: 0xff4444
});
var resetBtnText = new Text2('Ø', {
size: 100,
fill: 0xFFFFFF
});
resetBtnText.anchor.set(0.5, 0.5);
resetScoreBtn.addChild(resetBtnText);
resetScoreBtn.x = -100;
resetScoreBtn.y = 280;
LK.gui.topRight.addChild(resetScoreBtn);
// GUI: Bird swapper button
var birdSwapBtn = new Container();
var birdSwapBtnBg = birdSwapBtn.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150,
tint: 0x44ff44
});
var birdSwapIcon = birdSwapBtn.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
birdSwapBtn.x = -100;
birdSwapBtn.y = 460;
LK.gui.topRight.addChild(birdSwapBtn);
// Start spinning animation for reset button
function spinResetButton() {
tween(resetBtnText, {
rotation: resetBtnText.rotation + Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
spinResetButton();
}
});
}
spinResetButton();
// GUI: Power-up indicator
var powerUpIndicator = new Container();
var powerUpBg = powerUpIndicator.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 80,
tint: 0x00ffff
});
var powerUpText = new Text2('FREEZE: 30s', {
size: 40,
fill: 0xFFFFFF
});
powerUpText.anchor.set(0.5, 0.5);
powerUpIndicator.addChild(powerUpText);
powerUpIndicator.x = 0;
powerUpIndicator.y = 200;
powerUpIndicator.visible = false;
LK.gui.top.addChild(powerUpIndicator);
// Drink toggle handler
drinkToggleBtn.down = function () {
if (bird) {
bird.toggleDrink();
}
};
// Reset score handler
resetScoreBtn.down = function () {
score = 0;
scoreTxt.setText('0');
storage.lastScore = 0;
// Flash effect to indicate reset
LK.effects.flashObject(resetScoreBtn, 0xffffff, 300);
};
// Bird swap handler
birdSwapBtn.down = function () {
if (bird) {
// Get current bird type from storage or default to 'bird'
var currentBirdType = storage.currentBirdType || 'bird';
var newBirdType = currentBirdType === 'bird' ? 'Bird2' : 'bird';
// Store current drink state
var drinkState = {
drink1: bird.children[1].visible,
drink2: bird.children[2].visible,
drink3: bird.children[3].visible
};
// Remove current main bird sprite
var currentBird = bird.children[0];
bird.removeChild(currentBird);
// Create new bird sprite
var newBird = LK.getAsset(newBirdType, {
anchorX: 0.5,
anchorY: 0.5
});
bird.addChildAt(newBird, 0);
bird.currentSprite = newBird;
// Update rotation to match current velocity
var maxAngle = Math.PI / 4;
var minAngle = -Math.PI / 6;
var angle = bird.vy / 40 * maxAngle;
if (angle > maxAngle) angle = maxAngle;
if (angle < minAngle) angle = minAngle;
newBird.rotation = angle;
// Restore drink state
bird.children[1].visible = drinkState.drink1;
bird.children[2].visible = drinkState.drink2;
bird.children[3].visible = drinkState.drink3;
// Save new bird type
storage.currentBirdType = newBirdType;
// Flash effect to indicate swap
LK.effects.flashObject(birdSwapBtn, 0xffffff, 300);
}
};
// Add ground
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: GROUND_Y
});
game.addChild(ground);
// Helper: Reset game state
function resetGame() {
// Remove pipes
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
// Remove power-ups
for (var i = 0; i < powerUps.length; i++) {
powerUps[i].destroy();
}
powerUps = [];
// Clear power-up state
if (slowTimeTimer) {
LK.clearTimeout(slowTimeTimer);
slowTimeTimer = null;
}
slowTimeActive = false;
powerUpIndicator.visible = false;
frozenPipes = [];
// Remove bird if exists
if (bird) bird.destroy();
// Reset variables
score = 0;
scoreTxt.setText('0');
gameOver = false;
started = false;
lastPipeX = 0;
// Hide game over
gameOverTxt.visible = false;
restartTxt.visible = false;
// Add bird
bird = new Bird();
bird.x = BIRD_START_X;
bird.y = BIRD_START_Y;
game.addChild(bird);
// Restore score if available
if (typeof storage.lastScore !== "undefined") {
score = storage.lastScore;
scoreTxt.setText(score + '');
}
// Restore bird type if available
if (typeof storage.currentBirdType !== "undefined" && storage.currentBirdType === 'Bird2') {
var currentBird = bird.children[0];
var newBird = LK.getAsset('Bird2', {
anchorX: 0.5,
anchorY: 0.5
});
bird.removeChild(currentBird);
bird.addChildAt(newBird, 0);
bird.currentSprite = newBird;
}
// Restore drink state if available
if (typeof storage.lastDrink !== "undefined") {
if (storage.lastDrink === 1) {
bird.children[1].visible = true;
bird.children[2].visible = false;
} else if (storage.lastDrink === 2) {
bird.children[1].visible = false;
bird.children[2].visible = true;
} else if (storage.lastDrink === 3) {
bird.children[1].visible = false;
bird.children[2].visible = false;
bird.children[3].visible = true;
} else {
bird.children[1].visible = false;
bird.children[2].visible = false;
bird.children[3].visible = false;
}
}
// Add first pipes
for (var i = 0; i < 3; i++) {
spawnPipe(2048 + i * PIPE_INTERVAL);
}
}
// Helper: Spawn a pipe pair at x
function spawnPipe(x) {
var gapY = PIPE_MIN_Y + Math.floor(Math.random() * (PIPE_MAX_Y - PIPE_MIN_Y));
var pipePair = new PipePair();
pipePair.x = x;
pipePair.setGap(gapY);
pipes.push(pipePair);
game.addChild(pipePair);
lastPipeX = x;
// 10% chance to spawn power-up with pipe
if (Math.random() < 0.1 && !slowTimeActive) {
var powerUp = new PowerUp();
powerUp.x = x + pipePair.pipeWidth / 2;
powerUp.y = gapY + pipePair.gapHeight / 2;
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
// Helper: Check collision between bird and a pipe rect
function birdHitsRect(rect) {
// Return false if rect is null (e.g., when fire sprite is not visible)
if (!rect) return false;
// Bird is a circle, rect is {x, y, width, height}
var cx = bird.x;
var cy = bird.y;
var r = bird.radius;
// Find closest point in rect to bird center
var closestX = cx;
if (cx < rect.x) closestX = rect.x;else if (cx > rect.x + rect.width) closestX = rect.x + rect.width;
var closestY = cy;
if (cy < rect.y) closestY = rect.y;else if (cy > rect.y + rect.height) closestY = rect.y + rect.height;
var dx = cx - closestX;
var dy = cy - closestY;
return dx * dx + dy * dy < r * r;
}
// Helper: Activate power-up
function activatePowerUp() {
slowTimeActive = true;
powerUpIndicator.visible = true;
// Freeze all fire pipes
for (var i = 0; i < pipes.length; i++) {
if (pipes[i].isFirePipe && pipes[i].firePipe) {
pipes[i].firePipe.freeze();
frozenPipes.push(pipes[i].firePipe);
}
}
// Start countdown
var timeLeft = POWERUP_DURATION / 1000;
var countdownInterval = LK.setInterval(function () {
timeLeft--;
powerUpText.setText('FREEZE: ' + timeLeft + 's');
if (timeLeft <= 0) {
LK.clearInterval(countdownInterval);
}
}, 1000);
// Set timer to deactivate power-up
if (slowTimeTimer) {
LK.clearTimeout(slowTimeTimer);
}
slowTimeTimer = LK.setTimeout(function () {
slowTimeActive = false;
powerUpIndicator.visible = false;
// Unfreeze all frozen pipes
for (var i = 0; i < frozenPipes.length; i++) {
frozenPipes[i].unfreeze();
}
frozenPipes = [];
LK.clearInterval(countdownInterval);
}, POWERUP_DURATION);
}
// Helper: End game
function triggerGameOver() {
if (gameOver) return;
gameOver = true;
// Save score and drink state to storage
storage.lastScore = score;
// Access birdDrinkSprite via bird instance if available
storage.lastDrink = bird && bird.hasOwnProperty('children') && bird.children.length > 1 ? bird.children[1].visible ? 1 : bird.children[2].visible ? 2 : bird.children[3].visible ? 3 : 0 : 0;
LK.getSound('hit').play();
gameOverTxt.visible = true;
restartTxt.visible = true;
// Flash screen
LK.effects.flashScreen(0xff0000, 600);
// Show Game Over popup (will pause game)
// LK.showGameOver();
}
// Game tap/flap handler
function handleTap(x, y, obj) {
if (gameOver) {
resetGame();
return;
}
if (!started) {
started = true;
}
bird.flap();
}
// Attach tap handler
game.down = handleTap;
// Main update loop
game.update = function () {
if (gameOver) return;
// Bird update
bird.update();
// Pipes update
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.update();
// Remove pipes off screen
if (pipe.x + pipe.pipeWidth < 0) {
pipe.destroy();
pipes.splice(i, 1);
continue;
}
// Scoring: passed pipe
if (!pipe.passed && pipe.x + pipe.pipeWidth < bird.x) {
pipe.passed = true;
score += 1;
scoreTxt.setText(score + '');
LK.getSound('score').play();
}
}
// Spawn new pipes
if (pipes.length > 0) {
var rightmost = pipes[pipes.length - 1];
if (2048 - (rightmost.x + rightmost.pipeWidth) >= PIPE_INTERVAL - 10) {
spawnPipe(2048);
}
}
// Power-ups update and collision
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
powerUp.update();
// Remove power-ups off screen
if (powerUp.x + 40 < 0) {
powerUp.destroy();
powerUps.splice(i, 1);
continue;
}
// Check collision with bird
if (!powerUp.collected && birdHitsRect(powerUp.getBoundingRect())) {
powerUp.collected = true;
powerUp.visible = false;
activatePowerUp();
LK.getSound('score').play();
}
}
// Collision: pipes
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
var hitTopPipe = birdHitsRect(pipe.getTopRect());
var hitBottomPipe = birdHitsRect(pipe.getBottomRect());
var hitPipe = hitTopPipe || hitBottomPipe;
var hitFire = pipe.isFirePipe && pipe.firePipe && pipe.firePipe.getBoundingRect && birdHitsRect(pipe.firePipe.getBoundingRect());
if (hitPipe || hitFire) {
triggerGameOver();
return;
}
}
// Collision: ground
if (bird.y + bird.radius > GROUND_Y) {
bird.y = GROUND_Y - bird.radius;
triggerGameOver();
return;
}
// Collision: ceiling
if (bird.y - bird.radius < 0) {
bird.y = bird.radius;
bird.vy = 0;
}
// Out of bounds (left/right)
if (bird.x - bird.radius < 0 || bird.x + bird.radius > 2048) {
triggerGameOver();
return;
}
};
// Initial game state
resetGame();
Pipe. In-Game asset. 2d. High contrast. No shadows
Bird. In-Game asset. 2d. High contrast. No shadows
Rock bg. In-Game asset. 2d. High contrast. No shadows
Cup with Straw. In-Game asset. 2d. High contrast. No shadows
Coke bottle with straw. In-Game asset. 2d. High contrast. No shadows
Fire. In-Game asset. 2d. High contrast. No shadows
Red pipe. In-Game asset. 2d. High contrast. No shadows