/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bird = Container.expand(function () { var self = Container.call(this); var birdGraphics = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); self.velocity = 0; self.gravity = 0.8; self.flapStrength = -12; self.maxFallSpeed = 15; self.rotation = 0; self.animationTimer = 0; self.invincible = false; self.shieldActive = false; self.shieldTimer = 0; self.speedBoostActive = false; self.speedBoostTimer = 0; self.trail = []; self.flap = function () { self.velocity = self.flapStrength; LK.getSound('flap').play(); // Wing flapping animation - quick upward flap tween(birdGraphics, { scaleY: 1.3, scaleX: 0.8 }, { duration: 80, easing: tween.easeOut }); tween(birdGraphics, { scaleY: 1.0, scaleX: 1.0 }, { duration: 120, easing: tween.easeIn }); // Slight upward rotation on flap tween(birdGraphics, { rotation: -0.4 }, { duration: 150, easing: tween.easeOut }); }; self.update = function () { // Apply gravity only when game has started if (gameStarted && gameActive) { // Apply gravity (reduced if speed boost active) var currentGravity = self.speedBoostActive ? self.gravity * 0.7 : self.gravity; self.velocity += currentGravity; // Limit fall speed if (self.velocity > self.maxFallSpeed) { self.velocity = self.maxFallSpeed; } // Update position with swooping effect self.y += self.velocity; // Add swooping animation during fast descent if (gameStarted && gameActive && self.velocity > 8) { var swoopIntensity = (self.velocity - 8) * 0.02; var swoopCycle = Math.sin(LK.ticks * 0.4); birdGraphics.x = swoopCycle * swoopIntensity * 10; // Wing tucking during fast descent tween.stop(birdGraphics, { scaleX: true }); tween(birdGraphics, { scaleX: 0.8 - swoopIntensity }, { duration: 200, easing: tween.easeOut }); } } // Smooth rotation based on velocity with gliding effect var targetRotation = Math.min(self.velocity * 0.08, 1.2); if (self.velocity < 0) { targetRotation = Math.max(self.velocity * 0.08, -0.4); // Add gliding wing extension when rising if (gameStarted && gameActive) { var glideIntensity = Math.min(-self.velocity * 0.05, 0.3); tween.stop(birdGraphics, { scaleX: true }); tween(birdGraphics, { scaleX: 1.0 + glideIntensity }, { duration: 300, easing: tween.easeOut }); } } // Smooth rotation transition tween.stop(birdGraphics, { rotation: true }); tween(birdGraphics, { rotation: targetRotation }, { duration: 200, easing: tween.easeOut }); // Enhanced continuous wing flapping animation when flying if (gameStarted && gameActive) { self.animationTimer += 0.3; var flapCycle = Math.sin(self.animationTimer); var fastFlap = Math.sin(self.animationTimer * 2); // Wing flapping effect - compress and stretch with double beat var flapIntensity = 0.2; var microFlap = 0.05; birdGraphics.scaleY = 1.0 + flapCycle * flapIntensity + fastFlap * microFlap; birdGraphics.scaleX = 1.0 - flapCycle * flapIntensity * 0.7 - fastFlap * microFlap; // Add subtle wing position shifts var wingShift = Math.cos(self.animationTimer * 1.5) * 0.8; birdGraphics.x = wingShift; } else { // Enhanced floating animation when idle if (Math.abs(self.velocity) < 2) { self.animationTimer += 0.1; var bob = Math.sin(self.animationTimer) * 3; var sway = Math.cos(self.animationTimer * 0.7) * 1.5; birdGraphics.y = bob; birdGraphics.x = sway; // Gentle scale breathing effect var breathe = Math.sin(self.animationTimer * 0.5) * 0.05 + 1; birdGraphics.scaleX = breathe; birdGraphics.scaleY = breathe; } } // Update power-up timers if (self.shieldActive) { self.shieldTimer--; if (self.shieldTimer <= 0) { self.shieldActive = false; } } if (self.speedBoostActive) { self.speedBoostTimer--; if (self.speedBoostTimer <= 0) { self.speedBoostActive = false; } } // Visual effects for active power-ups if (self.shieldActive) { var shieldPulse = Math.sin(LK.ticks * 0.2) * 0.3 + 0.7; birdGraphics.tint = 0x4488FF; birdGraphics.alpha = shieldPulse; } else if (self.speedBoostActive) { birdGraphics.tint = 0xFF4444; birdGraphics.alpha = 0.9; } else if (self.invincible) { birdGraphics.alpha = 0.5 + 0.5 * Math.sin(LK.ticks * 0.3); birdGraphics.tint = 0xFFFFFF; } else { birdGraphics.alpha = 1; birdGraphics.tint = 0xFFFFFF; } // Add wing trail effect during flapping if (gameStarted && gameActive) { self.trail.push({ x: self.x, y: self.y, life: 15, isWingTrail: true }); if (self.trail.length > 12) { self.trail.shift(); } } else { // Regular trail when not flapping self.trail.push({ x: self.x, y: self.y, life: 10 }); if (self.trail.length > 8) { self.trail.shift(); } } }; return self; }); var Building = Container.expand(function () { var self = Container.call(this); // Random building height - much taller self.buildingHeight = 300 + Math.random() * 400; // Create building structure var buildingGraphics = self.attachAsset('building', { anchorX: 0.5, anchorY: 1, scaleY: self.buildingHeight / 400, scaleX: 1.8 // Same as Building2 }); // Add windows to building self.windows = []; var windowRows = Math.floor(self.buildingHeight / 20); // Same spacing as Building2 var windowCols = 4; // Same as Building2 for (var row = 0; row < windowRows; row++) { for (var col = 0; col < windowCols; col++) { if (Math.random() < 0.7) { // 70% chance for lit window var window = self.attachAsset('buildingWindow', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, // Same as Building2 scaleY: 0.5 }); window.x = -135 + col * 90; // Same spacing as Building2 window.y = -self.buildingHeight + 12 + row * 20; // Same spacing as Building2 self.windows.push(window); } } } self.speed = -2; self.update = function () { self.x += self.speed; // Flicker windows randomly for (var i = 0; i < self.windows.length; i++) { if (Math.random() < 0.01) { // 1% chance to flicker self.windows[i].alpha = Math.random() < 0.5 ? 0.3 : 1.0; } // Add flying/flapping animation to windows if (Math.random() < 0.005) { // 0.5% chance for window to "fly" with wing-like animation var window = self.windows[i]; // Wing flap animation - quick scale change tween(window, { scaleX: 1.5, scaleY: 0.8, rotation: 0.2 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(window, { scaleX: 1.0, scaleY: 1.0, rotation: 0 }, { duration: 300, easing: tween.easeInOut }); } }); } } }; return self; }); var Building2 = Container.expand(function () { var self = Container.call(this); // Same building height range as Building - much taller self.buildingHeight = 300 + Math.random() * 400; // Create building structure with different scaling var buildingGraphics = self.attachAsset('building', { anchorX: 0.5, anchorY: 1, scaleY: self.buildingHeight / 400, scaleX: 1.8 // Larger than Building 1 }); // Tint building slightly different color buildingGraphics.tint = 0xCCCCCC; // Add windows to building with different pattern self.windows = []; var windowRows = Math.floor(self.buildingHeight / 20); // Closer spacing var windowCols = 4; // Fewer columns for smaller building for (var row = 0; row < windowRows; row++) { for (var col = 0; col < windowCols; col++) { if (Math.random() < 0.8) { // 80% chance for lit window var window = self.attachAsset('buildingWindow', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); window.x = -135 + col * 90; // Adjusted spacing for larger building window.y = -self.buildingHeight + 12 + row * 20; // Random window colors for variety var windowColors = [0xFFFF88, 0x88FFFF, 0xFF88FF, 0xFFFFFF]; window.tint = windowColors[Math.floor(Math.random() * windowColors.length)]; self.windows.push(window); } } } self.speed = -2; self.update = function () { self.x += self.speed; // Different flicker pattern - faster flicker for (var i = 0; i < self.windows.length; i++) { if (Math.random() < 0.02) { // 2% chance to flicker (faster than Building) self.windows[i].alpha = Math.random() < 0.3 ? 0.2 : 1.0; } // Add flying/flapping animation to Building2 windows with different pattern if (Math.random() < 0.008) { // 0.8% chance for window to "fly" with butterfly-like animation var window = self.windows[i]; // Butterfly wing flap animation - more elegant movement tween(window, { scaleX: 1.3, scaleY: 1.4, rotation: -0.3, y: window.y - 10 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(window, { scaleX: 0.9, scaleY: 1.1, rotation: 0.3, y: window.y + 5 }, { duration: 180, easing: tween.easeInOut, onFinish: function onFinish() { tween(window, { scaleX: 1.0, scaleY: 1.0, rotation: 0, y: window.y }, { duration: 220, easing: tween.easeIn }); } }); } }); } } }; return self; }); var Cloud = Container.expand(function () { var self = Container.call(this); var cloudGraphics = self.attachAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -1; self.update = function () { self.x += self.speed; // Reset position when off screen if (self.x < -200) { self.x = 2048 + 200; self.y = 100 + Math.random() * 300; } }; return self; }); var Coin = Container.expand(function () { var self = Container.call(this); var coinGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -4; self.collected = false; self.update = function () { self.x += self.speed; // Simple rotation animation coinGraphics.rotation += 0.1; }; self.checkCollection = function (bird) { var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2)); return distance < 35; // Collection radius }; return self; }); var Monkey = Container.expand(function () { var self = Container.call(this); var monkeyGraphics = self.attachAsset('monkey', { anchorX: 0.5, anchorY: 0.5 }); self.speed = -1.5; self.verticalSpeed = 0; self.bounceHeight = 50; self.animationTimer = 0; self.direction = 1; // 1 for right, -1 for left self.baseY = 0; self.update = function () { // Horizontal movement - only right self.x += Math.abs(self.speed); // Bouncing animation self.animationTimer += 0.08; self.y = self.baseY + Math.sin(self.animationTimer) * self.bounceHeight; // Reset position when off screen if (self.x > 2048 + 100) { self.x = -100; self.baseY = 200 + Math.random() * 400; } }; return self; }); var Particle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.velocityX = 0; self.velocityY = 0; self.life = 60; self.maxLife = 60; self.gravity = 0.2; self.update = function () { self.x += self.velocityX; self.y += self.velocityY; self.velocityY += self.gravity; self.life--; // Fade out over time var alpha = self.life / self.maxLife; particleGraphics.alpha = alpha; particleGraphics.scaleX = alpha * 0.5; particleGraphics.scaleY = alpha * 0.5; // Rotation particleGraphics.rotation += 0.1; }; return self; }); var Pipe = Container.expand(function () { var self = Container.call(this); self.gapHeight = 260; self.speed = -4; self.scored = false; // Create top pipe self.topPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 1 }); // Create bottom pipe self.bottomPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 0 }); // Add pipe caps for authentic look self.topCap = LK.getAsset('pipe', { anchorX: 0.5, anchorY: 1, scaleX: 1.2, scaleY: 0.1 }); self.bottomCap = LK.getAsset('pipe', { anchorX: 0.5, anchorY: 0, scaleX: 1.2, scaleY: 0.1 }); self.addChild(self.topCap); self.addChild(self.bottomCap); self.setupPipes = function (gapCenterY) { self.topPipe.y = gapCenterY - self.gapHeight / 2; self.bottomPipe.y = gapCenterY + self.gapHeight / 2; self.topCap.y = self.topPipe.y; self.bottomCap.y = self.bottomPipe.y; }; self.update = function () { self.x += self.speed; }; self.checkCollision = function (bird) { var birdRadius = 30; var pipeWidth = 62; var birdBounds = { left: bird.x - birdRadius, right: bird.x + birdRadius, top: bird.y - birdRadius, bottom: bird.y + birdRadius }; var pipeBounds = { left: self.x - pipeWidth, right: self.x + pipeWidth, topBottom: self.topPipe.y, bottomTop: self.bottomPipe.y }; // Check if bird is within pipe horizontal bounds if (birdBounds.right > pipeBounds.left && birdBounds.left < pipeBounds.right) { // Check collision with top or bottom pipe if (birdBounds.top < pipeBounds.topBottom || birdBounds.bottom > pipeBounds.bottomTop) { return true; } } return false; }; return self; }); var PowerUp = Container.expand(function () { var self = Container.call(this); var powerUpGraphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); powerUpGraphics.tint = 0xFF4444; // Red tint for power-up self.speed = -4; self.collected = false; self.type = 'shield'; // shield, speed, score self.animationTimer = 0; self.update = function () { self.x += self.speed; self.animationTimer += 0.1; // Pulsing animation var pulse = Math.sin(self.animationTimer) * 0.3 + 1; powerUpGraphics.scaleX = pulse; powerUpGraphics.scaleY = pulse; // Rotation powerUpGraphics.rotation += 0.05; // Glowing effect var glow = Math.sin(self.animationTimer * 2) * 0.3 + 0.7; powerUpGraphics.alpha = glow; }; self.checkCollection = function (bird) { var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2)); return distance < 40; }; return self; }); var SpawnPoint = Container.expand(function () { var self = Container.call(this); self.isActive = true; self.spawnType = 'pipe'; // 'pipe' or 'coin' self.cooldownTimer = 0; self.cooldownDuration = 60; // 1 second at 60fps // Create visual marker for spawn point var marker = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); self.addChild(marker); self.marker = marker; self.update = function () { if (self.cooldownTimer > 0) { self.cooldownTimer--; self.marker.alpha = 0.3; // Dim when on cooldown } else { self.marker.alpha = 1.0; // Bright when ready } // Pulse animation self.marker.rotation += 0.05; var pulse = Math.sin(LK.ticks * 0.1) * 0.1 + 1; self.marker.scaleX = 0.5 * pulse; self.marker.scaleY = 0.5 * pulse; }; self.canSpawn = function () { return self.isActive && self.cooldownTimer <= 0; }; self.triggerSpawn = function () { if (self.canSpawn()) { self.cooldownTimer = self.cooldownDuration; return true; } return false; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ var bird; var pipes = []; var coins = []; var spawnPoints = []; var clouds = []; var monkeys = []; var particles = []; var powerUps = []; var buildings = []; var buildings2 = []; var ground; var gameStarted = false; var gameActive = true; var pipeSpawnTimer = 0; var pipeSpawnInterval = 150; // 2.5 seconds at 60fps var buildingSpawnTimer = 0; var buildingSpawnInterval = 200; // 3.33 seconds at 60fps var building2SpawnTimer = 0; var building2SpawnInterval = 280; // 4.67 seconds at 60fps var playerHealth = 3; var bestScore = 0; var dayTime = true; var lastColorChangeScore = 0; var currentSkin = 0; var skinShowMode = false; var currentWeather = 0; var weatherChangeTimer = 0; var weatherChangeInterval = 1800; // 30 seconds at 60fps var comboMultiplier = 1; var comboTimer = 0; var difficultyLevel = 1; var weatherTypes = [{ name: 'Sunny', bgColor: 0x87CEEB, cloudAlpha: 0.8, cloudSpeed: 1 }, { name: 'Cloudy', bgColor: 0x708090, cloudAlpha: 1.0, cloudSpeed: 1.5 }, { name: 'Stormy', bgColor: 0x2F4F4F, cloudAlpha: 1.2, cloudSpeed: 2.0 }, { name: 'Sunset', bgColor: 0xFF6B35, cloudAlpha: 0.9, cloudSpeed: 0.8 }, { name: 'Night', bgColor: 0x191970, cloudAlpha: 0.6, cloudSpeed: 0.5 }]; var skins = [{ name: 'Classic', asset: 'bird' }, { name: 'Red Fire', asset: 'bird_red' }, { name: 'Blue Ice', asset: 'bird_blue' }, { name: 'Green Forest', asset: 'bird_green' }, { name: 'Golden King', asset: 'bird_golden' }]; // Create score display var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create health display var healthTxt = new Text2('♥ ♥ ♥', { size: 60, fill: 0xFF0000 }); healthTxt.anchor.set(1, 0); healthTxt.x = -20; // Position from right edge healthTxt.y = 20; LK.gui.topRight.addChild(healthTxt); // Create weather display var weatherTxt = new Text2('Weather: Sunny', { size: 40, fill: 0xFFFFFF }); weatherTxt.anchor.set(0, 0); weatherTxt.x = 20; weatherTxt.y = 20; LK.gui.topLeft.addChild(weatherTxt); // Create combo display var comboTxt = new Text2('', { size: 50, fill: 0xFFD700 }); comboTxt.anchor.set(0.5, 0); comboTxt.x = 0; comboTxt.y = 100; LK.gui.top.addChild(comboTxt); // Create game title var titleTxt = new Text2('FLAPPY BIRD', { size: 120, fill: 0xFFD700 }); titleTxt.anchor.set(0.5, 0.5); titleTxt.x = 2048 / 2; titleTxt.y = 2732 / 2 - 400; titleTxt.alpha = 0; game.addChild(titleTxt); // Create subtitle text under title var subtitleTxt = new Text2('Tap to Fly Through Pipes', { size: 50, fill: 0xFFFFFF }); subtitleTxt.anchor.set(0.5, 0.5); subtitleTxt.x = 2048 / 2; subtitleTxt.y = 2732 / 2 - 320; subtitleTxt.alpha = 0; game.addChild(subtitleTxt); // Create best score display var bestScoreTxt = new Text2('BEST: 0', { size: 45, fill: 0xFFD700 }); bestScoreTxt.anchor.set(0.5, 0.5); bestScoreTxt.x = 2048 / 2; bestScoreTxt.y = 2732 / 2 - 100; bestScoreTxt.alpha = 0; game.addChild(bestScoreTxt); // Create shared start/skin button var skinBtn = new Text2('START / SKINS', { size: 50, fill: 0xFFFFFF }); skinBtn.anchor.set(0.5, 0.5); skinBtn.x = 2048 / 2; skinBtn.y = 2732 / 2 + 50; skinBtn.alpha = 0; game.addChild(skinBtn); // Create skin button background var skinBtnBg = LK.getAsset('startButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.6 }); skinBtnBg.x = 2048 / 2; skinBtnBg.y = 2732 / 2 + 50; skinBtnBg.alpha = 0; game.addChild(skinBtnBg); var skinBtnBorder = LK.getAsset('startButtonBorder', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.6 }); skinBtnBorder.x = 2048 / 2; skinBtnBorder.y = 2732 / 2 + 50; skinBtnBorder.alpha = 0; game.addChild(skinBtnBorder); // Create skin selection UI var skinTitleTxt = new Text2('SELECT SKIN', { size: 80, fill: 0xFFD700 }); skinTitleTxt.anchor.set(0.5, 0.5); skinTitleTxt.x = 2048 / 2; skinTitleTxt.y = 400; skinTitleTxt.alpha = 0; skinTitleTxt.visible = false; game.addChild(skinTitleTxt); var skinNameTxt = new Text2('Classic', { size: 60, fill: 0xFFFFFF }); skinNameTxt.anchor.set(0.5, 0.5); skinNameTxt.x = 2048 / 2; skinNameTxt.y = 2732 / 2 - 100; skinNameTxt.alpha = 0; skinNameTxt.visible = false; game.addChild(skinNameTxt); var prevBtn = new Text2('< PREV', { size: 50, fill: 0xFFFFFF }); prevBtn.anchor.set(0.5, 0.5); prevBtn.x = 2048 / 2 - 200; prevBtn.y = 2732 / 2 + 100; prevBtn.alpha = 0; prevBtn.visible = false; game.addChild(prevBtn); var nextBtn = new Text2('NEXT >', { size: 50, fill: 0xFFFFFF }); nextBtn.anchor.set(0.5, 0.5); nextBtn.x = 2048 / 2 + 200; nextBtn.y = 2732 / 2 + 100; nextBtn.alpha = 0; nextBtn.visible = false; game.addChild(nextBtn); var backBtn = new Text2('BACK', { size: 50, fill: 0xFF4444 }); backBtn.anchor.set(0.5, 0.5); backBtn.x = 2048 / 2; backBtn.y = 2732 / 2 + 200; backBtn.alpha = 0; backBtn.visible = false; game.addChild(backBtn); var skinPreviewBird = new Bird(); skinPreviewBird.x = 2048 / 2; skinPreviewBird.y = 2732 / 2; skinPreviewBird.alpha = 0; skinPreviewBird.visible = false; game.addChild(skinPreviewBird); // Cascade entrance animations for starting screen tween(titleTxt, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 1000, easing: tween.bounceOut }); LK.setTimeout(function () { // Animation slot reserved for future use }, 300); LK.setTimeout(function () { tween(bestScoreTxt, { alpha: 1 }, { duration: 800, easing: tween.easeOut }); tween(subtitleTxt, { alpha: 1 }, { duration: 600, easing: tween.easeOut }); }, 900); LK.setTimeout(function () { tween(skinBtnBorder, { alpha: 0.9, scaleX: 0.84, scaleY: 0.63 }, { duration: 800, easing: tween.bounceOut }); tween(skinBtnBg, { alpha: 1, scaleX: 0.8, scaleY: 0.6 }, { duration: 800, easing: tween.bounceOut }); tween(skinBtn, { alpha: 1 }, { duration: 1000, easing: tween.easeInOut }); }, 1200); // Title floating animation removed // Update best score display with stored value var storedBestScore = LK.getScore() || 0; bestScoreTxt.setText('BEST: ' + storedBestScore); // Create decorative sparkles for starting screen var sparkles = []; for (var i = 0; i < 8; i++) { var sparkle = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, alpha: 0 }); sparkle.x = 2048 / 2 + (Math.random() - 0.5) * 600; sparkle.y = 2732 / 2 - 350 + (Math.random() - 0.5) * 200; sparkles.push(sparkle); game.addChild(sparkle); } // Animate sparkles function animateSparkles() { for (var i = 0; i < sparkles.length; i++) { var sparkle = sparkles[i]; var delay = i * 200; LK.setTimeout(function (s) { return function () { tween(s, { alpha: 1, rotation: Math.PI * 2, scaleX: 0.5, scaleY: 0.5 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(s, { alpha: 0, scaleX: 0.3, scaleY: 0.3 }, { duration: 500, easing: tween.easeIn }); } }); }; }(sparkle), delay); } } LK.setTimeout(animateSparkles, 2000); // Initialize bird bird = new Bird(); bird.x = -100; // Start off screen bird.y = 2732 / 2; bird.invincible = false; game.addChild(bird); // Apply current skin bird.removeChildren(); var initialBirdGraphics = bird.attachAsset(skins[currentSkin].asset, { anchorX: 0.5, anchorY: 0.5 }); // Smooth entrance animation tween(bird, { x: 2048 / 4 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { // Floating animation removed // Rotation floating animation removed } }); // Initialize health display updateHealthDisplay(); // Initialize clouds for (var i = 0; i < 4; i++) { var cloud = new Cloud(); cloud.x = i * 500 + 200; cloud.y = 100 + Math.random() * 300; clouds.push(cloud); game.addChild(cloud); } // Initialize monkeys var monkey = new Monkey(); monkey.x = 2048 + 300; monkey.baseY = 200 + Math.random() * 400; monkey.y = monkey.baseY; monkeys.push(monkey); game.addChild(monkey); // Initialize spawn points for (var i = 0; i < 3; i++) { var spawnPoint = new SpawnPoint(); spawnPoint.x = 2048 + 200 + i * 400; spawnPoint.y = 300 + i * 200; spawnPoints.push(spawnPoint); game.addChild(spawnPoint); } // Initialize first few buildings for (var i = 0; i < 3; i++) { var building = new Building(); building.x = 300 + i * 300; building.y = 2732 - 100; buildings.push(building); game.addChildAt(building, 0); } // Initialize first few Building2 instances for (var i = 0; i < 2; i++) { var building2 = new Building2(); building2.x = 600 + i * 400; building2.y = 2732 - 100; buildings2.push(building2); game.addChildAt(building2, 0); } // Create ground ground = game.attachAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: 2732 - 100 }); // Add ground scrolling animation tween(ground, { x: -200 }, { duration: 4000, easing: tween.linear, onFinish: function onFinish() { ground.x = 0; tween(ground, { x: -200 }, { duration: 4000, easing: tween.linear, onFinish: arguments.callee }); } }); function spawnPipe() { var pipe = new Pipe(); pipe.x = 2048 + 100; // Start from right edge pipe.alpha = 1; // Start visible // Vary gap center position - keep it challenging but fair var baseY = 2732 / 2; var variation = 400; var gapCenterY = baseY + (Math.random() - 0.5) * variation; // Keep within reasonable bounds gapCenterY = Math.max(400, Math.min(2332, gapCenterY)); pipe.setupPipes(gapCenterY); pipes.push(pipe); // Add pipe at index 0 to ensure it stays behind buildings game.addChildAt(pipe, 0); // Spawn coin in the gap center (70% chance) if (Math.random() < 0.7) { var coin = new Coin(); coin.x = pipe.x; coin.y = gapCenterY; coin.alpha = 0; coins.push(coin); game.addChild(coin); // Coin entrance animation with slight delay tween(coin, { alpha: 1, scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.bounceOut, onFinish: function onFinish() { tween(coin, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeOut }); } }); } // Spawn power-up occasionally (15% chance) if (Math.random() < 0.15) { var powerUp = new PowerUp(); powerUp.x = pipe.x + 100; powerUp.y = gapCenterY + (Math.random() - 0.5) * 100; powerUps.push(powerUp); game.addChild(powerUp); } } function spawnBuilding() { var building = new Building(); building.x = 2048 + 100; // Start from right edge building.y = 2732 - 100; // Position on ground buildings.push(building); // Add building at index 0 to ensure it stays behind pipes and other game elements game.addChildAt(building, 0); } function spawnBuilding2() { var building2 = new Building2(); building2.x = 2048 + 150; // Start from right edge with slight offset building2.y = 2732 - 100; // Position on ground buildings2.push(building2); // Add building at index 0 to ensure it stays behind pipes and other game elements game.addChildAt(building2, 0); } function checkScore() { for (var i = 0; i < pipes.length; i++) { var pipe = pipes[i]; if (!pipe.scored && pipe.x < bird.x) { pipe.scored = true; var points = Math.floor(1 * comboMultiplier); LK.setScore(LK.getScore() + points); scoreTxt.setText(LK.getScore().toString()); LK.getSound('score').play(); // Update combo display if (comboMultiplier > 1) { comboTxt.setText('COMBO x' + comboMultiplier.toFixed(1)); tween(comboTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(comboTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeOut }); } }); } else { comboTxt.setText(''); } // Score animation tween(scoreTxt, { scaleX: 1.3, scaleY: 1.3 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(scoreTxt, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150, easing: tween.easeOut }); } }); } } } function updateHealthDisplay() { var hearts = ''; for (var i = 0; i < playerHealth; i++) { hearts += '♥ '; } for (var i = playerHealth; i < 3; i++) { hearts += '♡ '; } healthTxt.setText(hearts.trim()); } function spawnParticles(x, y, count, color) { for (var i = 0; i < count; i++) { var particle = new Particle(); particle.x = x + (Math.random() - 0.5) * 40; particle.y = y + (Math.random() - 0.5) * 40; particle.velocityX = (Math.random() - 0.5) * 8; particle.velocityY = (Math.random() - 0.5) * 8 - 2; if (color) { particle.children[0].tint = color; } particles.push(particle); game.addChild(particle); } } function checkCoinCollection() { for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; if (!coin.collected && coin.checkCollection(bird)) { coin.collected = true; var points = 5 * comboMultiplier; LK.setScore(LK.getScore() + points); scoreTxt.setText(LK.getScore().toString()); LK.getSound('score').play(); // Spawn particle effects spawnParticles(coin.x, coin.y, 6, 0xFFD700); // Increase combo comboMultiplier = Math.min(5, comboMultiplier + 0.5); comboTimer = 180; // 3 seconds coin.destroy(); coins.splice(i, 1); } } } function checkPowerUpCollection() { for (var i = powerUps.length - 1; i >= 0; i--) { var powerUp = powerUps[i]; if (!powerUp.collected && powerUp.checkCollection(bird)) { powerUp.collected = true; // Apply power-up effect if (powerUp.type === 'shield') { bird.shieldActive = true; bird.shieldTimer = 300; // 5 seconds } else if (powerUp.type === 'speed') { bird.speedBoostActive = true; bird.speedBoostTimer = 180; // 3 seconds } LK.getSound('score').play(); spawnParticles(powerUp.x, powerUp.y, 8, 0xFF4444); powerUp.destroy(); powerUps.splice(i, 1); } } } function checkCollisions() { // Check pipe collisions for (var i = 0; i < pipes.length; i++) { if (pipes[i].checkCollision(bird)) { return true; } } // Check ground collision if (bird.y + 30 > ground.y) { return true; } // Check ceiling collision if (bird.y - 30 < 0) { return true; } return false; } function takeDamage() { if (playerHealth > 0) { playerHealth--; updateHealthDisplay(); // Flash screen red to indicate damage LK.effects.flashScreen(0xff0000, 500); LK.getSound('hit').play(); // Make bird temporarily invincible bird.invincible = true; // Remove invincibility after 2 seconds LK.setTimeout(function () { bird.invincible = false; }, 2000); // Check if health is depleted if (playerHealth <= 0) { gameOver(); } } } function gameOver() { gameActive = false; LK.getSound('hit').play(); // Stop bird movement bird.velocity = 0; // Flash screen red LK.effects.flashScreen(0xff0000, 1000); // Show game over after a brief delay LK.setTimeout(function () { LK.showGameOver(); }, 500); } function showSkinSelection() { skinShowMode = true; // Hide main menu elements titleTxt.visible = false; subtitleTxt.visible = false; bestScoreTxt.visible = false; skinBtn.visible = false; skinBtnBg.visible = false; skinBtnBorder.visible = false; for (var i = 0; i < sparkles.length; i++) { sparkles[i].visible = false; } // Show skin selection elements skinTitleTxt.visible = true; skinNameTxt.visible = true; prevBtn.visible = true; nextBtn.visible = true; backBtn.visible = true; skinPreviewBird.visible = true; // Animate skin UI entrance tween(skinTitleTxt, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(skinNameTxt, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(prevBtn, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(nextBtn, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(backBtn, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(skinPreviewBird, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); updateSkinPreview(); } function hideSkinSelection() { skinShowMode = false; // Hide skin selection elements tween(skinTitleTxt, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { skinTitleTxt.visible = false; } }); tween(skinNameTxt, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { skinNameTxt.visible = false; } }); tween(prevBtn, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { prevBtn.visible = false; if (gameStarted) prevBtn.destroy(); } }); tween(nextBtn, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { nextBtn.visible = false; if (gameStarted) nextBtn.destroy(); } }); tween(backBtn, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { backBtn.visible = false; if (gameStarted) backBtn.destroy(); } }); tween(skinPreviewBird, { alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { skinPreviewBird.visible = false; } }); // Show main menu elements LK.setTimeout(function () { titleTxt.visible = true; subtitleTxt.visible = true; bestScoreTxt.visible = true; skinBtn.visible = true; skinBtnBg.visible = true; skinBtnBorder.visible = true; for (var i = 0; i < sparkles.length; i++) { sparkles[i].visible = true; } tween(titleTxt, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(subtitleTxt, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(bestScoreTxt, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(skinBtnBorder, { alpha: 0.9 }, { duration: 500, easing: tween.easeOut }); tween(skinBtnBg, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); tween(skinBtn, { alpha: 1 }, { duration: 500, easing: tween.easeOut }); }, 300); } function updateSkinPreview() { var skin = skins[currentSkin]; skinNameTxt.setText(skin.name); // Update preview bird skin skinPreviewBird.removeChildren(); var newBirdGraphics = skinPreviewBird.attachAsset(skin.asset, { anchorX: 0.5, anchorY: 0.5 }); // Floating animation removed from preview bird } function changeSkin(direction) { currentSkin += direction; if (currentSkin < 0) { currentSkin = skins.length - 1; } else if (currentSkin >= skins.length) { currentSkin = 0; } updateSkinPreview(); // Update actual bird skin bird.removeChildren(); var newBirdGraphics = bird.attachAsset(skins[currentSkin].asset, { anchorX: 0.5, anchorY: 0.5 }); } function changeWeather() { currentWeather = (currentWeather + 1) % weatherTypes.length; var weather = weatherTypes[currentWeather]; // Smooth background color transition var currentColor = game.backgroundColor; var newColor = weather.bgColor; var steps = 120; // 2 second transition var stepCount = 0; var transitionColor = function transitionColor() { if (stepCount < steps) { var t = stepCount / steps; var r1 = currentColor >> 16 & 0xFF; var g1 = currentColor >> 8 & 0xFF; var b1 = currentColor & 0xFF; var r2 = newColor >> 16 & 0xFF; var g2 = newColor >> 8 & 0xFF; var b2 = newColor & 0xFF; var r = Math.floor(r1 + (r2 - r1) * t); var g = Math.floor(g1 + (g2 - g1) * t); var b = Math.floor(b1 + (b2 - b1) * t); game.setBackgroundColor(r << 16 | g << 8 | b); stepCount++; } }; var colorTransitionInterval = LK.setInterval(transitionColor, 16); LK.setTimeout(function () { LK.clearInterval(colorTransitionInterval); }, 2000); // Update cloud properties for weather effect for (var i = 0; i < clouds.length; i++) { var cloud = clouds[i]; cloud.speed = -weather.cloudSpeed; tween(cloud, { alpha: weather.cloudAlpha }, { duration: 2000, easing: tween.easeInOut }); } // Update weather display weatherTxt.setText('Weather: ' + weather.name); // Add weather-specific visual effects if (weather.name === 'Stormy') { // Screen flash effect for lightning LK.setTimeout(function () { LK.effects.flashScreen(0xFFFFFF, 200); }, 1000); } } // Touch/tap handler game.down = function (x, y, obj) { if (!gameStarted) { // Floating animations removed if (skinShowMode) { // Check skin selection UI clicks var prevBounds = { left: prevBtn.x - 75, right: prevBtn.x + 75, top: prevBtn.y - 30, bottom: prevBtn.y + 30 }; var nextBounds = { left: nextBtn.x - 75, right: nextBtn.x + 75, top: nextBtn.y - 30, bottom: nextBtn.y + 30 }; var backBounds = { left: backBtn.x - 50, right: backBtn.x + 50, top: backBtn.y - 30, bottom: backBtn.y + 30 }; if (x >= prevBounds.left && x <= prevBounds.right && y >= prevBounds.top && y <= prevBounds.bottom) { // Previous skin button tween(prevBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(prevBtn, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); changeSkin(-1); // Hide skin selection panel after skin is chosen hideSkinSelection(); return; } else if (x >= nextBounds.left && x <= nextBounds.right && y >= nextBounds.top && y <= nextBounds.bottom) { // Next skin button tween(nextBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(nextBtn, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); changeSkin(1); // Hide skin selection panel after skin is chosen hideSkinSelection(); return; } else if (x >= backBounds.left && x <= backBounds.right && y >= backBounds.top && y <= backBounds.bottom) { // Back button - return to main menu only tween(backBtn, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(backBtn, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); // Hide skin selection and return to main menu hideSkinSelection(); return; } } else { // Check if skin button was clicked var skinBounds = { left: skinBtn.x - 120, right: skinBtn.x + 120, top: skinBtn.y - 30, bottom: skinBtn.y + 30 }; if (x >= skinBounds.left && x <= skinBounds.right && y >= skinBounds.top && y <= skinBounds.bottom) { // Check if this is a long press for skin selection or quick tap for start var pressStartTime = Date.now(); var longPressThreshold = 500; // 500ms for long press var longPressTimer = LK.setTimeout(function () { // Long press - show skin selection tween(skinBtn, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(skinBtn, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); tween(skinBtnBorder, { scaleX: 0.76, scaleY: 0.57, tint: 0x1B5E20 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(skinBtnBorder, { scaleX: 0.84, scaleY: 0.63, tint: 0x2E7D32 }, { duration: 100, easing: tween.easeOut }); } }); tween(skinBtnBg, { scaleX: 0.76, scaleY: 0.57, tint: 0x45A049 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(skinBtnBg, { scaleX: 0.8, scaleY: 0.6, tint: 0x4CAF50 }, { duration: 100, easing: tween.easeOut }); } }); showSkinSelection(); }, longPressThreshold); // Store the timer for potential cancellation game.longPressTimer = longPressTimer; return; } } // Note: Game start logic moved to up handler for shared button functionality } // Check if game is prepared but not yet active (waiting for touch to start) if (gameStarted && !gameActive) { // First touch after start button - actually start the game gameActive = true; // Spawn first pipe with delay LK.setTimeout(function () { spawnPipe(); }, 800); bird.flap(); return; } if (gameActive) { bird.flap(); } }; // Touch/tap up handler for shared button functionality game.up = function (x, y, obj) { if (!gameStarted && !skinShowMode && game.longPressTimer) { // Cancel long press timer LK.clearTimeout(game.longPressTimer); game.longPressTimer = null; // Check if this was a quick tap on the shared button var skinBounds = { left: skinBtn.x - 120, right: skinBtn.x + 120, top: skinBtn.y - 30, bottom: skinBtn.y + 30 }; if (x >= skinBounds.left && x <= skinBounds.right && y >= skinBounds.top && y <= skinBounds.bottom) { // Quick tap - prepare game but don't start yet gameStarted = true; gameActive = false; // Game is prepared but not active yet // Hide all starting screen elements with staggered animations tween(titleTxt, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { titleTxt.visible = false; } }); tween(subtitleTxt, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { subtitleTxt.visible = false; } }); // Additional entrance animations can be added here if needed tween(bestScoreTxt, { alpha: 0, y: bestScoreTxt.y + 50 }, { duration: 250, easing: tween.easeIn, onFinish: function onFinish() { bestScoreTxt.visible = false; } }); // Hide skin button when game starts tween(skinBtn, { alpha: 0, scaleX: 0.8, scaleY: 0.8 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { skinBtn.visible = false; skinBtn.destroy(); } }); tween(skinBtnBg, { alpha: 0, scaleX: 0.64, scaleY: 0.48 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { skinBtnBg.visible = false; skinBtnBg.destroy(); } }); tween(skinBtnBorder, { alpha: 0, scaleX: 0.64, scaleY: 0.48 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { skinBtnBorder.visible = false; skinBtnBorder.destroy(); } }); // Hide sparkles when game starts for (var i = 0; i < sparkles.length; i++) { tween(sparkles[i], { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 400, easing: tween.easeIn, onFinish: function (sparkle) { return function () { sparkle.visible = false; }; }(sparkles[i]) }); } // Don't spawn pipes yet - wait for touch to start // Bird will start flying when user first touches screen // Removed hover mode - bird stays stationary } } }; // Main game loop game.update = function () { // Weather change system if (gameStarted && gameActive) { weatherChangeTimer++; if (weatherChangeTimer >= weatherChangeInterval) { changeWeather(); weatherChangeTimer = 0; } } // Always update background elements for ambiance for (var i = 0; i < clouds.length; i++) { clouds[i].update(); } for (var i = 0; i < monkeys.length; i++) { monkeys[i].update(); } if (!gameStarted || !gameActive) { return; } // Update difficulty level difficultyLevel = Math.floor(LK.getScore() / 15) + 1; // Update combo system if (comboTimer > 0) { comboTimer--; } else { comboMultiplier = Math.max(1, comboMultiplier - 0.1); } // Update bird bird.update(); // Render bird wing trails for (var i = 0; i < bird.trail.length; i++) { var trailPoint = bird.trail[i]; if (trailPoint.isWingTrail) { var alpha = trailPoint.life / 15; var size = alpha * 0.3; // Create wing trail particles if (i % 2 === 0 && alpha > 0.3) { var wingParticle = new Particle(); wingParticle.x = trailPoint.x + (Math.random() - 0.5) * 20; wingParticle.y = trailPoint.y + (Math.random() - 0.5) * 20; wingParticle.velocityX = (Math.random() - 0.5) * 2; wingParticle.velocityY = (Math.random() - 0.5) * 2; wingParticle.life = 20; wingParticle.children[0].tint = 0x87CEEB; wingParticle.children[0].alpha = alpha * 0.5; wingParticle.children[0].scaleX = size; wingParticle.children[0].scaleY = size; particles.push(wingParticle); game.addChild(wingParticle); } } trailPoint.life--; } // Remove dead trail points for (var i = bird.trail.length - 1; i >= 0; i--) { if (bird.trail[i].life <= 0) { bird.trail.splice(i, 1); } } // Update particles for (var i = particles.length - 1; i >= 0; i--) { particles[i].update(); if (particles[i].life <= 0) { particles[i].destroy(); particles.splice(i, 1); } } // Update pipes for (var i = pipes.length - 1; i >= 0; i--) { pipes[i].update(); // Remove pipes that have moved off screen if (pipes[i].x < -120) { pipes[i].destroy(); pipes.splice(i, 1); } } // Update coins for (var i = coins.length - 1; i >= 0; i--) { coins[i].update(); // Remove coins that have moved off screen if (coins[i].x < -120) { coins[i].destroy(); coins.splice(i, 1); } } // Update power-ups for (var i = powerUps.length - 1; i >= 0; i--) { powerUps[i].update(); if (powerUps[i].x < -120) { powerUps[i].destroy(); powerUps.splice(i, 1); } } // Update spawn points for (var i = 0; i < spawnPoints.length; i++) { spawnPoints[i].update(); // Move spawn points left spawnPoints[i].x -= 2; // Reset spawn point position when it goes off screen if (spawnPoints[i].x < -100) { spawnPoints[i].x = 2048 + 200; spawnPoints[i].y = 300 + Math.random() * 400; } } // Update buildings for (var i = buildings.length - 1; i >= 0; i--) { buildings[i].update(); // Remove buildings that have moved off screen if (buildings[i].x < -200) { buildings[i].destroy(); buildings.splice(i, 1); } } // Update buildings2 for (var i = buildings2.length - 1; i >= 0; i--) { buildings2[i].update(); // Remove buildings2 that have moved off screen if (buildings2[i].x < -250) { buildings2[i].destroy(); buildings2.splice(i, 1); } } // Spawn new pipes with consistent timing pipeSpawnTimer++; if (pipeSpawnTimer >= pipeSpawnInterval) { spawnPipe(); pipeSpawnTimer = 0; } // Spawn new buildings buildingSpawnTimer++; if (buildingSpawnTimer >= buildingSpawnInterval) { spawnBuilding(); buildingSpawnTimer = 0; } // Spawn new Building2 instances building2SpawnTimer++; if (building2SpawnTimer >= building2SpawnInterval) { spawnBuilding2(); building2SpawnTimer = 0; } // Check for score checkScore(); // Check for coin collection checkCoinCollection(); // Check for power-up collection checkPowerUpCollection(); // Check for collisions (shield protects from damage) if (checkCollisions() && !bird.invincible && !bird.shieldActive) { takeDamage(); } // Screen shake effect when bird is close to pipes for (var i = 0; i < pipes.length; i++) { var distance = Math.abs(bird.x - pipes[i].x); if (distance < 100) { var intensity = (100 - distance) / 100 * 2; game.x = (Math.random() - 0.5) * intensity; game.y = (Math.random() - 0.5) * intensity; break; } else { game.x = 0; game.y = 0; } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocity = 0;
self.gravity = 0.8;
self.flapStrength = -12;
self.maxFallSpeed = 15;
self.rotation = 0;
self.animationTimer = 0;
self.invincible = false;
self.shieldActive = false;
self.shieldTimer = 0;
self.speedBoostActive = false;
self.speedBoostTimer = 0;
self.trail = [];
self.flap = function () {
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Wing flapping animation - quick upward flap
tween(birdGraphics, {
scaleY: 1.3,
scaleX: 0.8
}, {
duration: 80,
easing: tween.easeOut
});
tween(birdGraphics, {
scaleY: 1.0,
scaleX: 1.0
}, {
duration: 120,
easing: tween.easeIn
});
// Slight upward rotation on flap
tween(birdGraphics, {
rotation: -0.4
}, {
duration: 150,
easing: tween.easeOut
});
};
self.update = function () {
// Apply gravity only when game has started
if (gameStarted && gameActive) {
// Apply gravity (reduced if speed boost active)
var currentGravity = self.speedBoostActive ? self.gravity * 0.7 : self.gravity;
self.velocity += currentGravity;
// Limit fall speed
if (self.velocity > self.maxFallSpeed) {
self.velocity = self.maxFallSpeed;
}
// Update position with swooping effect
self.y += self.velocity;
// Add swooping animation during fast descent
if (gameStarted && gameActive && self.velocity > 8) {
var swoopIntensity = (self.velocity - 8) * 0.02;
var swoopCycle = Math.sin(LK.ticks * 0.4);
birdGraphics.x = swoopCycle * swoopIntensity * 10;
// Wing tucking during fast descent
tween.stop(birdGraphics, {
scaleX: true
});
tween(birdGraphics, {
scaleX: 0.8 - swoopIntensity
}, {
duration: 200,
easing: tween.easeOut
});
}
}
// Smooth rotation based on velocity with gliding effect
var targetRotation = Math.min(self.velocity * 0.08, 1.2);
if (self.velocity < 0) {
targetRotation = Math.max(self.velocity * 0.08, -0.4);
// Add gliding wing extension when rising
if (gameStarted && gameActive) {
var glideIntensity = Math.min(-self.velocity * 0.05, 0.3);
tween.stop(birdGraphics, {
scaleX: true
});
tween(birdGraphics, {
scaleX: 1.0 + glideIntensity
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Smooth rotation transition
tween.stop(birdGraphics, {
rotation: true
});
tween(birdGraphics, {
rotation: targetRotation
}, {
duration: 200,
easing: tween.easeOut
});
// Enhanced continuous wing flapping animation when flying
if (gameStarted && gameActive) {
self.animationTimer += 0.3;
var flapCycle = Math.sin(self.animationTimer);
var fastFlap = Math.sin(self.animationTimer * 2);
// Wing flapping effect - compress and stretch with double beat
var flapIntensity = 0.2;
var microFlap = 0.05;
birdGraphics.scaleY = 1.0 + flapCycle * flapIntensity + fastFlap * microFlap;
birdGraphics.scaleX = 1.0 - flapCycle * flapIntensity * 0.7 - fastFlap * microFlap;
// Add subtle wing position shifts
var wingShift = Math.cos(self.animationTimer * 1.5) * 0.8;
birdGraphics.x = wingShift;
} else {
// Enhanced floating animation when idle
if (Math.abs(self.velocity) < 2) {
self.animationTimer += 0.1;
var bob = Math.sin(self.animationTimer) * 3;
var sway = Math.cos(self.animationTimer * 0.7) * 1.5;
birdGraphics.y = bob;
birdGraphics.x = sway;
// Gentle scale breathing effect
var breathe = Math.sin(self.animationTimer * 0.5) * 0.05 + 1;
birdGraphics.scaleX = breathe;
birdGraphics.scaleY = breathe;
}
}
// Update power-up timers
if (self.shieldActive) {
self.shieldTimer--;
if (self.shieldTimer <= 0) {
self.shieldActive = false;
}
}
if (self.speedBoostActive) {
self.speedBoostTimer--;
if (self.speedBoostTimer <= 0) {
self.speedBoostActive = false;
}
}
// Visual effects for active power-ups
if (self.shieldActive) {
var shieldPulse = Math.sin(LK.ticks * 0.2) * 0.3 + 0.7;
birdGraphics.tint = 0x4488FF;
birdGraphics.alpha = shieldPulse;
} else if (self.speedBoostActive) {
birdGraphics.tint = 0xFF4444;
birdGraphics.alpha = 0.9;
} else if (self.invincible) {
birdGraphics.alpha = 0.5 + 0.5 * Math.sin(LK.ticks * 0.3);
birdGraphics.tint = 0xFFFFFF;
} else {
birdGraphics.alpha = 1;
birdGraphics.tint = 0xFFFFFF;
}
// Add wing trail effect during flapping
if (gameStarted && gameActive) {
self.trail.push({
x: self.x,
y: self.y,
life: 15,
isWingTrail: true
});
if (self.trail.length > 12) {
self.trail.shift();
}
} else {
// Regular trail when not flapping
self.trail.push({
x: self.x,
y: self.y,
life: 10
});
if (self.trail.length > 8) {
self.trail.shift();
}
}
};
return self;
});
var Building = Container.expand(function () {
var self = Container.call(this);
// Random building height - much taller
self.buildingHeight = 300 + Math.random() * 400;
// Create building structure
var buildingGraphics = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 1,
scaleY: self.buildingHeight / 400,
scaleX: 1.8 // Same as Building2
});
// Add windows to building
self.windows = [];
var windowRows = Math.floor(self.buildingHeight / 20); // Same spacing as Building2
var windowCols = 4; // Same as Building2
for (var row = 0; row < windowRows; row++) {
for (var col = 0; col < windowCols; col++) {
if (Math.random() < 0.7) {
// 70% chance for lit window
var window = self.attachAsset('buildingWindow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
// Same as Building2
scaleY: 0.5
});
window.x = -135 + col * 90; // Same spacing as Building2
window.y = -self.buildingHeight + 12 + row * 20; // Same spacing as Building2
self.windows.push(window);
}
}
}
self.speed = -2;
self.update = function () {
self.x += self.speed;
// Flicker windows randomly
for (var i = 0; i < self.windows.length; i++) {
if (Math.random() < 0.01) {
// 1% chance to flicker
self.windows[i].alpha = Math.random() < 0.5 ? 0.3 : 1.0;
}
// Add flying/flapping animation to windows
if (Math.random() < 0.005) {
// 0.5% chance for window to "fly" with wing-like animation
var window = self.windows[i];
// Wing flap animation - quick scale change
tween(window, {
scaleX: 1.5,
scaleY: 0.8,
rotation: 0.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(window, {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
}
}
};
return self;
});
var Building2 = Container.expand(function () {
var self = Container.call(this);
// Same building height range as Building - much taller
self.buildingHeight = 300 + Math.random() * 400;
// Create building structure with different scaling
var buildingGraphics = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 1,
scaleY: self.buildingHeight / 400,
scaleX: 1.8 // Larger than Building 1
});
// Tint building slightly different color
buildingGraphics.tint = 0xCCCCCC;
// Add windows to building with different pattern
self.windows = [];
var windowRows = Math.floor(self.buildingHeight / 20); // Closer spacing
var windowCols = 4; // Fewer columns for smaller building
for (var row = 0; row < windowRows; row++) {
for (var col = 0; col < windowCols; col++) {
if (Math.random() < 0.8) {
// 80% chance for lit window
var window = self.attachAsset('buildingWindow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
window.x = -135 + col * 90; // Adjusted spacing for larger building
window.y = -self.buildingHeight + 12 + row * 20;
// Random window colors for variety
var windowColors = [0xFFFF88, 0x88FFFF, 0xFF88FF, 0xFFFFFF];
window.tint = windowColors[Math.floor(Math.random() * windowColors.length)];
self.windows.push(window);
}
}
}
self.speed = -2;
self.update = function () {
self.x += self.speed;
// Different flicker pattern - faster flicker
for (var i = 0; i < self.windows.length; i++) {
if (Math.random() < 0.02) {
// 2% chance to flicker (faster than Building)
self.windows[i].alpha = Math.random() < 0.3 ? 0.2 : 1.0;
}
// Add flying/flapping animation to Building2 windows with different pattern
if (Math.random() < 0.008) {
// 0.8% chance for window to "fly" with butterfly-like animation
var window = self.windows[i];
// Butterfly wing flap animation - more elegant movement
tween(window, {
scaleX: 1.3,
scaleY: 1.4,
rotation: -0.3,
y: window.y - 10
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(window, {
scaleX: 0.9,
scaleY: 1.1,
rotation: 0.3,
y: window.y + 5
}, {
duration: 180,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(window, {
scaleX: 1.0,
scaleY: 1.0,
rotation: 0,
y: window.y
}, {
duration: 220,
easing: tween.easeIn
});
}
});
}
});
}
}
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
var cloudGraphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1;
self.update = function () {
self.x += self.speed;
// Reset position when off screen
if (self.x < -200) {
self.x = 2048 + 200;
self.y = 100 + Math.random() * 300;
}
};
return self;
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -4;
self.collected = false;
self.update = function () {
self.x += self.speed;
// Simple rotation animation
coinGraphics.rotation += 0.1;
};
self.checkCollection = function (bird) {
var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2));
return distance < 35; // Collection radius
};
return self;
});
var Monkey = Container.expand(function () {
var self = Container.call(this);
var monkeyGraphics = self.attachAsset('monkey', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = -1.5;
self.verticalSpeed = 0;
self.bounceHeight = 50;
self.animationTimer = 0;
self.direction = 1; // 1 for right, -1 for left
self.baseY = 0;
self.update = function () {
// Horizontal movement - only right
self.x += Math.abs(self.speed);
// Bouncing animation
self.animationTimer += 0.08;
self.y = self.baseY + Math.sin(self.animationTimer) * self.bounceHeight;
// Reset position when off screen
if (self.x > 2048 + 100) {
self.x = -100;
self.baseY = 200 + Math.random() * 400;
}
};
return self;
});
var Particle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.life = 60;
self.maxLife = 60;
self.gravity = 0.2;
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.velocityY += self.gravity;
self.life--;
// Fade out over time
var alpha = self.life / self.maxLife;
particleGraphics.alpha = alpha;
particleGraphics.scaleX = alpha * 0.5;
particleGraphics.scaleY = alpha * 0.5;
// Rotation
particleGraphics.rotation += 0.1;
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.gapHeight = 260;
self.speed = -4;
self.scored = false;
// Create top pipe
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1
});
// Create bottom pipe
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0
});
// Add pipe caps for authentic look
self.topCap = LK.getAsset('pipe', {
anchorX: 0.5,
anchorY: 1,
scaleX: 1.2,
scaleY: 0.1
});
self.bottomCap = LK.getAsset('pipe', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.2,
scaleY: 0.1
});
self.addChild(self.topCap);
self.addChild(self.bottomCap);
self.setupPipes = function (gapCenterY) {
self.topPipe.y = gapCenterY - self.gapHeight / 2;
self.bottomPipe.y = gapCenterY + self.gapHeight / 2;
self.topCap.y = self.topPipe.y;
self.bottomCap.y = self.bottomPipe.y;
};
self.update = function () {
self.x += self.speed;
};
self.checkCollision = function (bird) {
var birdRadius = 30;
var pipeWidth = 62;
var birdBounds = {
left: bird.x - birdRadius,
right: bird.x + birdRadius,
top: bird.y - birdRadius,
bottom: bird.y + birdRadius
};
var pipeBounds = {
left: self.x - pipeWidth,
right: self.x + pipeWidth,
topBottom: self.topPipe.y,
bottomTop: self.bottomPipe.y
};
// Check if bird is within pipe horizontal bounds
if (birdBounds.right > pipeBounds.left && birdBounds.left < pipeBounds.right) {
// Check collision with top or bottom pipe
if (birdBounds.top < pipeBounds.topBottom || birdBounds.bottom > pipeBounds.bottomTop) {
return true;
}
}
return false;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
var powerUpGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
powerUpGraphics.tint = 0xFF4444; // Red tint for power-up
self.speed = -4;
self.collected = false;
self.type = 'shield'; // shield, speed, score
self.animationTimer = 0;
self.update = function () {
self.x += self.speed;
self.animationTimer += 0.1;
// Pulsing animation
var pulse = Math.sin(self.animationTimer) * 0.3 + 1;
powerUpGraphics.scaleX = pulse;
powerUpGraphics.scaleY = pulse;
// Rotation
powerUpGraphics.rotation += 0.05;
// Glowing effect
var glow = Math.sin(self.animationTimer * 2) * 0.3 + 0.7;
powerUpGraphics.alpha = glow;
};
self.checkCollection = function (bird) {
var distance = Math.sqrt(Math.pow(bird.x - self.x, 2) + Math.pow(bird.y - self.y, 2));
return distance < 40;
};
return self;
});
var SpawnPoint = Container.expand(function () {
var self = Container.call(this);
self.isActive = true;
self.spawnType = 'pipe'; // 'pipe' or 'coin'
self.cooldownTimer = 0;
self.cooldownDuration = 60; // 1 second at 60fps
// Create visual marker for spawn point
var marker = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
self.addChild(marker);
self.marker = marker;
self.update = function () {
if (self.cooldownTimer > 0) {
self.cooldownTimer--;
self.marker.alpha = 0.3; // Dim when on cooldown
} else {
self.marker.alpha = 1.0; // Bright when ready
}
// Pulse animation
self.marker.rotation += 0.05;
var pulse = Math.sin(LK.ticks * 0.1) * 0.1 + 1;
self.marker.scaleX = 0.5 * pulse;
self.marker.scaleY = 0.5 * pulse;
};
self.canSpawn = function () {
return self.isActive && self.cooldownTimer <= 0;
};
self.triggerSpawn = function () {
if (self.canSpawn()) {
self.cooldownTimer = self.cooldownDuration;
return true;
}
return false;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var bird;
var pipes = [];
var coins = [];
var spawnPoints = [];
var clouds = [];
var monkeys = [];
var particles = [];
var powerUps = [];
var buildings = [];
var buildings2 = [];
var ground;
var gameStarted = false;
var gameActive = true;
var pipeSpawnTimer = 0;
var pipeSpawnInterval = 150; // 2.5 seconds at 60fps
var buildingSpawnTimer = 0;
var buildingSpawnInterval = 200; // 3.33 seconds at 60fps
var building2SpawnTimer = 0;
var building2SpawnInterval = 280; // 4.67 seconds at 60fps
var playerHealth = 3;
var bestScore = 0;
var dayTime = true;
var lastColorChangeScore = 0;
var currentSkin = 0;
var skinShowMode = false;
var currentWeather = 0;
var weatherChangeTimer = 0;
var weatherChangeInterval = 1800; // 30 seconds at 60fps
var comboMultiplier = 1;
var comboTimer = 0;
var difficultyLevel = 1;
var weatherTypes = [{
name: 'Sunny',
bgColor: 0x87CEEB,
cloudAlpha: 0.8,
cloudSpeed: 1
}, {
name: 'Cloudy',
bgColor: 0x708090,
cloudAlpha: 1.0,
cloudSpeed: 1.5
}, {
name: 'Stormy',
bgColor: 0x2F4F4F,
cloudAlpha: 1.2,
cloudSpeed: 2.0
}, {
name: 'Sunset',
bgColor: 0xFF6B35,
cloudAlpha: 0.9,
cloudSpeed: 0.8
}, {
name: 'Night',
bgColor: 0x191970,
cloudAlpha: 0.6,
cloudSpeed: 0.5
}];
var skins = [{
name: 'Classic',
asset: 'bird'
}, {
name: 'Red Fire',
asset: 'bird_red'
}, {
name: 'Blue Ice',
asset: 'bird_blue'
}, {
name: 'Green Forest',
asset: 'bird_green'
}, {
name: 'Golden King',
asset: 'bird_golden'
}];
// Create score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create health display
var healthTxt = new Text2('♥ ♥ ♥', {
size: 60,
fill: 0xFF0000
});
healthTxt.anchor.set(1, 0);
healthTxt.x = -20; // Position from right edge
healthTxt.y = 20;
LK.gui.topRight.addChild(healthTxt);
// Create weather display
var weatherTxt = new Text2('Weather: Sunny', {
size: 40,
fill: 0xFFFFFF
});
weatherTxt.anchor.set(0, 0);
weatherTxt.x = 20;
weatherTxt.y = 20;
LK.gui.topLeft.addChild(weatherTxt);
// Create combo display
var comboTxt = new Text2('', {
size: 50,
fill: 0xFFD700
});
comboTxt.anchor.set(0.5, 0);
comboTxt.x = 0;
comboTxt.y = 100;
LK.gui.top.addChild(comboTxt);
// Create game title
var titleTxt = new Text2('FLAPPY BIRD', {
size: 120,
fill: 0xFFD700
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 2048 / 2;
titleTxt.y = 2732 / 2 - 400;
titleTxt.alpha = 0;
game.addChild(titleTxt);
// Create subtitle text under title
var subtitleTxt = new Text2('Tap to Fly Through Pipes', {
size: 50,
fill: 0xFFFFFF
});
subtitleTxt.anchor.set(0.5, 0.5);
subtitleTxt.x = 2048 / 2;
subtitleTxt.y = 2732 / 2 - 320;
subtitleTxt.alpha = 0;
game.addChild(subtitleTxt);
// Create best score display
var bestScoreTxt = new Text2('BEST: 0', {
size: 45,
fill: 0xFFD700
});
bestScoreTxt.anchor.set(0.5, 0.5);
bestScoreTxt.x = 2048 / 2;
bestScoreTxt.y = 2732 / 2 - 100;
bestScoreTxt.alpha = 0;
game.addChild(bestScoreTxt);
// Create shared start/skin button
var skinBtn = new Text2('START / SKINS', {
size: 50,
fill: 0xFFFFFF
});
skinBtn.anchor.set(0.5, 0.5);
skinBtn.x = 2048 / 2;
skinBtn.y = 2732 / 2 + 50;
skinBtn.alpha = 0;
game.addChild(skinBtn);
// Create skin button background
var skinBtnBg = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.6
});
skinBtnBg.x = 2048 / 2;
skinBtnBg.y = 2732 / 2 + 50;
skinBtnBg.alpha = 0;
game.addChild(skinBtnBg);
var skinBtnBorder = LK.getAsset('startButtonBorder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.6
});
skinBtnBorder.x = 2048 / 2;
skinBtnBorder.y = 2732 / 2 + 50;
skinBtnBorder.alpha = 0;
game.addChild(skinBtnBorder);
// Create skin selection UI
var skinTitleTxt = new Text2('SELECT SKIN', {
size: 80,
fill: 0xFFD700
});
skinTitleTxt.anchor.set(0.5, 0.5);
skinTitleTxt.x = 2048 / 2;
skinTitleTxt.y = 400;
skinTitleTxt.alpha = 0;
skinTitleTxt.visible = false;
game.addChild(skinTitleTxt);
var skinNameTxt = new Text2('Classic', {
size: 60,
fill: 0xFFFFFF
});
skinNameTxt.anchor.set(0.5, 0.5);
skinNameTxt.x = 2048 / 2;
skinNameTxt.y = 2732 / 2 - 100;
skinNameTxt.alpha = 0;
skinNameTxt.visible = false;
game.addChild(skinNameTxt);
var prevBtn = new Text2('< PREV', {
size: 50,
fill: 0xFFFFFF
});
prevBtn.anchor.set(0.5, 0.5);
prevBtn.x = 2048 / 2 - 200;
prevBtn.y = 2732 / 2 + 100;
prevBtn.alpha = 0;
prevBtn.visible = false;
game.addChild(prevBtn);
var nextBtn = new Text2('NEXT >', {
size: 50,
fill: 0xFFFFFF
});
nextBtn.anchor.set(0.5, 0.5);
nextBtn.x = 2048 / 2 + 200;
nextBtn.y = 2732 / 2 + 100;
nextBtn.alpha = 0;
nextBtn.visible = false;
game.addChild(nextBtn);
var backBtn = new Text2('BACK', {
size: 50,
fill: 0xFF4444
});
backBtn.anchor.set(0.5, 0.5);
backBtn.x = 2048 / 2;
backBtn.y = 2732 / 2 + 200;
backBtn.alpha = 0;
backBtn.visible = false;
game.addChild(backBtn);
var skinPreviewBird = new Bird();
skinPreviewBird.x = 2048 / 2;
skinPreviewBird.y = 2732 / 2;
skinPreviewBird.alpha = 0;
skinPreviewBird.visible = false;
game.addChild(skinPreviewBird);
// Cascade entrance animations for starting screen
tween(titleTxt, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1000,
easing: tween.bounceOut
});
LK.setTimeout(function () {
// Animation slot reserved for future use
}, 300);
LK.setTimeout(function () {
tween(bestScoreTxt, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
tween(subtitleTxt, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
}, 900);
LK.setTimeout(function () {
tween(skinBtnBorder, {
alpha: 0.9,
scaleX: 0.84,
scaleY: 0.63
}, {
duration: 800,
easing: tween.bounceOut
});
tween(skinBtnBg, {
alpha: 1,
scaleX: 0.8,
scaleY: 0.6
}, {
duration: 800,
easing: tween.bounceOut
});
tween(skinBtn, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeInOut
});
}, 1200);
// Title floating animation removed
// Update best score display with stored value
var storedBestScore = LK.getScore() || 0;
bestScoreTxt.setText('BEST: ' + storedBestScore);
// Create decorative sparkles for starting screen
var sparkles = [];
for (var i = 0; i < 8; i++) {
var sparkle = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
alpha: 0
});
sparkle.x = 2048 / 2 + (Math.random() - 0.5) * 600;
sparkle.y = 2732 / 2 - 350 + (Math.random() - 0.5) * 200;
sparkles.push(sparkle);
game.addChild(sparkle);
}
// Animate sparkles
function animateSparkles() {
for (var i = 0; i < sparkles.length; i++) {
var sparkle = sparkles[i];
var delay = i * 200;
LK.setTimeout(function (s) {
return function () {
tween(s, {
alpha: 1,
rotation: Math.PI * 2,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(s, {
alpha: 0,
scaleX: 0.3,
scaleY: 0.3
}, {
duration: 500,
easing: tween.easeIn
});
}
});
};
}(sparkle), delay);
}
}
LK.setTimeout(animateSparkles, 2000);
// Initialize bird
bird = new Bird();
bird.x = -100; // Start off screen
bird.y = 2732 / 2;
bird.invincible = false;
game.addChild(bird);
// Apply current skin
bird.removeChildren();
var initialBirdGraphics = bird.attachAsset(skins[currentSkin].asset, {
anchorX: 0.5,
anchorY: 0.5
});
// Smooth entrance animation
tween(bird, {
x: 2048 / 4
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Floating animation removed
// Rotation floating animation removed
}
});
// Initialize health display
updateHealthDisplay();
// Initialize clouds
for (var i = 0; i < 4; i++) {
var cloud = new Cloud();
cloud.x = i * 500 + 200;
cloud.y = 100 + Math.random() * 300;
clouds.push(cloud);
game.addChild(cloud);
}
// Initialize monkeys
var monkey = new Monkey();
monkey.x = 2048 + 300;
monkey.baseY = 200 + Math.random() * 400;
monkey.y = monkey.baseY;
monkeys.push(monkey);
game.addChild(monkey);
// Initialize spawn points
for (var i = 0; i < 3; i++) {
var spawnPoint = new SpawnPoint();
spawnPoint.x = 2048 + 200 + i * 400;
spawnPoint.y = 300 + i * 200;
spawnPoints.push(spawnPoint);
game.addChild(spawnPoint);
}
// Initialize first few buildings
for (var i = 0; i < 3; i++) {
var building = new Building();
building.x = 300 + i * 300;
building.y = 2732 - 100;
buildings.push(building);
game.addChildAt(building, 0);
}
// Initialize first few Building2 instances
for (var i = 0; i < 2; i++) {
var building2 = new Building2();
building2.x = 600 + i * 400;
building2.y = 2732 - 100;
buildings2.push(building2);
game.addChildAt(building2, 0);
}
// Create ground
ground = game.attachAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 2732 - 100
});
// Add ground scrolling animation
tween(ground, {
x: -200
}, {
duration: 4000,
easing: tween.linear,
onFinish: function onFinish() {
ground.x = 0;
tween(ground, {
x: -200
}, {
duration: 4000,
easing: tween.linear,
onFinish: arguments.callee
});
}
});
function spawnPipe() {
var pipe = new Pipe();
pipe.x = 2048 + 100; // Start from right edge
pipe.alpha = 1; // Start visible
// Vary gap center position - keep it challenging but fair
var baseY = 2732 / 2;
var variation = 400;
var gapCenterY = baseY + (Math.random() - 0.5) * variation;
// Keep within reasonable bounds
gapCenterY = Math.max(400, Math.min(2332, gapCenterY));
pipe.setupPipes(gapCenterY);
pipes.push(pipe);
// Add pipe at index 0 to ensure it stays behind buildings
game.addChildAt(pipe, 0);
// Spawn coin in the gap center (70% chance)
if (Math.random() < 0.7) {
var coin = new Coin();
coin.x = pipe.x;
coin.y = gapCenterY;
coin.alpha = 0;
coins.push(coin);
game.addChild(coin);
// Coin entrance animation with slight delay
tween(coin, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(coin, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
// Spawn power-up occasionally (15% chance)
if (Math.random() < 0.15) {
var powerUp = new PowerUp();
powerUp.x = pipe.x + 100;
powerUp.y = gapCenterY + (Math.random() - 0.5) * 100;
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
function spawnBuilding() {
var building = new Building();
building.x = 2048 + 100; // Start from right edge
building.y = 2732 - 100; // Position on ground
buildings.push(building);
// Add building at index 0 to ensure it stays behind pipes and other game elements
game.addChildAt(building, 0);
}
function spawnBuilding2() {
var building2 = new Building2();
building2.x = 2048 + 150; // Start from right edge with slight offset
building2.y = 2732 - 100; // Position on ground
buildings2.push(building2);
// Add building at index 0 to ensure it stays behind pipes and other game elements
game.addChildAt(building2, 0);
}
function checkScore() {
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
if (!pipe.scored && pipe.x < bird.x) {
pipe.scored = true;
var points = Math.floor(1 * comboMultiplier);
LK.setScore(LK.getScore() + points);
scoreTxt.setText(LK.getScore().toString());
LK.getSound('score').play();
// Update combo display
if (comboMultiplier > 1) {
comboTxt.setText('COMBO x' + comboMultiplier.toFixed(1));
tween(comboTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
}
});
} else {
comboTxt.setText('');
}
// Score animation
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150,
easing: tween.easeOut
});
}
});
}
}
}
function updateHealthDisplay() {
var hearts = '';
for (var i = 0; i < playerHealth; i++) {
hearts += '♥ ';
}
for (var i = playerHealth; i < 3; i++) {
hearts += '♡ ';
}
healthTxt.setText(hearts.trim());
}
function spawnParticles(x, y, count, color) {
for (var i = 0; i < count; i++) {
var particle = new Particle();
particle.x = x + (Math.random() - 0.5) * 40;
particle.y = y + (Math.random() - 0.5) * 40;
particle.velocityX = (Math.random() - 0.5) * 8;
particle.velocityY = (Math.random() - 0.5) * 8 - 2;
if (color) {
particle.children[0].tint = color;
}
particles.push(particle);
game.addChild(particle);
}
}
function checkCoinCollection() {
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.collected && coin.checkCollection(bird)) {
coin.collected = true;
var points = 5 * comboMultiplier;
LK.setScore(LK.getScore() + points);
scoreTxt.setText(LK.getScore().toString());
LK.getSound('score').play();
// Spawn particle effects
spawnParticles(coin.x, coin.y, 6, 0xFFD700);
// Increase combo
comboMultiplier = Math.min(5, comboMultiplier + 0.5);
comboTimer = 180; // 3 seconds
coin.destroy();
coins.splice(i, 1);
}
}
}
function checkPowerUpCollection() {
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (!powerUp.collected && powerUp.checkCollection(bird)) {
powerUp.collected = true;
// Apply power-up effect
if (powerUp.type === 'shield') {
bird.shieldActive = true;
bird.shieldTimer = 300; // 5 seconds
} else if (powerUp.type === 'speed') {
bird.speedBoostActive = true;
bird.speedBoostTimer = 180; // 3 seconds
}
LK.getSound('score').play();
spawnParticles(powerUp.x, powerUp.y, 8, 0xFF4444);
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
function checkCollisions() {
// Check pipe collisions
for (var i = 0; i < pipes.length; i++) {
if (pipes[i].checkCollision(bird)) {
return true;
}
}
// Check ground collision
if (bird.y + 30 > ground.y) {
return true;
}
// Check ceiling collision
if (bird.y - 30 < 0) {
return true;
}
return false;
}
function takeDamage() {
if (playerHealth > 0) {
playerHealth--;
updateHealthDisplay();
// Flash screen red to indicate damage
LK.effects.flashScreen(0xff0000, 500);
LK.getSound('hit').play();
// Make bird temporarily invincible
bird.invincible = true;
// Remove invincibility after 2 seconds
LK.setTimeout(function () {
bird.invincible = false;
}, 2000);
// Check if health is depleted
if (playerHealth <= 0) {
gameOver();
}
}
}
function gameOver() {
gameActive = false;
LK.getSound('hit').play();
// Stop bird movement
bird.velocity = 0;
// Flash screen red
LK.effects.flashScreen(0xff0000, 1000);
// Show game over after a brief delay
LK.setTimeout(function () {
LK.showGameOver();
}, 500);
}
function showSkinSelection() {
skinShowMode = true;
// Hide main menu elements
titleTxt.visible = false;
subtitleTxt.visible = false;
bestScoreTxt.visible = false;
skinBtn.visible = false;
skinBtnBg.visible = false;
skinBtnBorder.visible = false;
for (var i = 0; i < sparkles.length; i++) {
sparkles[i].visible = false;
}
// Show skin selection elements
skinTitleTxt.visible = true;
skinNameTxt.visible = true;
prevBtn.visible = true;
nextBtn.visible = true;
backBtn.visible = true;
skinPreviewBird.visible = true;
// Animate skin UI entrance
tween(skinTitleTxt, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(skinNameTxt, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(prevBtn, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(nextBtn, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(backBtn, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(skinPreviewBird, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
updateSkinPreview();
}
function hideSkinSelection() {
skinShowMode = false;
// Hide skin selection elements
tween(skinTitleTxt, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
skinTitleTxt.visible = false;
}
});
tween(skinNameTxt, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
skinNameTxt.visible = false;
}
});
tween(prevBtn, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
prevBtn.visible = false;
if (gameStarted) prevBtn.destroy();
}
});
tween(nextBtn, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
nextBtn.visible = false;
if (gameStarted) nextBtn.destroy();
}
});
tween(backBtn, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
backBtn.visible = false;
if (gameStarted) backBtn.destroy();
}
});
tween(skinPreviewBird, {
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
skinPreviewBird.visible = false;
}
});
// Show main menu elements
LK.setTimeout(function () {
titleTxt.visible = true;
subtitleTxt.visible = true;
bestScoreTxt.visible = true;
skinBtn.visible = true;
skinBtnBg.visible = true;
skinBtnBorder.visible = true;
for (var i = 0; i < sparkles.length; i++) {
sparkles[i].visible = true;
}
tween(titleTxt, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(subtitleTxt, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(bestScoreTxt, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(skinBtnBorder, {
alpha: 0.9
}, {
duration: 500,
easing: tween.easeOut
});
tween(skinBtnBg, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
tween(skinBtn, {
alpha: 1
}, {
duration: 500,
easing: tween.easeOut
});
}, 300);
}
function updateSkinPreview() {
var skin = skins[currentSkin];
skinNameTxt.setText(skin.name);
// Update preview bird skin
skinPreviewBird.removeChildren();
var newBirdGraphics = skinPreviewBird.attachAsset(skin.asset, {
anchorX: 0.5,
anchorY: 0.5
});
// Floating animation removed from preview bird
}
function changeSkin(direction) {
currentSkin += direction;
if (currentSkin < 0) {
currentSkin = skins.length - 1;
} else if (currentSkin >= skins.length) {
currentSkin = 0;
}
updateSkinPreview();
// Update actual bird skin
bird.removeChildren();
var newBirdGraphics = bird.attachAsset(skins[currentSkin].asset, {
anchorX: 0.5,
anchorY: 0.5
});
}
function changeWeather() {
currentWeather = (currentWeather + 1) % weatherTypes.length;
var weather = weatherTypes[currentWeather];
// Smooth background color transition
var currentColor = game.backgroundColor;
var newColor = weather.bgColor;
var steps = 120; // 2 second transition
var stepCount = 0;
var transitionColor = function transitionColor() {
if (stepCount < steps) {
var t = stepCount / steps;
var r1 = currentColor >> 16 & 0xFF;
var g1 = currentColor >> 8 & 0xFF;
var b1 = currentColor & 0xFF;
var r2 = newColor >> 16 & 0xFF;
var g2 = newColor >> 8 & 0xFF;
var b2 = newColor & 0xFF;
var r = Math.floor(r1 + (r2 - r1) * t);
var g = Math.floor(g1 + (g2 - g1) * t);
var b = Math.floor(b1 + (b2 - b1) * t);
game.setBackgroundColor(r << 16 | g << 8 | b);
stepCount++;
}
};
var colorTransitionInterval = LK.setInterval(transitionColor, 16);
LK.setTimeout(function () {
LK.clearInterval(colorTransitionInterval);
}, 2000);
// Update cloud properties for weather effect
for (var i = 0; i < clouds.length; i++) {
var cloud = clouds[i];
cloud.speed = -weather.cloudSpeed;
tween(cloud, {
alpha: weather.cloudAlpha
}, {
duration: 2000,
easing: tween.easeInOut
});
}
// Update weather display
weatherTxt.setText('Weather: ' + weather.name);
// Add weather-specific visual effects
if (weather.name === 'Stormy') {
// Screen flash effect for lightning
LK.setTimeout(function () {
LK.effects.flashScreen(0xFFFFFF, 200);
}, 1000);
}
}
// Touch/tap handler
game.down = function (x, y, obj) {
if (!gameStarted) {
// Floating animations removed
if (skinShowMode) {
// Check skin selection UI clicks
var prevBounds = {
left: prevBtn.x - 75,
right: prevBtn.x + 75,
top: prevBtn.y - 30,
bottom: prevBtn.y + 30
};
var nextBounds = {
left: nextBtn.x - 75,
right: nextBtn.x + 75,
top: nextBtn.y - 30,
bottom: nextBtn.y + 30
};
var backBounds = {
left: backBtn.x - 50,
right: backBtn.x + 50,
top: backBtn.y - 30,
bottom: backBtn.y + 30
};
if (x >= prevBounds.left && x <= prevBounds.right && y >= prevBounds.top && y <= prevBounds.bottom) {
// Previous skin button
tween(prevBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(prevBtn, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
changeSkin(-1);
// Hide skin selection panel after skin is chosen
hideSkinSelection();
return;
} else if (x >= nextBounds.left && x <= nextBounds.right && y >= nextBounds.top && y <= nextBounds.bottom) {
// Next skin button
tween(nextBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(nextBtn, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
changeSkin(1);
// Hide skin selection panel after skin is chosen
hideSkinSelection();
return;
} else if (x >= backBounds.left && x <= backBounds.right && y >= backBounds.top && y <= backBounds.bottom) {
// Back button - return to main menu only
tween(backBtn, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(backBtn, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
// Hide skin selection and return to main menu
hideSkinSelection();
return;
}
} else {
// Check if skin button was clicked
var skinBounds = {
left: skinBtn.x - 120,
right: skinBtn.x + 120,
top: skinBtn.y - 30,
bottom: skinBtn.y + 30
};
if (x >= skinBounds.left && x <= skinBounds.right && y >= skinBounds.top && y <= skinBounds.bottom) {
// Check if this is a long press for skin selection or quick tap for start
var pressStartTime = Date.now();
var longPressThreshold = 500; // 500ms for long press
var longPressTimer = LK.setTimeout(function () {
// Long press - show skin selection
tween(skinBtn, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(skinBtn, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
tween(skinBtnBorder, {
scaleX: 0.76,
scaleY: 0.57,
tint: 0x1B5E20
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(skinBtnBorder, {
scaleX: 0.84,
scaleY: 0.63,
tint: 0x2E7D32
}, {
duration: 100,
easing: tween.easeOut
});
}
});
tween(skinBtnBg, {
scaleX: 0.76,
scaleY: 0.57,
tint: 0x45A049
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(skinBtnBg, {
scaleX: 0.8,
scaleY: 0.6,
tint: 0x4CAF50
}, {
duration: 100,
easing: tween.easeOut
});
}
});
showSkinSelection();
}, longPressThreshold);
// Store the timer for potential cancellation
game.longPressTimer = longPressTimer;
return;
}
}
// Note: Game start logic moved to up handler for shared button functionality
}
// Check if game is prepared but not yet active (waiting for touch to start)
if (gameStarted && !gameActive) {
// First touch after start button - actually start the game
gameActive = true;
// Spawn first pipe with delay
LK.setTimeout(function () {
spawnPipe();
}, 800);
bird.flap();
return;
}
if (gameActive) {
bird.flap();
}
};
// Touch/tap up handler for shared button functionality
game.up = function (x, y, obj) {
if (!gameStarted && !skinShowMode && game.longPressTimer) {
// Cancel long press timer
LK.clearTimeout(game.longPressTimer);
game.longPressTimer = null;
// Check if this was a quick tap on the shared button
var skinBounds = {
left: skinBtn.x - 120,
right: skinBtn.x + 120,
top: skinBtn.y - 30,
bottom: skinBtn.y + 30
};
if (x >= skinBounds.left && x <= skinBounds.right && y >= skinBounds.top && y <= skinBounds.bottom) {
// Quick tap - prepare game but don't start yet
gameStarted = true;
gameActive = false; // Game is prepared but not active yet
// Hide all starting screen elements with staggered animations
tween(titleTxt, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
titleTxt.visible = false;
}
});
tween(subtitleTxt, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
subtitleTxt.visible = false;
}
});
// Additional entrance animations can be added here if needed
tween(bestScoreTxt, {
alpha: 0,
y: bestScoreTxt.y + 50
}, {
duration: 250,
easing: tween.easeIn,
onFinish: function onFinish() {
bestScoreTxt.visible = false;
}
});
// Hide skin button when game starts
tween(skinBtn, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
skinBtn.visible = false;
skinBtn.destroy();
}
});
tween(skinBtnBg, {
alpha: 0,
scaleX: 0.64,
scaleY: 0.48
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
skinBtnBg.visible = false;
skinBtnBg.destroy();
}
});
tween(skinBtnBorder, {
alpha: 0,
scaleX: 0.64,
scaleY: 0.48
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
skinBtnBorder.visible = false;
skinBtnBorder.destroy();
}
});
// Hide sparkles when game starts
for (var i = 0; i < sparkles.length; i++) {
tween(sparkles[i], {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function (sparkle) {
return function () {
sparkle.visible = false;
};
}(sparkles[i])
});
}
// Don't spawn pipes yet - wait for touch to start
// Bird will start flying when user first touches screen
// Removed hover mode - bird stays stationary
}
}
};
// Main game loop
game.update = function () {
// Weather change system
if (gameStarted && gameActive) {
weatherChangeTimer++;
if (weatherChangeTimer >= weatherChangeInterval) {
changeWeather();
weatherChangeTimer = 0;
}
}
// Always update background elements for ambiance
for (var i = 0; i < clouds.length; i++) {
clouds[i].update();
}
for (var i = 0; i < monkeys.length; i++) {
monkeys[i].update();
}
if (!gameStarted || !gameActive) {
return;
}
// Update difficulty level
difficultyLevel = Math.floor(LK.getScore() / 15) + 1;
// Update combo system
if (comboTimer > 0) {
comboTimer--;
} else {
comboMultiplier = Math.max(1, comboMultiplier - 0.1);
}
// Update bird
bird.update();
// Render bird wing trails
for (var i = 0; i < bird.trail.length; i++) {
var trailPoint = bird.trail[i];
if (trailPoint.isWingTrail) {
var alpha = trailPoint.life / 15;
var size = alpha * 0.3;
// Create wing trail particles
if (i % 2 === 0 && alpha > 0.3) {
var wingParticle = new Particle();
wingParticle.x = trailPoint.x + (Math.random() - 0.5) * 20;
wingParticle.y = trailPoint.y + (Math.random() - 0.5) * 20;
wingParticle.velocityX = (Math.random() - 0.5) * 2;
wingParticle.velocityY = (Math.random() - 0.5) * 2;
wingParticle.life = 20;
wingParticle.children[0].tint = 0x87CEEB;
wingParticle.children[0].alpha = alpha * 0.5;
wingParticle.children[0].scaleX = size;
wingParticle.children[0].scaleY = size;
particles.push(wingParticle);
game.addChild(wingParticle);
}
}
trailPoint.life--;
}
// Remove dead trail points
for (var i = bird.trail.length - 1; i >= 0; i--) {
if (bird.trail[i].life <= 0) {
bird.trail.splice(i, 1);
}
}
// Update particles
for (var i = particles.length - 1; i >= 0; i--) {
particles[i].update();
if (particles[i].life <= 0) {
particles[i].destroy();
particles.splice(i, 1);
}
}
// Update pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].update();
// Remove pipes that have moved off screen
if (pipes[i].x < -120) {
pipes[i].destroy();
pipes.splice(i, 1);
}
}
// Update coins
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].update();
// Remove coins that have moved off screen
if (coins[i].x < -120) {
coins[i].destroy();
coins.splice(i, 1);
}
}
// Update power-ups
for (var i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].update();
if (powerUps[i].x < -120) {
powerUps[i].destroy();
powerUps.splice(i, 1);
}
}
// Update spawn points
for (var i = 0; i < spawnPoints.length; i++) {
spawnPoints[i].update();
// Move spawn points left
spawnPoints[i].x -= 2;
// Reset spawn point position when it goes off screen
if (spawnPoints[i].x < -100) {
spawnPoints[i].x = 2048 + 200;
spawnPoints[i].y = 300 + Math.random() * 400;
}
}
// Update buildings
for (var i = buildings.length - 1; i >= 0; i--) {
buildings[i].update();
// Remove buildings that have moved off screen
if (buildings[i].x < -200) {
buildings[i].destroy();
buildings.splice(i, 1);
}
}
// Update buildings2
for (var i = buildings2.length - 1; i >= 0; i--) {
buildings2[i].update();
// Remove buildings2 that have moved off screen
if (buildings2[i].x < -250) {
buildings2[i].destroy();
buildings2.splice(i, 1);
}
}
// Spawn new pipes with consistent timing
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnInterval) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Spawn new buildings
buildingSpawnTimer++;
if (buildingSpawnTimer >= buildingSpawnInterval) {
spawnBuilding();
buildingSpawnTimer = 0;
}
// Spawn new Building2 instances
building2SpawnTimer++;
if (building2SpawnTimer >= building2SpawnInterval) {
spawnBuilding2();
building2SpawnTimer = 0;
}
// Check for score
checkScore();
// Check for coin collection
checkCoinCollection();
// Check for power-up collection
checkPowerUpCollection();
// Check for collisions (shield protects from damage)
if (checkCollisions() && !bird.invincible && !bird.shieldActive) {
takeDamage();
}
// Screen shake effect when bird is close to pipes
for (var i = 0; i < pipes.length; i++) {
var distance = Math.abs(bird.x - pipes[i].x);
if (distance < 100) {
var intensity = (100 - distance) / 100 * 2;
game.x = (Math.random() - 0.5) * intensity;
game.y = (Math.random() - 0.5) * intensity;
break;
} else {
game.x = 0;
game.y = 0;
}
}
};
Make bird same like flappy bird. In-Game asset. 2d. No shadows
Make background forest. In-Game asset. 2d. No shadows
Flapy bird coin. In-Game asset. 2d. No shadows
Make it flapy bird cloud. In-Game asset. 2d. High contrast. No shadows
Add a monkey flying with plane. In-Game asset. 2d. No shadows
Make a zombi flapy bird. In-Game asset. 2d. High contrast. No shadows
Make a sigma flapy bird. In-Game asset. 2d. No shadows
Make a star War flapy bird. In-Game asset. 2d. No shadows
Make a gost flapy bird. In-Game asset. 2d. High contrast. No shadows
Make a starting buton. In-Game asset. 2d. High contrast. No shadows
Make a skin buton. In-Game asset. 2d. No shadows
Make it flapy bird building. 2d. No shadows
Make it flapy bird shape. 2d. High contrast. No shadows
Make it flapy bird building. In-Game asset. 2d. No shadows