/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Track if continue has been used in current session
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.flap = function () {
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Animate bird flap
tween(birdGraphics, {
rotation: -0.3
}, {
duration: 150
});
tween(birdGraphics, {
rotation: 0
}, {
duration: 150,
onFinish: function onFinish() {
if (self.velocity > 0) {
tween(birdGraphics, {
rotation: 0.3
}, {
duration: 200
});
}
}
});
};
self.update = function () {
// Don't update bird physics if game hasn't started
if (!gameStarted) {
return;
}
// Apply gravity
self.velocity += self.gravity;
if (self.velocity > self.maxFallSpeed) {
self.velocity = self.maxFallSpeed;
}
// Update position
self.y += self.velocity;
// Update rotation based on velocity with falling effect
var targetRotation = Math.min(Math.max(self.velocity * 0.05, -0.5), 0.8);
// Add dramatic falling effect when bird is falling fast
if (self.velocity > 8) {
// Create falling spin effect
tween(birdGraphics, {
rotation: targetRotation + Math.PI * 2
}, {
duration: 800,
easing: tween.easeIn
});
// Add slight scale effect during fall
tween(birdGraphics, {
scaleX: 0.9,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(birdGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
} else {
// Normal rotation for regular movement
birdGraphics.rotation = targetRotation;
}
};
return self;
});
var Chicken = Container.expand(function () {
var self = Container.call(this);
var chickenGraphics = self.attachAsset('chicken', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
self.baseY = 0;
self.pecking = false;
self.update = function () {
self.x += self.speed;
// Chicken walking animation - quick and jerky movements
var walkCycle = LK.ticks * 0.25; // Fast walking
// Quick head bobbing motion
self.y = self.baseY + Math.sin(walkCycle) * 1;
// Head jerking motion characteristic of chickens
chickenGraphics.x = Math.sin(walkCycle * 0.8) * 0.5;
// Periodic pecking animation
if (LK.ticks % 120 === 0) {
self.pecking = !self.pecking;
}
// Quick stepping animation every 10 frames for rapid chicken steps
if (LK.ticks % 10 === 0) {
var stepDirection = Math.floor(LK.ticks / 10) % 2 * 2 - 1;
tween(chickenGraphics, {
scaleY: 0.95,
scaleX: 1.05,
y: stepDirection * 0.3,
rotation: stepDirection * 0.05
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(chickenGraphics, {
scaleY: 1,
scaleX: 1,
y: 0,
rotation: 0
}, {
duration: 50,
easing: tween.easeIn
});
}
});
}
// Enhanced pecking motion when pecking
if (self.pecking) {
chickenGraphics.y = Math.sin(LK.ticks * 0.3) * 2;
}
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
self.speed = -1;
self.cloudGraphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
self.cloudGraphics.alpha = 0.6;
self.update = function () {
self.x += self.speed;
// Gentle floating
self.y += Math.sin(LK.ticks * 0.02) * 0.1;
};
return self;
});
// Cloud class removed
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.rotationSpeed = 0.1;
self.update = function () {
self.x += self.speed;
// Rotate coin for visual appeal
coinGraphics.rotation += self.rotationSpeed;
// Gentle floating animation
coinGraphics.y = Math.sin(LK.ticks * 0.05) * 3;
};
return self;
});
var Cow = Container.expand(function () {
var self = Container.call(this);
var cowGraphics = self.attachAsset('cow', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
// Add some black spots for cow appearance
self.baseY = 0;
self.update = function () {
self.x += self.speed;
// Proper walking animation with realistic bobbing
var walkCycle = LK.ticks * 0.15; // Walking speed
// Vertical bobbing motion - more pronounced and realistic
self.y = self.baseY + Math.sin(walkCycle) * 2;
// Subtle horizontal body sway
cowGraphics.x = Math.sin(walkCycle * 0.5) * 1;
// Body tilt during walking
cowGraphics.rotation = Math.sin(walkCycle) * 0.05;
// Step-based animation every 20 frames for more frequent steps
if (LK.ticks % 20 === 0) {
// Alternating leg movement effect
var stepDirection = Math.floor(LK.ticks / 20) % 2 * 2 - 1; // -1 or 1
// Step effect with body compression and extension
tween(cowGraphics, {
scaleY: 0.95,
scaleX: 1.05,
y: stepDirection * 1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(cowGraphics, {
scaleY: 1,
scaleX: 1,
y: 0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
};
return self;
});
var Farm = Container.expand(function () {
var self = Container.call(this);
var farmGraphics = self.attachAsset('farmGround', {
anchorX: 0,
anchorY: 0
});
self.speed = -4;
self.update = function () {
self.x += self.speed;
};
return self;
});
var ParticleSystem = Container.expand(function () {
var self = Container.call(this);
self.particles = [];
self.maxParticles = 20;
self.createParticle = function (x, y, color, size) {
if (self.particles.length >= self.maxParticles) {
return;
}
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = x;
particle.y = y;
particle.tint = color || 0xFFFFFF;
particle.scaleX = size || 1;
particle.scaleY = size || 1;
particle.velocity = {
x: (Math.random() - 0.5) * 10,
y: (Math.random() - 0.5) * 10
};
particle.life = 1.0;
particle.decay = 0.02;
self.addChild(particle);
self.particles.push(particle);
};
self.update = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
particle.x += particle.velocity.x;
particle.y += particle.velocity.y;
particle.velocity.y += 0.3; // gravity
particle.life -= particle.decay;
particle.alpha = particle.life;
if (particle.life <= 0) {
particle.destroy();
self.particles.splice(i, 1);
}
}
};
self.explode = function (x, y, color, count) {
for (var i = 0; i < (count || 10); i++) {
self.createParticle(x, y, color, Math.random() * 0.5 + 0.5);
}
};
return self;
});
var Pig = Container.expand(function () {
var self = Container.call(this);
var pigGraphics = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
self.baseY = 0;
self.update = function () {
self.x += self.speed;
// Pig walking animation - heavier and slower
var walkCycle = LK.ticks * 0.12; // Slower walking
// Heavy bobbing motion
self.y = self.baseY + Math.sin(walkCycle) * 1.2;
// Wide body sway for heavier appearance
pigGraphics.x = Math.sin(walkCycle * 0.3) * 1.5;
// Heavy stepping animation every 25 frames
if (LK.ticks % 25 === 0) {
var stepDirection = Math.floor(LK.ticks / 25) % 2 * 2 - 1;
tween(pigGraphics, {
scaleY: 0.92,
scaleX: 1.08,
y: stepDirection * 0.8
}, {
duration: 125,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pigGraphics, {
scaleY: 1,
scaleX: 1,
y: 0
}, {
duration: 125,
easing: tween.easeIn
});
}
});
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.speed = -4;
self.passed = false;
self.gapSize = 450;
// Create top pipe
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1
});
// Create top pipe segment (Mario-style cap)
self.topPipeSegment = self.attachAsset('pipeSegment', {
anchorX: 0.5,
anchorY: 1
});
// Create bottom pipe
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0
});
// Create bottom pipe segment (Mario-style cap)
self.bottomPipeSegment = self.attachAsset('pipeSegment', {
anchorX: 0.5,
anchorY: 0
});
self.setGapPosition = function (gapY) {
self.topPipe.y = gapY - self.gapSize / 2;
self.bottomPipe.y = gapY + self.gapSize / 2;
// Position the Mario-style pipe segments
self.topPipeSegment.y = gapY - self.gapSize / 2;
self.bottomPipeSegment.y = gapY + self.gapSize / 2;
};
self.update = function () {
self.x += self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.type = 'shield'; // 'shield', 'speedBoost'
self.speed = -4;
self.collected = false;
self.rotationSpeed = 0.05;
self.powerUpGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (self.collected) return;
self.x += self.speed;
self.powerUpGraphics.rotation += self.rotationSpeed;
// Floating animation
self.powerUpGraphics.y = Math.sin(LK.ticks * 0.08) * 10;
// Pulsing effect
var pulse = Math.sin(LK.ticks * 0.1) * 0.2 + 1;
self.powerUpGraphics.scaleX = pulse;
self.powerUpGraphics.scaleY = pulse;
};
self.collect = function () {
self.collected = true;
// Collection effect
tween(self.powerUpGraphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Sheep = Container.expand(function () {
var self = Container.call(this);
var sheepGraphics = self.attachAsset('sheep', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
self.baseY = 0;
self.update = function () {
self.x += self.speed;
// Sheep walking animation - lighter and bouncier than cows
var walkCycle = LK.ticks * 0.18; // Slightly faster walking
// Bouncy vertical movement
self.y = self.baseY + Math.sin(walkCycle) * 1.5;
// Gentle body sway
sheepGraphics.x = Math.sin(walkCycle * 0.4) * 0.8;
// Light stepping animation every 15 frames for quicker steps
if (LK.ticks % 15 === 0) {
var stepDirection = Math.floor(LK.ticks / 15) % 2 * 2 - 1;
tween(sheepGraphics, {
scaleY: 0.98,
scaleX: 1.02,
y: stepDirection * 0.5
}, {
duration: 75,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(sheepGraphics, {
scaleY: 1,
scaleX: 1,
y: 0
}, {
duration: 75,
easing: tween.easeIn
});
}
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4a90e2
});
/****
* Game Code
****/
// Sound and music assets
// Power-up assets
// Menu decoration assets
// Visual effect assets
// Farm and animal assets
// Game element assets
// Health system assets
// Sky gradient assets removed
// Cloud asset removed
// Game variables
var continueUsed = false;
var bird;
var pipes = [];
var ground;
var gameStarted = false;
var gameSpeed = 4;
var pipeSpawnTimer = 0;
var pipeSpawnInterval = 180; // frames between pipe spawns
var lastPipeScore = 0;
var coins = [];
var coinSpawnTimer = 0;
var coinSpawnInterval = 200; // frames between coin spawns - slightly after pipes
var farms = [];
var farmSpawnTimer = 0;
var farmSpawnInterval = 400; // frames between farm spawns
var animals = [];
var animalSpawnTimer = 0;
var animalSpawnInterval = 150; // frames between animal spawns
// Enhanced visual systems
var clouds = [];
var cloudSpawnTimer = 0;
var cloudSpawnInterval = 300;
var powerUps = [];
var powerUpSpawnTimer = 0;
var powerUpSpawnInterval = 600;
var particleSystem;
var stars = [];
// Power-up effects
var shieldActive = false;
var shieldTime = 0;
var speedBoostActive = false;
var speedBoostTime = 0;
// Health system variables
var maxHealth = 3;
var currentHealth = 3;
var healthBar;
var healthBarBg;
// Achievement system
var achievements = {
firstFlight: false,
coinCollector: false,
survivor: false,
speedDemon: false
};
var achievementMessages = [];
// UI elements
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var instructionTxt = new Text2('Tap to Flap!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionTxt);
// Days counter display
var daysTxt = new Text2('Days: 0', {
size: 50,
fill: 0xFFFFFF
});
daysTxt.anchor.set(0, 0);
daysTxt.x = 20;
daysTxt.y = 70;
LK.gui.topLeft.addChild(daysTxt);
// Start menu UI elements
var showStartMenu = true;
var menuBirds = [];
var menuCoins = [];
// Create animated background birds for menu
function createMenuBirds() {
for (var i = 0; i < 3; i++) {
var menuBird = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
menuBird.x = -100 - i * 200;
menuBird.y = 400 + i * 300;
menuBird.alpha = 0.3;
menuBird.scaleX = 0.6;
menuBird.scaleY = 0.6;
game.addChild(menuBird);
menuBirds.push(menuBird);
// Animate birds flying across screen
tween(menuBird, {
x: 2200,
y: menuBird.y + Math.sin(i) * 100
}, {
duration: 8000 + i * 1000,
easing: tween.linear
});
// Add gentle floating animation
tween(menuBird, {
y: menuBird.y + 30,
rotation: 0.2
}, {
duration: 2000 + i * 500,
easing: tween.easeInOut
});
}
}
// Create enhanced menu background
function createMenuBackground() {
// Add animated background
var menuBg = LK.getAsset('menuBg', {
anchorX: 0,
anchorY: 0
});
menuBg.x = 0;
menuBg.y = 0;
menuBg.alpha = 0.8;
game.addChild(menuBg);
menuCoins.push(menuBg);
// Add animated sun
var sun = LK.getAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
sun.x = 1800;
sun.y = 300;
sun.alpha = 0.7;
game.addChild(sun);
menuCoins.push(sun);
// Animate sun rotation
tween(sun, {
rotation: Math.PI * 2
}, {
duration: 10000,
easing: tween.linear
});
// Add clouds
for (var i = 0; i < 4; i++) {
var cloud = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloud.x = Math.random() * 2048;
cloud.y = 200 + Math.random() * 400;
cloud.alpha = 0.4;
cloud.scaleX = 0.8 + Math.random() * 0.4;
cloud.scaleY = 0.8 + Math.random() * 0.4;
game.addChild(cloud);
menuCoins.push(cloud);
// Animate clouds drifting
tween(cloud, {
x: cloud.x + 200,
y: cloud.y + Math.sin(i) * 50
}, {
duration: 15000 + i * 2000,
easing: tween.linear
});
}
// Add decorative trees
for (var j = 0; j < 6; j++) {
var tree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 1
});
tree.x = j * 350 + 200;
tree.y = 2732 - 100;
tree.alpha = 0.3;
game.addChild(tree);
menuCoins.push(tree);
var treeTop = LK.getAsset('treeTop', {
anchorX: 0.5,
anchorY: 1
});
treeTop.x = tree.x;
treeTop.y = tree.y - 150;
treeTop.alpha = 0.3;
game.addChild(treeTop);
menuCoins.push(treeTop);
// Gentle swaying animation
tween(tree, {
rotation: 0.1
}, {
duration: 3000 + j * 500,
easing: tween.easeInOut
});
}
}
// Create floating coins for menu ambience
function createMenuCoins() {
for (var i = 0; i < 5; i++) {
var menuCoin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
menuCoin.x = Math.random() * 2048;
menuCoin.y = Math.random() * 2732;
menuCoin.alpha = 0.2;
menuCoin.scaleX = 0.4;
menuCoin.scaleY = 0.4;
game.addChild(menuCoin);
menuCoins.push(menuCoin);
// Add gentle floating and rotation
tween(menuCoin, {
y: menuCoin.y + 50,
rotation: Math.PI * 2
}, {
duration: 3000 + i * 800,
easing: tween.easeInOut
});
}
}
var titleTxt = new Text2('Mutili Bird', {
size: 120,
fill: 0xFFD700
});
titleTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(titleTxt);
var startButtonTxt = new Text2('TAP TO START', {
size: 80,
fill: 0x00FF00
});
startButtonTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startButtonTxt);
// Initialize particle system
particleSystem = game.addChild(new ParticleSystem());
// Create enhanced menu with background
createMenuBackground();
createMenuBirds();
createMenuCoins();
spawnStars();
// Position menu elements
titleTxt.y = -200;
startButtonTxt.y = 100;
// Add rainbow title animation
function animateTitle() {
var colors = [0xFFD700, 0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xF7DC6F, 0xBB8FCE];
var currentColorIndex = 0;
function cycleColors() {
tween(titleTxt, {
tint: colors[currentColorIndex]
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
currentColorIndex = (currentColorIndex + 1) % colors.length;
if (showStartMenu) {
cycleColors();
}
}
});
}
cycleColors();
}
// Add bouncing title animation
tween(titleTxt, {
y: titleTxt.y - 20,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleTxt, {
y: titleTxt.y + 20,
scaleX: 1,
scaleY: 1
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
// Add glowing effect to start button
function glowButton() {
tween(startButtonTxt, {
scaleX: 1.15,
scaleY: 1.15,
tint: 0x00FFFF
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButtonTxt, {
scaleX: 1,
scaleY: 1,
tint: 0x00FF00
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (showStartMenu) {
glowButton();
}
}
});
}
});
}
// Start animations
animateTitle();
glowButton();
// Set interval for continuous menu animations
var menuAnimationTimer = LK.setInterval(function () {
if (showStartMenu) {
// Recreate menu birds periodically
if (LK.ticks % 600 === 0) {
createMenuBirds();
}
// Add sparkle effect to coins
for (var i = 0; i < menuCoins.length; i++) {
if (Math.random() < 0.1 && menuCoins[i] && !menuCoins[i].destroyed) {
tween(menuCoins[i], {
alpha: 0.6,
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (menuCoins[i] && !menuCoins[i].destroyed) {
tween(menuCoins[i], {
alpha: 0.2,
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 300,
easing: tween.easeIn
});
}
}
});
}
}
}
}, 100);
// Create health bar
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
healthBarBg.x = 150;
healthBarBg.y = 20;
LK.gui.topLeft.addChild(healthBarBg);
healthBar = LK.getAsset('healthBarFill', {
anchorX: 0,
anchorY: 0
});
healthBar.x = 150;
healthBar.y = 20;
LK.gui.topLeft.addChild(healthBar);
// Create bird
bird = game.addChild(new Bird());
bird.x = 400;
bird.y = 1366; // Center of screen height
// Initialize health system
currentHealth = maxHealth;
updateHealthBar();
// Hide game UI initially
scoreTxt.alpha = 0;
instructionTxt.alpha = 0;
healthBarBg.alpha = 0;
healthBar.alpha = 0;
daysTxt.alpha = 0;
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = 2732 - 100; // Bottom of screen
// Game state tracking
var lastBirdY = bird.y;
var lastGroundCollision = false;
var lastCeilingCollision = false;
function spawnPipe() {
var pipe = new Pipe();
pipe.x = 2048 + 60; // Start off-screen right
// Random gap position (avoiding too high or too low)
var minGapY = 300;
var maxGapY = ground.y - 300;
var gapY = minGapY + Math.random() * (maxGapY - minGapY);
pipe.setGapPosition(gapY);
pipe.speed = -gameSpeed;
// Add entrance animation - pipes grow from small to normal size
pipe.scaleX = 0.3;
pipe.scaleY = 0.3;
tween(pipe, {
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
pipes.push(pipe);
game.addChild(pipe);
}
function spawnCoin() {
// Only spawn coin if there's a recent pipe to place it with
if (pipes.length > 0) {
var latestPipe = pipes[pipes.length - 1];
var coin = new Coin();
// Place coin slightly ahead of the pipe gap
coin.x = latestPipe.x + 150; // Position coin in the gap area
// Place coin in the center of the pipe gap
var gapCenterY = (latestPipe.topPipe.y + latestPipe.bottomPipe.y) / 2;
coin.y = gapCenterY;
coin.speed = -gameSpeed;
// Add sparkle entrance effect - coin appears with bounce
coin.scaleX = 0;
coin.scaleY = 0;
tween(coin, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(coin, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
coins.push(coin);
game.addChild(coin);
}
}
function spawnPowerUp() {
if (Math.random() < 0.3) {
// 30% chance
var powerUp = new PowerUp();
var types = ['shield', 'speedBoost'];
powerUp.type = types[Math.floor(Math.random() * types.length)];
powerUp.x = 2048 + 100;
powerUp.y = 300 + Math.random() * (ground.y - 600);
powerUp.speed = -gameSpeed;
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
function spawnCloud() {
var cloud = new Cloud();
cloud.x = 2048 + 100;
cloud.y = 100 + Math.random() * 400;
cloud.speed = -1 - Math.random() * 2;
clouds.push(cloud);
game.addChild(cloud);
}
function spawnStars() {
for (var i = 0; i < 5; i++) {
var star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
star.x = Math.random() * 2048;
star.y = Math.random() * 300;
star.alpha = 0.6;
star.scaleX = 0.3 + Math.random() * 0.4;
star.scaleY = star.scaleX;
game.addChild(star);
stars.push(star);
// Twinkling effect
tween(star, {
alpha: 0.2
}, {
duration: 1000 + Math.random() * 2000,
easing: tween.easeInOut
});
}
}
function checkPowerUpCollisions() {
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (bird.intersects(powerUp) && !powerUp.collected) {
powerUp.collect();
LK.getSound('powerup').play();
// Create particle effect
if (particleSystem) {
particleSystem.explode(powerUp.x, powerUp.y, 0x00BFFF, 8);
}
// Apply power-up effect
if (powerUp.type === 'shield') {
shieldActive = true;
shieldTime = 300; // 5 seconds at 60fps
// Visual shield effect
tween(bird, {
tint: 0x00BFFF
}, {
duration: 5000,
easing: tween.linear
});
} else if (powerUp.type === 'speedBoost') {
speedBoostActive = true;
speedBoostTime = 180; // 3 seconds at 60fps
gameSpeed *= 1.5;
}
powerUps.splice(i, 1);
}
}
}
function updatePowerUps() {
// Update shield
if (shieldActive) {
shieldTime--;
if (shieldTime <= 0) {
shieldActive = false;
tween(bird, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Update speed boost
if (speedBoostActive) {
speedBoostTime--;
if (speedBoostTime <= 0) {
speedBoostActive = false;
gameSpeed = Math.max(4, gameSpeed / 1.5);
}
}
}
// Cloud spawning function removed
function spawnFarm() {
var farm = new Farm();
farm.x = 2048;
farm.y = ground.y - 200; // Position above ground
farm.speed = -gameSpeed;
farms.push(farm);
game.addChild(farm);
}
function spawnAnimal() {
if (farms.length > 0) {
var randomFarm = farms[Math.floor(Math.random() * farms.length)];
var animalTypes = [Cow, Sheep, Pig, Chicken];
var AnimalClass = animalTypes[Math.floor(Math.random() * animalTypes.length)];
var animal = new AnimalClass();
animal.x = randomFarm.x + Math.random() * 1500; // Random position on farm
animal.baseY = randomFarm.y;
animal.y = animal.baseY;
animal.speed = -gameSpeed;
animals.push(animal);
game.addChild(animal);
}
}
function updateHealthBar() {
var healthPercent = currentHealth / maxHealth;
healthBar.width = 300 * healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
// Flash effect when damaged
tween(healthBar, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(healthBar, {
alpha: 1
}, {
duration: 100
});
}
});
}
function takeDamage() {
// Check if shield is active
if (shieldActive) {
// Create shield deflection effect
if (particleSystem) {
particleSystem.explode(bird.x, bird.y, 0x00BFFF, 12);
}
LK.getSound('collect').play();
return false; // No damage taken
}
currentHealth--;
updateHealthBar();
if (currentHealth <= 0) {
LK.getSound('hit').play();
// Add dramatic screen shake before game over
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 20,
y: originalY + 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX - 15,
y: originalY - 8
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 100,
onFinish: function onFinish() {
showCustomGameOver();
}
});
}
});
}
});
return true; // Game over
}
LK.getSound('hit').play();
// Create damage particles
if (particleSystem) {
particleSystem.explode(bird.x, bird.y, 0xFF0000, 6);
}
// Add screen shake effect for damage feedback
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 10,
y: originalY + 5
}, {
duration: 60,
onFinish: function onFinish() {
tween(game, {
x: originalX - 8,
y: originalY - 4
}, {
duration: 60,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 80
});
}
});
}
});
// Flash bird red when damaged
tween(bird, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(bird, {
tint: 0xffffff
}, {
duration: 200
});
}
});
return false; // Continue game
}
function checkCollisions() {
// Check ground collision
var currentGroundCollision = bird.y + 22 >= ground.y; // bird half-height
if (!lastGroundCollision && currentGroundCollision) {
LK.getSound('hit').play();
showCustomGameOver();
return;
}
lastGroundCollision = currentGroundCollision;
// Check heaven win condition - when bird reaches very top
var heavenThreshold = -50; // Above the screen
if (bird.y <= heavenThreshold) {
// Flash screen with heavenly light effect
tween(game, {
tint: 0xffffff
}, {
duration: 500,
onFinish: function onFinish() {
tween(game, {
tint: 0xffffff
}, {
duration: 500,
onFinish: function onFinish() {
LK.showYouWin(); // Show win screen
}
});
}
});
return;
}
// Check ceiling collision (but not heaven)
var currentCeilingCollision = bird.y - 22 <= 0 && bird.y > heavenThreshold;
if (!lastCeilingCollision && currentCeilingCollision) {
LK.getSound('hit').play();
showCustomGameOver();
return;
}
lastCeilingCollision = currentCeilingCollision;
// Check pipe collisions and scoring
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
// Check if bird passed through pipe (scoring)
if (!pipe.passed && bird.x > pipe.x + 60) {
pipe.passed = true;
// Check if this is a milestone (every 10 pipes)
var pipesPassed = 0;
for (var p = 0; p < pipes.length; p++) {
if (pipes[p].passed) {
pipesPassed++;
}
}
// Add bonus points for every 10 pipes passed
if (pipesPassed > 0 && pipesPassed % 10 === 0) {
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Special visual effect for bonus score
tween(scoreTxt, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
LK.getSound('score').play();
// Increase difficulty every 5 pipes
if (LK.getScore() % 5 === 0) {
gameSpeed += 0.5;
}
}
// Check collision with pipes
var birdLeft = bird.x - 30;
var birdRight = bird.x + 30;
var birdTop = bird.y - 22;
var birdBottom = bird.y + 22;
var pipeLeft = pipe.x - 60;
var pipeRight = pipe.x + 60;
if (birdRight > pipeLeft && birdLeft < pipeRight) {
// Bird is horizontally aligned with pipe
var topPipeBottom = pipe.topPipe.y;
var bottomPipeTop = pipe.bottomPipe.y;
if (birdTop < topPipeBottom || birdBottom > bottomPipeTop) {
// Check if this pipe already caused damage
if (!pipe.damageCaused) {
pipe.damageCaused = true;
if (takeDamage()) {
return; // Game over
}
}
}
}
}
// Check coin collection
for (var j = coins.length - 1; j >= 0; j--) {
var coin = coins[j];
if (!coin.collected && bird.intersects(coin)) {
coin.collected = true;
LK.setScore(LK.getScore() + 1); // Coins worth 1 point
scoreTxt.setText(LK.getScore());
LK.getSound('score').play();
// Add score text animation for feedback
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
// Visual effect - make coin disappear with scaling
tween(coin, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
coin.destroy();
}
});
coins.splice(j, 1);
}
}
}
// Custom game over UI variables
var gameOverScreen = null;
var restartButton = null;
var continueButton = null;
var gameOverTitleTxt = null;
var showingGameOver = false;
function showCustomGameOver() {
if (showingGameOver) return;
showingGameOver = true;
gameStarted = false;
// Create game over overlay
gameOverScreen = new Container();
// Semi-transparent background
var overlay = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
overlay.width = 2048;
overlay.height = 2732;
overlay.alpha = 0.8;
overlay.tint = 0x000000;
gameOverScreen.addChild(overlay);
// Game Over title
gameOverTitleTxt = new Text2('GAME OVER', {
size: 100,
fill: 0xFF0000
});
gameOverTitleTxt.anchor.set(0.5, 0.5);
gameOverTitleTxt.x = 1024;
gameOverTitleTxt.y = 800;
gameOverScreen.addChild(gameOverTitleTxt);
// Restart button
restartButton = new Text2('RESTART', {
size: 80,
fill: 0x00FF00
});
restartButton.anchor.set(0.5, 0.5);
restartButton.x = 1024;
restartButton.y = 1200;
gameOverScreen.addChild(restartButton);
// Continue button (only show if not used yet)
if (!continueUsed) {
continueButton = new Text2('CONTINUE (2 LIVES)', {
size: 60,
fill: 0xFFD700
});
continueButton.anchor.set(0.5, 0.5);
continueButton.x = 1024;
continueButton.y = 1400;
gameOverScreen.addChild(continueButton);
}
game.addChild(gameOverScreen);
// Add pulsing animation to buttons
tween(restartButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
easing: tween.easeInOut
});
if (continueButton) {
tween(continueButton, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 800,
easing: tween.easeInOut
});
}
}
function restartGame() {
// Reset game state
gameStarted = false;
showingGameOver = false;
continueUsed = false;
currentHealth = maxHealth;
gameSpeed = 4;
LK.setScore(0);
scoreTxt.setText('0');
updateHealthBar();
// Clear all game objects
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroy();
}
pipes = [];
for (var j = coins.length - 1; j >= 0; j--) {
coins[j].destroy();
}
coins = [];
for (var k = animals.length - 1; k >= 0; k--) {
animals[k].destroy();
}
animals = [];
for (var l = farms.length - 1; l >= 0; l--) {
farms[l].destroy();
}
farms = [];
// Reset bird position
bird.x = 400;
bird.y = 1366;
bird.velocity = 0;
// Reset timers
pipeSpawnTimer = 0;
coinSpawnTimer = 0;
farmSpawnTimer = 0;
animalSpawnTimer = 0;
// Remove game over screen
if (gameOverScreen) {
gameOverScreen.destroy();
gameOverScreen = null;
}
// Show start menu again
showStartMenu = true;
titleTxt.alpha = 1;
titleTxt.y = -200;
titleTxt.tint = 0xFFD700;
startButtonTxt.alpha = 1;
startButtonTxt.y = 100;
startButtonTxt.tint = 0x00FF00;
// Reset menu decorations
menuBirds = [];
menuCoins = [];
createMenuBirds();
createMenuCoins();
animateTitle();
glowButton();
// Hide game UI
scoreTxt.alpha = 0;
instructionTxt.alpha = 0;
healthBarBg.alpha = 0;
healthBar.alpha = 0;
daysTxt.alpha = 0;
}
function continueGame() {
if (continueUsed) return;
continueUsed = true;
showingGameOver = false;
gameStarted = true;
// Give 2 lives (set health to 2)
currentHealth = 2;
updateHealthBar();
// Reset bird position to safe spot
bird.x = 400;
bird.y = 1366;
bird.velocity = 0;
// Remove game over screen
if (gameOverScreen) {
gameOverScreen.destroy();
gameOverScreen = null;
}
// Continue with current score and game state
}
// Touch controls
game.down = function (x, y, obj) {
// Handle game over screen touches
if (showingGameOver) {
// Use the x, y coordinates directly from the touch event
// Check restart button
if (restartButton && x >= restartButton.x - 150 && x <= restartButton.x + 150 && y >= restartButton.y - 50 && y <= restartButton.y + 50) {
restartGame();
return;
}
// Check continue button (if available)
if (continueButton && !continueUsed && x >= continueButton.x - 200 && x <= continueButton.x + 200 && y >= continueButton.y - 40 && y <= continueButton.y + 40) {
continueGame();
return;
}
return;
}
if (showStartMenu) {
// Start the game from menu
showStartMenu = false;
gameStarted = true;
// Update days counter
var currentDate = new Date().toDateString();
var lastPlayDate = storage.lastPlayDate || '';
var daysPlayed = storage.daysPlayed || 0;
if (lastPlayDate !== currentDate) {
daysPlayed++;
storage.daysPlayed = daysPlayed;
storage.lastPlayDate = currentDate;
}
daysTxt.setText('Days: ' + daysPlayed);
// Smooth fade out menu elements
tween(titleTxt, {
alpha: 0,
y: titleTxt.y - 100
}, {
duration: 500,
easing: tween.easeIn
});
tween(startButtonTxt, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn
});
// Clean up menu decorations
for (var i = 0; i < menuBirds.length; i++) {
tween(menuBirds[i], {
alpha: 0,
y: menuBirds[i].y - 50
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (menuBirds[i]) {
menuBirds[i].destroy();
}
}
});
}
for (var j = 0; j < menuCoins.length; j++) {
tween(menuCoins[j], {
alpha: 0,
scaleX: 0,
scaleY: 0
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
if (menuCoins[j]) {
menuCoins[j].destroy();
}
}
});
}
// Clear timers
LK.clearInterval(menuAnimationTimer);
// Smooth fade in game UI
tween(scoreTxt, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
tween(instructionTxt, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
tween(healthBarBg, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
tween(healthBar, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
tween(daysTxt, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
// Start background music
try {
LK.playMusic('bgmusic', {
loop: true,
volume: 0.5
});
} catch (e) {
console.log('Music playback failed:', e);
}
// Hide instruction after a delay with smooth fade
tween(instructionTxt, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeInOut
});
bird.flap();
} else if (!gameStarted) {
gameStarted = true;
tween(instructionTxt, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut
});
bird.flap();
} else {
bird.flap();
}
};
// Main game loop
game.update = function () {
if (!gameStarted) {
return;
}
// Update bird
lastBirdY = bird.y;
// Update power-up effects
updatePowerUps();
// Spawn pipes
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnInterval) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer >= coinSpawnInterval) {
spawnCoin();
coinSpawnTimer = 0;
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= powerUpSpawnInterval) {
spawnPowerUp();
powerUpSpawnTimer = 0;
}
// Spawn clouds
cloudSpawnTimer++;
if (cloudSpawnTimer >= cloudSpawnInterval) {
spawnCloud();
cloudSpawnTimer = 0;
}
// Spawn farms
farmSpawnTimer++;
if (farmSpawnTimer >= farmSpawnInterval) {
spawnFarm();
farmSpawnTimer = 0;
}
// Spawn animals on existing farms
animalSpawnTimer++;
if (animalSpawnTimer >= animalSpawnInterval) {
spawnAnimal();
animalSpawnTimer = 0;
}
// Update pipes and remove off-screen ones
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.speed = -gameSpeed;
if (pipe.x < -120) {
pipe.destroy();
pipes.splice(i, 1);
}
}
// Update coins and remove off-screen ones
for (var j = coins.length - 1; j >= 0; j--) {
var coin = coins[j];
coin.speed = -gameSpeed;
if (coin.x < -40) {
coin.destroy();
coins.splice(j, 1);
}
}
// Update power-ups and remove off-screen ones
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
powerUp.speed = -gameSpeed;
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(p, 1);
}
}
// Update clouds and remove off-screen ones
for (var c = clouds.length - 1; c >= 0; c--) {
var cloud = clouds[c];
if (cloud.x < -200) {
cloud.destroy();
clouds.splice(c, 1);
}
}
// Update farms and remove off-screen ones
for (var l = farms.length - 1; l >= 0; l--) {
var farm = farms[l];
farm.speed = -gameSpeed;
if (farm.x < -2048) {
farm.destroy();
farms.splice(l, 1);
}
}
// Update animals and remove off-screen ones
for (var m = animals.length - 1; m >= 0; m--) {
var animal = animals[m];
animal.speed = -gameSpeed;
if (animal.x < -100) {
animal.destroy();
animals.splice(m, 1);
}
}
// Check power-up collisions
checkPowerUpCollisions();
// Check all collisions
checkCollisions();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Track if continue has been used in current session
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.flap = function () {
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Animate bird flap
tween(birdGraphics, {
rotation: -0.3
}, {
duration: 150
});
tween(birdGraphics, {
rotation: 0
}, {
duration: 150,
onFinish: function onFinish() {
if (self.velocity > 0) {
tween(birdGraphics, {
rotation: 0.3
}, {
duration: 200
});
}
}
});
};
self.update = function () {
// Don't update bird physics if game hasn't started
if (!gameStarted) {
return;
}
// Apply gravity
self.velocity += self.gravity;
if (self.velocity > self.maxFallSpeed) {
self.velocity = self.maxFallSpeed;
}
// Update position
self.y += self.velocity;
// Update rotation based on velocity with falling effect
var targetRotation = Math.min(Math.max(self.velocity * 0.05, -0.5), 0.8);
// Add dramatic falling effect when bird is falling fast
if (self.velocity > 8) {
// Create falling spin effect
tween(birdGraphics, {
rotation: targetRotation + Math.PI * 2
}, {
duration: 800,
easing: tween.easeIn
});
// Add slight scale effect during fall
tween(birdGraphics, {
scaleX: 0.9,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(birdGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
}
});
} else {
// Normal rotation for regular movement
birdGraphics.rotation = targetRotation;
}
};
return self;
});
var Chicken = Container.expand(function () {
var self = Container.call(this);
var chickenGraphics = self.attachAsset('chicken', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
self.baseY = 0;
self.pecking = false;
self.update = function () {
self.x += self.speed;
// Chicken walking animation - quick and jerky movements
var walkCycle = LK.ticks * 0.25; // Fast walking
// Quick head bobbing motion
self.y = self.baseY + Math.sin(walkCycle) * 1;
// Head jerking motion characteristic of chickens
chickenGraphics.x = Math.sin(walkCycle * 0.8) * 0.5;
// Periodic pecking animation
if (LK.ticks % 120 === 0) {
self.pecking = !self.pecking;
}
// Quick stepping animation every 10 frames for rapid chicken steps
if (LK.ticks % 10 === 0) {
var stepDirection = Math.floor(LK.ticks / 10) % 2 * 2 - 1;
tween(chickenGraphics, {
scaleY: 0.95,
scaleX: 1.05,
y: stepDirection * 0.3,
rotation: stepDirection * 0.05
}, {
duration: 50,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(chickenGraphics, {
scaleY: 1,
scaleX: 1,
y: 0,
rotation: 0
}, {
duration: 50,
easing: tween.easeIn
});
}
});
}
// Enhanced pecking motion when pecking
if (self.pecking) {
chickenGraphics.y = Math.sin(LK.ticks * 0.3) * 2;
}
};
return self;
});
var Cloud = Container.expand(function () {
var self = Container.call(this);
self.speed = -1;
self.cloudGraphics = self.attachAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
self.cloudGraphics.alpha = 0.6;
self.update = function () {
self.x += self.speed;
// Gentle floating
self.y += Math.sin(LK.ticks * 0.02) * 0.1;
};
return self;
});
// Cloud class removed
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.rotationSpeed = 0.1;
self.update = function () {
self.x += self.speed;
// Rotate coin for visual appeal
coinGraphics.rotation += self.rotationSpeed;
// Gentle floating animation
coinGraphics.y = Math.sin(LK.ticks * 0.05) * 3;
};
return self;
});
var Cow = Container.expand(function () {
var self = Container.call(this);
var cowGraphics = self.attachAsset('cow', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
// Add some black spots for cow appearance
self.baseY = 0;
self.update = function () {
self.x += self.speed;
// Proper walking animation with realistic bobbing
var walkCycle = LK.ticks * 0.15; // Walking speed
// Vertical bobbing motion - more pronounced and realistic
self.y = self.baseY + Math.sin(walkCycle) * 2;
// Subtle horizontal body sway
cowGraphics.x = Math.sin(walkCycle * 0.5) * 1;
// Body tilt during walking
cowGraphics.rotation = Math.sin(walkCycle) * 0.05;
// Step-based animation every 20 frames for more frequent steps
if (LK.ticks % 20 === 0) {
// Alternating leg movement effect
var stepDirection = Math.floor(LK.ticks / 20) % 2 * 2 - 1; // -1 or 1
// Step effect with body compression and extension
tween(cowGraphics, {
scaleY: 0.95,
scaleX: 1.05,
y: stepDirection * 1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(cowGraphics, {
scaleY: 1,
scaleX: 1,
y: 0
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
};
return self;
});
var Farm = Container.expand(function () {
var self = Container.call(this);
var farmGraphics = self.attachAsset('farmGround', {
anchorX: 0,
anchorY: 0
});
self.speed = -4;
self.update = function () {
self.x += self.speed;
};
return self;
});
var ParticleSystem = Container.expand(function () {
var self = Container.call(this);
self.particles = [];
self.maxParticles = 20;
self.createParticle = function (x, y, color, size) {
if (self.particles.length >= self.maxParticles) {
return;
}
var particle = LK.getAsset('particle', {
anchorX: 0.5,
anchorY: 0.5
});
particle.x = x;
particle.y = y;
particle.tint = color || 0xFFFFFF;
particle.scaleX = size || 1;
particle.scaleY = size || 1;
particle.velocity = {
x: (Math.random() - 0.5) * 10,
y: (Math.random() - 0.5) * 10
};
particle.life = 1.0;
particle.decay = 0.02;
self.addChild(particle);
self.particles.push(particle);
};
self.update = function () {
for (var i = self.particles.length - 1; i >= 0; i--) {
var particle = self.particles[i];
particle.x += particle.velocity.x;
particle.y += particle.velocity.y;
particle.velocity.y += 0.3; // gravity
particle.life -= particle.decay;
particle.alpha = particle.life;
if (particle.life <= 0) {
particle.destroy();
self.particles.splice(i, 1);
}
}
};
self.explode = function (x, y, color, count) {
for (var i = 0; i < (count || 10); i++) {
self.createParticle(x, y, color, Math.random() * 0.5 + 0.5);
}
};
return self;
});
var Pig = Container.expand(function () {
var self = Container.call(this);
var pigGraphics = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
self.baseY = 0;
self.update = function () {
self.x += self.speed;
// Pig walking animation - heavier and slower
var walkCycle = LK.ticks * 0.12; // Slower walking
// Heavy bobbing motion
self.y = self.baseY + Math.sin(walkCycle) * 1.2;
// Wide body sway for heavier appearance
pigGraphics.x = Math.sin(walkCycle * 0.3) * 1.5;
// Heavy stepping animation every 25 frames
if (LK.ticks % 25 === 0) {
var stepDirection = Math.floor(LK.ticks / 25) % 2 * 2 - 1;
tween(pigGraphics, {
scaleY: 0.92,
scaleX: 1.08,
y: stepDirection * 0.8
}, {
duration: 125,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pigGraphics, {
scaleY: 1,
scaleX: 1,
y: 0
}, {
duration: 125,
easing: tween.easeIn
});
}
});
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.speed = -4;
self.passed = false;
self.gapSize = 450;
// Create top pipe
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1
});
// Create top pipe segment (Mario-style cap)
self.topPipeSegment = self.attachAsset('pipeSegment', {
anchorX: 0.5,
anchorY: 1
});
// Create bottom pipe
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0
});
// Create bottom pipe segment (Mario-style cap)
self.bottomPipeSegment = self.attachAsset('pipeSegment', {
anchorX: 0.5,
anchorY: 0
});
self.setGapPosition = function (gapY) {
self.topPipe.y = gapY - self.gapSize / 2;
self.bottomPipe.y = gapY + self.gapSize / 2;
// Position the Mario-style pipe segments
self.topPipeSegment.y = gapY - self.gapSize / 2;
self.bottomPipeSegment.y = gapY + self.gapSize / 2;
};
self.update = function () {
self.x += self.speed;
};
return self;
});
var PowerUp = Container.expand(function () {
var self = Container.call(this);
self.type = 'shield'; // 'shield', 'speedBoost'
self.speed = -4;
self.collected = false;
self.rotationSpeed = 0.05;
self.powerUpGraphics = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
if (self.collected) return;
self.x += self.speed;
self.powerUpGraphics.rotation += self.rotationSpeed;
// Floating animation
self.powerUpGraphics.y = Math.sin(LK.ticks * 0.08) * 10;
// Pulsing effect
var pulse = Math.sin(LK.ticks * 0.1) * 0.2 + 1;
self.powerUpGraphics.scaleX = pulse;
self.powerUpGraphics.scaleY = pulse;
};
self.collect = function () {
self.collected = true;
// Collection effect
tween(self.powerUpGraphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var Sheep = Container.expand(function () {
var self = Container.call(this);
var sheepGraphics = self.attachAsset('sheep', {
anchorX: 0.5,
anchorY: 1
});
self.speed = -4;
self.baseY = 0;
self.update = function () {
self.x += self.speed;
// Sheep walking animation - lighter and bouncier than cows
var walkCycle = LK.ticks * 0.18; // Slightly faster walking
// Bouncy vertical movement
self.y = self.baseY + Math.sin(walkCycle) * 1.5;
// Gentle body sway
sheepGraphics.x = Math.sin(walkCycle * 0.4) * 0.8;
// Light stepping animation every 15 frames for quicker steps
if (LK.ticks % 15 === 0) {
var stepDirection = Math.floor(LK.ticks / 15) % 2 * 2 - 1;
tween(sheepGraphics, {
scaleY: 0.98,
scaleX: 1.02,
y: stepDirection * 0.5
}, {
duration: 75,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(sheepGraphics, {
scaleY: 1,
scaleX: 1,
y: 0
}, {
duration: 75,
easing: tween.easeIn
});
}
});
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x4a90e2
});
/****
* Game Code
****/
// Sound and music assets
// Power-up assets
// Menu decoration assets
// Visual effect assets
// Farm and animal assets
// Game element assets
// Health system assets
// Sky gradient assets removed
// Cloud asset removed
// Game variables
var continueUsed = false;
var bird;
var pipes = [];
var ground;
var gameStarted = false;
var gameSpeed = 4;
var pipeSpawnTimer = 0;
var pipeSpawnInterval = 180; // frames between pipe spawns
var lastPipeScore = 0;
var coins = [];
var coinSpawnTimer = 0;
var coinSpawnInterval = 200; // frames between coin spawns - slightly after pipes
var farms = [];
var farmSpawnTimer = 0;
var farmSpawnInterval = 400; // frames between farm spawns
var animals = [];
var animalSpawnTimer = 0;
var animalSpawnInterval = 150; // frames between animal spawns
// Enhanced visual systems
var clouds = [];
var cloudSpawnTimer = 0;
var cloudSpawnInterval = 300;
var powerUps = [];
var powerUpSpawnTimer = 0;
var powerUpSpawnInterval = 600;
var particleSystem;
var stars = [];
// Power-up effects
var shieldActive = false;
var shieldTime = 0;
var speedBoostActive = false;
var speedBoostTime = 0;
// Health system variables
var maxHealth = 3;
var currentHealth = 3;
var healthBar;
var healthBarBg;
// Achievement system
var achievements = {
firstFlight: false,
coinCollector: false,
survivor: false,
speedDemon: false
};
var achievementMessages = [];
// UI elements
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var instructionTxt = new Text2('Tap to Flap!', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(instructionTxt);
// Days counter display
var daysTxt = new Text2('Days: 0', {
size: 50,
fill: 0xFFFFFF
});
daysTxt.anchor.set(0, 0);
daysTxt.x = 20;
daysTxt.y = 70;
LK.gui.topLeft.addChild(daysTxt);
// Start menu UI elements
var showStartMenu = true;
var menuBirds = [];
var menuCoins = [];
// Create animated background birds for menu
function createMenuBirds() {
for (var i = 0; i < 3; i++) {
var menuBird = LK.getAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
menuBird.x = -100 - i * 200;
menuBird.y = 400 + i * 300;
menuBird.alpha = 0.3;
menuBird.scaleX = 0.6;
menuBird.scaleY = 0.6;
game.addChild(menuBird);
menuBirds.push(menuBird);
// Animate birds flying across screen
tween(menuBird, {
x: 2200,
y: menuBird.y + Math.sin(i) * 100
}, {
duration: 8000 + i * 1000,
easing: tween.linear
});
// Add gentle floating animation
tween(menuBird, {
y: menuBird.y + 30,
rotation: 0.2
}, {
duration: 2000 + i * 500,
easing: tween.easeInOut
});
}
}
// Create enhanced menu background
function createMenuBackground() {
// Add animated background
var menuBg = LK.getAsset('menuBg', {
anchorX: 0,
anchorY: 0
});
menuBg.x = 0;
menuBg.y = 0;
menuBg.alpha = 0.8;
game.addChild(menuBg);
menuCoins.push(menuBg);
// Add animated sun
var sun = LK.getAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
sun.x = 1800;
sun.y = 300;
sun.alpha = 0.7;
game.addChild(sun);
menuCoins.push(sun);
// Animate sun rotation
tween(sun, {
rotation: Math.PI * 2
}, {
duration: 10000,
easing: tween.linear
});
// Add clouds
for (var i = 0; i < 4; i++) {
var cloud = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloud.x = Math.random() * 2048;
cloud.y = 200 + Math.random() * 400;
cloud.alpha = 0.4;
cloud.scaleX = 0.8 + Math.random() * 0.4;
cloud.scaleY = 0.8 + Math.random() * 0.4;
game.addChild(cloud);
menuCoins.push(cloud);
// Animate clouds drifting
tween(cloud, {
x: cloud.x + 200,
y: cloud.y + Math.sin(i) * 50
}, {
duration: 15000 + i * 2000,
easing: tween.linear
});
}
// Add decorative trees
for (var j = 0; j < 6; j++) {
var tree = LK.getAsset('tree', {
anchorX: 0.5,
anchorY: 1
});
tree.x = j * 350 + 200;
tree.y = 2732 - 100;
tree.alpha = 0.3;
game.addChild(tree);
menuCoins.push(tree);
var treeTop = LK.getAsset('treeTop', {
anchorX: 0.5,
anchorY: 1
});
treeTop.x = tree.x;
treeTop.y = tree.y - 150;
treeTop.alpha = 0.3;
game.addChild(treeTop);
menuCoins.push(treeTop);
// Gentle swaying animation
tween(tree, {
rotation: 0.1
}, {
duration: 3000 + j * 500,
easing: tween.easeInOut
});
}
}
// Create floating coins for menu ambience
function createMenuCoins() {
for (var i = 0; i < 5; i++) {
var menuCoin = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
menuCoin.x = Math.random() * 2048;
menuCoin.y = Math.random() * 2732;
menuCoin.alpha = 0.2;
menuCoin.scaleX = 0.4;
menuCoin.scaleY = 0.4;
game.addChild(menuCoin);
menuCoins.push(menuCoin);
// Add gentle floating and rotation
tween(menuCoin, {
y: menuCoin.y + 50,
rotation: Math.PI * 2
}, {
duration: 3000 + i * 800,
easing: tween.easeInOut
});
}
}
var titleTxt = new Text2('Mutili Bird', {
size: 120,
fill: 0xFFD700
});
titleTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(titleTxt);
var startButtonTxt = new Text2('TAP TO START', {
size: 80,
fill: 0x00FF00
});
startButtonTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startButtonTxt);
// Initialize particle system
particleSystem = game.addChild(new ParticleSystem());
// Create enhanced menu with background
createMenuBackground();
createMenuBirds();
createMenuCoins();
spawnStars();
// Position menu elements
titleTxt.y = -200;
startButtonTxt.y = 100;
// Add rainbow title animation
function animateTitle() {
var colors = [0xFFD700, 0xFF6B6B, 0x4ECDC4, 0x45B7D1, 0x96CEB4, 0xF7DC6F, 0xBB8FCE];
var currentColorIndex = 0;
function cycleColors() {
tween(titleTxt, {
tint: colors[currentColorIndex]
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
currentColorIndex = (currentColorIndex + 1) % colors.length;
if (showStartMenu) {
cycleColors();
}
}
});
}
cycleColors();
}
// Add bouncing title animation
tween(titleTxt, {
y: titleTxt.y - 20,
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(titleTxt, {
y: titleTxt.y + 20,
scaleX: 1,
scaleY: 1
}, {
duration: 1500,
easing: tween.easeInOut
});
}
});
// Add glowing effect to start button
function glowButton() {
tween(startButtonTxt, {
scaleX: 1.15,
scaleY: 1.15,
tint: 0x00FFFF
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(startButtonTxt, {
scaleX: 1,
scaleY: 1,
tint: 0x00FF00
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (showStartMenu) {
glowButton();
}
}
});
}
});
}
// Start animations
animateTitle();
glowButton();
// Set interval for continuous menu animations
var menuAnimationTimer = LK.setInterval(function () {
if (showStartMenu) {
// Recreate menu birds periodically
if (LK.ticks % 600 === 0) {
createMenuBirds();
}
// Add sparkle effect to coins
for (var i = 0; i < menuCoins.length; i++) {
if (Math.random() < 0.1 && menuCoins[i] && !menuCoins[i].destroyed) {
tween(menuCoins[i], {
alpha: 0.6,
scaleX: 0.6,
scaleY: 0.6
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (menuCoins[i] && !menuCoins[i].destroyed) {
tween(menuCoins[i], {
alpha: 0.2,
scaleX: 0.4,
scaleY: 0.4
}, {
duration: 300,
easing: tween.easeIn
});
}
}
});
}
}
}
}, 100);
// Create health bar
healthBarBg = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
healthBarBg.x = 150;
healthBarBg.y = 20;
LK.gui.topLeft.addChild(healthBarBg);
healthBar = LK.getAsset('healthBarFill', {
anchorX: 0,
anchorY: 0
});
healthBar.x = 150;
healthBar.y = 20;
LK.gui.topLeft.addChild(healthBar);
// Create bird
bird = game.addChild(new Bird());
bird.x = 400;
bird.y = 1366; // Center of screen height
// Initialize health system
currentHealth = maxHealth;
updateHealthBar();
// Hide game UI initially
scoreTxt.alpha = 0;
instructionTxt.alpha = 0;
healthBarBg.alpha = 0;
healthBar.alpha = 0;
daysTxt.alpha = 0;
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = 2732 - 100; // Bottom of screen
// Game state tracking
var lastBirdY = bird.y;
var lastGroundCollision = false;
var lastCeilingCollision = false;
function spawnPipe() {
var pipe = new Pipe();
pipe.x = 2048 + 60; // Start off-screen right
// Random gap position (avoiding too high or too low)
var minGapY = 300;
var maxGapY = ground.y - 300;
var gapY = minGapY + Math.random() * (maxGapY - minGapY);
pipe.setGapPosition(gapY);
pipe.speed = -gameSpeed;
// Add entrance animation - pipes grow from small to normal size
pipe.scaleX = 0.3;
pipe.scaleY = 0.3;
tween(pipe, {
scaleX: 1,
scaleY: 1
}, {
duration: 400,
easing: tween.easeOut
});
pipes.push(pipe);
game.addChild(pipe);
}
function spawnCoin() {
// Only spawn coin if there's a recent pipe to place it with
if (pipes.length > 0) {
var latestPipe = pipes[pipes.length - 1];
var coin = new Coin();
// Place coin slightly ahead of the pipe gap
coin.x = latestPipe.x + 150; // Position coin in the gap area
// Place coin in the center of the pipe gap
var gapCenterY = (latestPipe.topPipe.y + latestPipe.bottomPipe.y) / 2;
coin.y = gapCenterY;
coin.speed = -gameSpeed;
// Add sparkle entrance effect - coin appears with bounce
coin.scaleX = 0;
coin.scaleY = 0;
tween(coin, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(coin, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
coins.push(coin);
game.addChild(coin);
}
}
function spawnPowerUp() {
if (Math.random() < 0.3) {
// 30% chance
var powerUp = new PowerUp();
var types = ['shield', 'speedBoost'];
powerUp.type = types[Math.floor(Math.random() * types.length)];
powerUp.x = 2048 + 100;
powerUp.y = 300 + Math.random() * (ground.y - 600);
powerUp.speed = -gameSpeed;
powerUps.push(powerUp);
game.addChild(powerUp);
}
}
function spawnCloud() {
var cloud = new Cloud();
cloud.x = 2048 + 100;
cloud.y = 100 + Math.random() * 400;
cloud.speed = -1 - Math.random() * 2;
clouds.push(cloud);
game.addChild(cloud);
}
function spawnStars() {
for (var i = 0; i < 5; i++) {
var star = LK.getAsset('star', {
anchorX: 0.5,
anchorY: 0.5
});
star.x = Math.random() * 2048;
star.y = Math.random() * 300;
star.alpha = 0.6;
star.scaleX = 0.3 + Math.random() * 0.4;
star.scaleY = star.scaleX;
game.addChild(star);
stars.push(star);
// Twinkling effect
tween(star, {
alpha: 0.2
}, {
duration: 1000 + Math.random() * 2000,
easing: tween.easeInOut
});
}
}
function checkPowerUpCollisions() {
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (bird.intersects(powerUp) && !powerUp.collected) {
powerUp.collect();
LK.getSound('powerup').play();
// Create particle effect
if (particleSystem) {
particleSystem.explode(powerUp.x, powerUp.y, 0x00BFFF, 8);
}
// Apply power-up effect
if (powerUp.type === 'shield') {
shieldActive = true;
shieldTime = 300; // 5 seconds at 60fps
// Visual shield effect
tween(bird, {
tint: 0x00BFFF
}, {
duration: 5000,
easing: tween.linear
});
} else if (powerUp.type === 'speedBoost') {
speedBoostActive = true;
speedBoostTime = 180; // 3 seconds at 60fps
gameSpeed *= 1.5;
}
powerUps.splice(i, 1);
}
}
}
function updatePowerUps() {
// Update shield
if (shieldActive) {
shieldTime--;
if (shieldTime <= 0) {
shieldActive = false;
tween(bird, {
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeOut
});
}
}
// Update speed boost
if (speedBoostActive) {
speedBoostTime--;
if (speedBoostTime <= 0) {
speedBoostActive = false;
gameSpeed = Math.max(4, gameSpeed / 1.5);
}
}
}
// Cloud spawning function removed
function spawnFarm() {
var farm = new Farm();
farm.x = 2048;
farm.y = ground.y - 200; // Position above ground
farm.speed = -gameSpeed;
farms.push(farm);
game.addChild(farm);
}
function spawnAnimal() {
if (farms.length > 0) {
var randomFarm = farms[Math.floor(Math.random() * farms.length)];
var animalTypes = [Cow, Sheep, Pig, Chicken];
var AnimalClass = animalTypes[Math.floor(Math.random() * animalTypes.length)];
var animal = new AnimalClass();
animal.x = randomFarm.x + Math.random() * 1500; // Random position on farm
animal.baseY = randomFarm.y;
animal.y = animal.baseY;
animal.speed = -gameSpeed;
animals.push(animal);
game.addChild(animal);
}
}
function updateHealthBar() {
var healthPercent = currentHealth / maxHealth;
healthBar.width = 300 * healthPercent;
// Change color based on health
if (healthPercent > 0.6) {
healthBar.tint = 0x00ff00; // Green
} else if (healthPercent > 0.3) {
healthBar.tint = 0xffff00; // Yellow
} else {
healthBar.tint = 0xff0000; // Red
}
// Flash effect when damaged
tween(healthBar, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(healthBar, {
alpha: 1
}, {
duration: 100
});
}
});
}
function takeDamage() {
// Check if shield is active
if (shieldActive) {
// Create shield deflection effect
if (particleSystem) {
particleSystem.explode(bird.x, bird.y, 0x00BFFF, 12);
}
LK.getSound('collect').play();
return false; // No damage taken
}
currentHealth--;
updateHealthBar();
if (currentHealth <= 0) {
LK.getSound('hit').play();
// Add dramatic screen shake before game over
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 20,
y: originalY + 10
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX - 15,
y: originalY - 8
}, {
duration: 50,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 100,
onFinish: function onFinish() {
showCustomGameOver();
}
});
}
});
}
});
return true; // Game over
}
LK.getSound('hit').play();
// Create damage particles
if (particleSystem) {
particleSystem.explode(bird.x, bird.y, 0xFF0000, 6);
}
// Add screen shake effect for damage feedback
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + 10,
y: originalY + 5
}, {
duration: 60,
onFinish: function onFinish() {
tween(game, {
x: originalX - 8,
y: originalY - 4
}, {
duration: 60,
onFinish: function onFinish() {
tween(game, {
x: originalX,
y: originalY
}, {
duration: 80
});
}
});
}
});
// Flash bird red when damaged
tween(bird, {
tint: 0xff0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(bird, {
tint: 0xffffff
}, {
duration: 200
});
}
});
return false; // Continue game
}
function checkCollisions() {
// Check ground collision
var currentGroundCollision = bird.y + 22 >= ground.y; // bird half-height
if (!lastGroundCollision && currentGroundCollision) {
LK.getSound('hit').play();
showCustomGameOver();
return;
}
lastGroundCollision = currentGroundCollision;
// Check heaven win condition - when bird reaches very top
var heavenThreshold = -50; // Above the screen
if (bird.y <= heavenThreshold) {
// Flash screen with heavenly light effect
tween(game, {
tint: 0xffffff
}, {
duration: 500,
onFinish: function onFinish() {
tween(game, {
tint: 0xffffff
}, {
duration: 500,
onFinish: function onFinish() {
LK.showYouWin(); // Show win screen
}
});
}
});
return;
}
// Check ceiling collision (but not heaven)
var currentCeilingCollision = bird.y - 22 <= 0 && bird.y > heavenThreshold;
if (!lastCeilingCollision && currentCeilingCollision) {
LK.getSound('hit').play();
showCustomGameOver();
return;
}
lastCeilingCollision = currentCeilingCollision;
// Check pipe collisions and scoring
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
// Check if bird passed through pipe (scoring)
if (!pipe.passed && bird.x > pipe.x + 60) {
pipe.passed = true;
// Check if this is a milestone (every 10 pipes)
var pipesPassed = 0;
for (var p = 0; p < pipes.length; p++) {
if (pipes[p].passed) {
pipesPassed++;
}
}
// Add bonus points for every 10 pipes passed
if (pipesPassed > 0 && pipesPassed % 10 === 0) {
LK.setScore(LK.getScore() + 10);
scoreTxt.setText(LK.getScore());
// Special visual effect for bonus score
tween(scoreTxt, {
scaleX: 1.5,
scaleY: 1.5,
tint: 0xFFD700
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1,
tint: 0xFFFFFF
}, {
duration: 300,
easing: tween.easeIn
});
}
});
}
LK.getSound('score').play();
// Increase difficulty every 5 pipes
if (LK.getScore() % 5 === 0) {
gameSpeed += 0.5;
}
}
// Check collision with pipes
var birdLeft = bird.x - 30;
var birdRight = bird.x + 30;
var birdTop = bird.y - 22;
var birdBottom = bird.y + 22;
var pipeLeft = pipe.x - 60;
var pipeRight = pipe.x + 60;
if (birdRight > pipeLeft && birdLeft < pipeRight) {
// Bird is horizontally aligned with pipe
var topPipeBottom = pipe.topPipe.y;
var bottomPipeTop = pipe.bottomPipe.y;
if (birdTop < topPipeBottom || birdBottom > bottomPipeTop) {
// Check if this pipe already caused damage
if (!pipe.damageCaused) {
pipe.damageCaused = true;
if (takeDamage()) {
return; // Game over
}
}
}
}
}
// Check coin collection
for (var j = coins.length - 1; j >= 0; j--) {
var coin = coins[j];
if (!coin.collected && bird.intersects(coin)) {
coin.collected = true;
LK.setScore(LK.getScore() + 1); // Coins worth 1 point
scoreTxt.setText(LK.getScore());
LK.getSound('score').play();
// Add score text animation for feedback
tween(scoreTxt, {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(scoreTxt, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeIn
});
}
});
// Visual effect - make coin disappear with scaling
tween(coin, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
coin.destroy();
}
});
coins.splice(j, 1);
}
}
}
// Custom game over UI variables
var gameOverScreen = null;
var restartButton = null;
var continueButton = null;
var gameOverTitleTxt = null;
var showingGameOver = false;
function showCustomGameOver() {
if (showingGameOver) return;
showingGameOver = true;
gameStarted = false;
// Create game over overlay
gameOverScreen = new Container();
// Semi-transparent background
var overlay = LK.getAsset('healthBarBg', {
anchorX: 0,
anchorY: 0
});
overlay.width = 2048;
overlay.height = 2732;
overlay.alpha = 0.8;
overlay.tint = 0x000000;
gameOverScreen.addChild(overlay);
// Game Over title
gameOverTitleTxt = new Text2('GAME OVER', {
size: 100,
fill: 0xFF0000
});
gameOverTitleTxt.anchor.set(0.5, 0.5);
gameOverTitleTxt.x = 1024;
gameOverTitleTxt.y = 800;
gameOverScreen.addChild(gameOverTitleTxt);
// Restart button
restartButton = new Text2('RESTART', {
size: 80,
fill: 0x00FF00
});
restartButton.anchor.set(0.5, 0.5);
restartButton.x = 1024;
restartButton.y = 1200;
gameOverScreen.addChild(restartButton);
// Continue button (only show if not used yet)
if (!continueUsed) {
continueButton = new Text2('CONTINUE (2 LIVES)', {
size: 60,
fill: 0xFFD700
});
continueButton.anchor.set(0.5, 0.5);
continueButton.x = 1024;
continueButton.y = 1400;
gameOverScreen.addChild(continueButton);
}
game.addChild(gameOverScreen);
// Add pulsing animation to buttons
tween(restartButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
easing: tween.easeInOut
});
if (continueButton) {
tween(continueButton, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 800,
easing: tween.easeInOut
});
}
}
function restartGame() {
// Reset game state
gameStarted = false;
showingGameOver = false;
continueUsed = false;
currentHealth = maxHealth;
gameSpeed = 4;
LK.setScore(0);
scoreTxt.setText('0');
updateHealthBar();
// Clear all game objects
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroy();
}
pipes = [];
for (var j = coins.length - 1; j >= 0; j--) {
coins[j].destroy();
}
coins = [];
for (var k = animals.length - 1; k >= 0; k--) {
animals[k].destroy();
}
animals = [];
for (var l = farms.length - 1; l >= 0; l--) {
farms[l].destroy();
}
farms = [];
// Reset bird position
bird.x = 400;
bird.y = 1366;
bird.velocity = 0;
// Reset timers
pipeSpawnTimer = 0;
coinSpawnTimer = 0;
farmSpawnTimer = 0;
animalSpawnTimer = 0;
// Remove game over screen
if (gameOverScreen) {
gameOverScreen.destroy();
gameOverScreen = null;
}
// Show start menu again
showStartMenu = true;
titleTxt.alpha = 1;
titleTxt.y = -200;
titleTxt.tint = 0xFFD700;
startButtonTxt.alpha = 1;
startButtonTxt.y = 100;
startButtonTxt.tint = 0x00FF00;
// Reset menu decorations
menuBirds = [];
menuCoins = [];
createMenuBirds();
createMenuCoins();
animateTitle();
glowButton();
// Hide game UI
scoreTxt.alpha = 0;
instructionTxt.alpha = 0;
healthBarBg.alpha = 0;
healthBar.alpha = 0;
daysTxt.alpha = 0;
}
function continueGame() {
if (continueUsed) return;
continueUsed = true;
showingGameOver = false;
gameStarted = true;
// Give 2 lives (set health to 2)
currentHealth = 2;
updateHealthBar();
// Reset bird position to safe spot
bird.x = 400;
bird.y = 1366;
bird.velocity = 0;
// Remove game over screen
if (gameOverScreen) {
gameOverScreen.destroy();
gameOverScreen = null;
}
// Continue with current score and game state
}
// Touch controls
game.down = function (x, y, obj) {
// Handle game over screen touches
if (showingGameOver) {
// Use the x, y coordinates directly from the touch event
// Check restart button
if (restartButton && x >= restartButton.x - 150 && x <= restartButton.x + 150 && y >= restartButton.y - 50 && y <= restartButton.y + 50) {
restartGame();
return;
}
// Check continue button (if available)
if (continueButton && !continueUsed && x >= continueButton.x - 200 && x <= continueButton.x + 200 && y >= continueButton.y - 40 && y <= continueButton.y + 40) {
continueGame();
return;
}
return;
}
if (showStartMenu) {
// Start the game from menu
showStartMenu = false;
gameStarted = true;
// Update days counter
var currentDate = new Date().toDateString();
var lastPlayDate = storage.lastPlayDate || '';
var daysPlayed = storage.daysPlayed || 0;
if (lastPlayDate !== currentDate) {
daysPlayed++;
storage.daysPlayed = daysPlayed;
storage.lastPlayDate = currentDate;
}
daysTxt.setText('Days: ' + daysPlayed);
// Smooth fade out menu elements
tween(titleTxt, {
alpha: 0,
y: titleTxt.y - 100
}, {
duration: 500,
easing: tween.easeIn
});
tween(startButtonTxt, {
alpha: 0,
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 300,
easing: tween.easeIn
});
// Clean up menu decorations
for (var i = 0; i < menuBirds.length; i++) {
tween(menuBirds[i], {
alpha: 0,
y: menuBirds[i].y - 50
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
if (menuBirds[i]) {
menuBirds[i].destroy();
}
}
});
}
for (var j = 0; j < menuCoins.length; j++) {
tween(menuCoins[j], {
alpha: 0,
scaleX: 0,
scaleY: 0
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
if (menuCoins[j]) {
menuCoins[j].destroy();
}
}
});
}
// Clear timers
LK.clearInterval(menuAnimationTimer);
// Smooth fade in game UI
tween(scoreTxt, {
alpha: 1
}, {
duration: 800,
easing: tween.easeOut
});
tween(instructionTxt, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeOut
});
tween(healthBarBg, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
tween(healthBar, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
tween(daysTxt, {
alpha: 1
}, {
duration: 600,
easing: tween.easeOut
});
// Start background music
try {
LK.playMusic('bgmusic', {
loop: true,
volume: 0.5
});
} catch (e) {
console.log('Music playback failed:', e);
}
// Hide instruction after a delay with smooth fade
tween(instructionTxt, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeInOut
});
bird.flap();
} else if (!gameStarted) {
gameStarted = true;
tween(instructionTxt, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut
});
bird.flap();
} else {
bird.flap();
}
};
// Main game loop
game.update = function () {
if (!gameStarted) {
return;
}
// Update bird
lastBirdY = bird.y;
// Update power-up effects
updatePowerUps();
// Spawn pipes
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnInterval) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Spawn coins
coinSpawnTimer++;
if (coinSpawnTimer >= coinSpawnInterval) {
spawnCoin();
coinSpawnTimer = 0;
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= powerUpSpawnInterval) {
spawnPowerUp();
powerUpSpawnTimer = 0;
}
// Spawn clouds
cloudSpawnTimer++;
if (cloudSpawnTimer >= cloudSpawnInterval) {
spawnCloud();
cloudSpawnTimer = 0;
}
// Spawn farms
farmSpawnTimer++;
if (farmSpawnTimer >= farmSpawnInterval) {
spawnFarm();
farmSpawnTimer = 0;
}
// Spawn animals on existing farms
animalSpawnTimer++;
if (animalSpawnTimer >= animalSpawnInterval) {
spawnAnimal();
animalSpawnTimer = 0;
}
// Update pipes and remove off-screen ones
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.speed = -gameSpeed;
if (pipe.x < -120) {
pipe.destroy();
pipes.splice(i, 1);
}
}
// Update coins and remove off-screen ones
for (var j = coins.length - 1; j >= 0; j--) {
var coin = coins[j];
coin.speed = -gameSpeed;
if (coin.x < -40) {
coin.destroy();
coins.splice(j, 1);
}
}
// Update power-ups and remove off-screen ones
for (var p = powerUps.length - 1; p >= 0; p--) {
var powerUp = powerUps[p];
powerUp.speed = -gameSpeed;
if (powerUp.x < -100) {
powerUp.destroy();
powerUps.splice(p, 1);
}
}
// Update clouds and remove off-screen ones
for (var c = clouds.length - 1; c >= 0; c--) {
var cloud = clouds[c];
if (cloud.x < -200) {
cloud.destroy();
clouds.splice(c, 1);
}
}
// Update farms and remove off-screen ones
for (var l = farms.length - 1; l >= 0; l--) {
var farm = farms[l];
farm.speed = -gameSpeed;
if (farm.x < -2048) {
farm.destroy();
farms.splice(l, 1);
}
}
// Update animals and remove off-screen ones
for (var m = animals.length - 1; m >= 0; m--) {
var animal = animals[m];
animal.speed = -gameSpeed;
if (animal.x < -100) {
animal.destroy();
animals.splice(m, 1);
}
}
// Check power-up collisions
checkPowerUpCollisions();
// Check all collisions
checkCollisions();
};