User prompt
İncrease distance pipe to pipe
User prompt
İncrease distance pipe to pipe
User prompt
Make everything better ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add all Real flapy bird thing ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Can you add health bar
User prompt
İncrease distance pipe to pipe
User prompt
Decrase distance of pipe to pipe
User prompt
Add some spacn point
User prompt
Decrease size of pipe to pipe
User prompt
Add coin at among of pipe
User prompt
Reset last adding
User prompt
Make more birde jumping
Code edit (1 edits merged)
Please save this source code
User prompt
Flappy Bird
Initial prompt
Make me flaapy bird
/**** * 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