/****
* 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