/****
* 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.flapPower = -12;
self.maxFallSpeed = 15;
self.maxRiseSpeed = -15;
self.flap = function () {
self.velocity = self.flapPower;
LK.getSound('flap').play();
// Rotate bird upward when flapping
tween(birdGraphics, {
rotation: -0.5
}, {
duration: 200
});
};
self.update = function () {
// Apply gravity
self.velocity += self.gravity;
// Limit velocity
if (self.velocity > self.maxFallSpeed) {
self.velocity = self.maxFallSpeed;
}
if (self.velocity < self.maxRiseSpeed) {
self.velocity = self.maxRiseSpeed;
}
// Update position
self.y += self.velocity;
// Rotate bird based on velocity
var targetRotation = self.velocity * 0.1;
if (targetRotation > 1.5) targetRotation = 1.5;
if (targetRotation < -0.5) targetRotation = -0.5;
tween(birdGraphics, {
rotation: targetRotation
}, {
duration: 100
});
};
return self;
});
var Particle = Container.expand(function (x, y, color) {
var self = Container.call(this);
var particle = self.attachAsset('speedPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = color;
particle.scaleX = 0.3;
particle.scaleY = 0.3;
self.x = x;
self.y = y;
self.velocityX = (Math.random() - 0.5) * 8;
self.velocityY = (Math.random() - 0.5) * 8;
self.life = 60; // 1 second at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.life--;
// Fade out over time
particle.alpha = self.life / 60;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.speed = -4;
self.scored = false;
// Dynamic gap height that decreases with score for progressive difficulty
var gapReduction = LK.getScore() * 5; // Reduce gap by 5px per point
self.gapHeight = Math.max(250, 350 - gapReduction); // Minimum gap of 250px
// 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
});
// Extend pipes to fill entire screen height
self.topPipe.height = 2732;
self.bottomPipe.height = 2732;
self.setGapPosition = function (centerY) {
self.topPipe.y = centerY - self.gapHeight / 2;
self.bottomPipe.y = centerY + self.gapHeight / 2;
};
self.update = function () {
self.x += self.speed;
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.speed = -4;
self.type = type;
self.collected = false;
var powerUpGraphics;
if (type === 'speed') {
powerUpGraphics = self.attachAsset('speedPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'invincibility') {
powerUpGraphics = self.attachAsset('invincibilityPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Add pulsing animation
self.pulseTime = 0;
// Add glow effect using tween
tween(powerUpGraphics, {
alpha: 0.6
}, {
duration: 800,
yoyo: true,
repeat: -1
});
self.update = function () {
self.x += self.speed;
// Pulsing animation
self.pulseTime += 0.2;
var scale = 1 + Math.sin(self.pulseTime) * 0.2;
powerUpGraphics.scaleX = scale;
powerUpGraphics.scaleY = scale;
};
return self;
});
var TrailNode = Container.expand(function (x, y) {
var self = Container.call(this);
var trail = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
trail.alpha = 0.3;
trail.scaleX = 0.7;
trail.scaleY = 0.7;
trail.tint = 0x88CCFF;
self.x = x;
self.y = y;
self.life = 20; // Trail lasts 20 frames
self.update = function () {
self.life--;
trail.alpha = self.life / 20 * 0.3;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var bird;
var pipes = [];
var powerUps = [];
var particles = [];
var trails = [];
var ground;
var gameStarted = false;
var pipeSpawnTimer = 0;
var pipeSpawnInterval = 240; // Spawn pipe every 4 seconds at 60fps for much more spacing
var powerUpSpawnTimer = 0;
var powerUpSpawnInterval = 480; // Spawn power-up every 8 seconds to match increased spacing
var speedBoostTimer = 0;
var invincibilityTimer = 0;
var comboScore = 0;
var comboTimer = 0;
var trailTimer = 0;
var currentMusicTrack = null;
// Create score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// Create speed indicator
var speedTxt = new Text2('SPEED: 1x', {
size: 40,
fill: 0xFFD700
});
speedTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(speedTxt);
speedTxt.x = -20;
speedTxt.y = 120;
// Create combo display
var comboTxt = new Text2('', {
size: 50,
fill: 0xFF6B35
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.y = 150;
comboTxt.visible = false;
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = 2732 - 100;
ground.width = 2048 * 3; // Make ground wider for scrolling effect
ground.scrollSpeed = -2;
// Create bird
bird = game.addChild(new Bird());
bird.x = 300;
bird.y = 1366; // Middle of screen
bird.startY = 1366;
bird.floatTime = 0;
// Add gentle floating animation before game starts
bird.updateFloat = function () {
if (!gameStarted) {
bird.floatTime += 0.1;
bird.y = bird.startY + Math.sin(bird.floatTime) * 20;
}
};
// Create instruction text
var instructionTxt = new Text2('TAP TO FLAP', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 1024;
instructionTxt.y = 1000;
game.addChild(instructionTxt);
function startGame() {
gameStarted = true;
instructionTxt.visible = false;
bird.flap();
}
function spawnPipe() {
var pipe = new Pipe();
pipe.x = 2048 + 60; // Start off screen
// Random gap position (avoid too high or too low)
var minGapCenter = 200;
var maxGapCenter = 2732 - 200 - 100; // Account for ground
var gapCenter = minGapCenter + Math.random() * (maxGapCenter - minGapCenter);
pipe.setGapPosition(gapCenter);
pipes.push(pipe);
game.addChild(pipe);
}
function createTrail() {
var trail = new TrailNode(bird.x, bird.y);
trails.push(trail);
game.addChild(trail);
}
function updateCombo() {
comboScore++;
comboTimer = 180; // 3 seconds
if (comboScore >= 3) {
comboTxt.setText('COMBO x' + comboScore + '!');
comboTxt.visible = true;
LK.effects.flashObject(comboTxt, 0xFF6B35, 500);
}
}
function resetCombo() {
comboScore = 0;
comboTimer = 0;
comboTxt.visible = false;
}
function spawnPowerUp() {
var types = ['speed', 'invincibility'];
var type = types[Math.floor(Math.random() * types.length)];
var powerUp = new PowerUp(type);
powerUp.x = 2048 + 20;
powerUp.y = 200 + Math.random() * (2732 - 400 - 100);
powerUps.push(powerUp);
game.addChild(powerUp);
}
function createParticleEffect(x, y, color, count) {
for (var i = 0; i < count; i++) {
var particle = new Particle(x, y, color);
particles.push(particle);
game.addChild(particle);
}
}
function checkCollisions() {
// Check ground collision
if (bird.y + 30 > ground.y) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
// Check ceiling collision
if (bird.y - 30 < 0) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
// Check pipe collisions
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
// Check if bird is in pipe's x range
if (bird.x + 30 > pipe.x - 60 && bird.x - 30 < pipe.x + 60) {
// Check collision with top pipe
if (bird.y - 22 < pipe.topPipe.y) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
// Check collision with bottom pipe
if (bird.y + 22 > pipe.bottomPipe.y) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
}
// Check for scoring
if (!pipe.scored && bird.x > pipe.x + 60) {
pipe.scored = true;
var basePoints = 1;
var bonusPoints = comboScore >= 3 ? comboScore : 0;
var totalPoints = basePoints + bonusPoints;
LK.setScore(LK.getScore() + totalPoints);
scoreTxt.setText(LK.getScore());
LK.getSound('score').play();
// Flash score text when scoring
LK.effects.flashObject(scoreTxt, 0xFFD700, 300);
// Update combo system
updateCombo();
// Create particles for high combos
if (comboScore >= 5) {
createParticleEffect(bird.x, bird.y, 0xFFD700, 6);
}
}
}
// Check power-up collisions
for (var j = 0; j < powerUps.length; j++) {
var powerUp = powerUps[j];
if (!powerUp.collected && bird.intersects(powerUp)) {
powerUp.collected = true;
LK.getSound('powerup').play();
if (powerUp.type === 'speed') {
speedBoostTimer = 300; // 5 seconds
createParticleEffect(powerUp.x, powerUp.y, 0xFF6B35, 8);
} else if (powerUp.type === 'invincibility') {
invincibilityTimer = 180; // 3 seconds
createParticleEffect(powerUp.x, powerUp.y, 0x4ECDC4, 8);
}
powerUp.destroy();
powerUps.splice(j, 1);
j--;
}
}
}
function gameOver() {
LK.getSound('hit').play();
LK.showGameOver();
}
function cleanupPipes() {
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
if (pipe.x < -120) {
pipe.destroy();
pipes.splice(i, 1);
}
}
}
function cleanupPowerUps() {
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.x < -60) {
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
function cleanupParticles() {
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (particle.life <= 0) {
particles.splice(i, 1);
}
}
}
function cleanupTrails() {
for (var i = trails.length - 1; i >= 0; i--) {
var trail = trails[i];
if (trail.life <= 0) {
trails.splice(i, 1);
}
}
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
} else {
bird.flap();
}
};
// Game update loop
game.update = function () {
// Update bird floating animation
bird.updateFloat();
if (!gameStarted) {
return;
}
// Start background music when game begins
if (currentMusicTrack === null) {
currentMusicTrack = 'bgmusic';
LK.playMusic('bgmusic');
}
// Calculate dynamic base speed based on score for progressive difficulty
var baseSpeed = -4 - LK.getScore() * 0.1; // Gradually increase speed with score
if (baseSpeed < -8) baseSpeed = -8; // Cap maximum speed
// Dynamic music based on game intensity
var gameIntensity = LK.getScore() + (speedBoostTimer > 0 ? 10 : 0);
if (gameIntensity >= 15 && currentMusicTrack !== 'fastmusic') {
currentMusicTrack = 'fastmusic';
LK.playMusic('fastmusic', {
fade: {
start: 0,
end: 0.8,
duration: 1000
}
});
} else if (gameIntensity < 15 && currentMusicTrack !== 'bgmusic') {
currentMusicTrack = 'bgmusic';
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Create bird trail effect
trailTimer++;
if (trailTimer >= 4) {
// Create trail every 4 frames
createTrail();
trailTimer = 0;
}
// Update combo timer
if (comboTimer > 0) {
comboTimer--;
if (comboTimer <= 0) {
resetCombo();
}
}
// Update power-up timers
if (speedBoostTimer > 0) {
speedBoostTimer--;
// Apply speed boost effect to pipes and power-ups
for (var i = 0; i < pipes.length; i++) {
pipes[i].speed = baseSpeed - 2; // Faster speed during boost
}
for (var j = 0; j < powerUps.length; j++) {
powerUps[j].speed = baseSpeed - 2;
}
ground.scrollSpeed = (baseSpeed - 2) * 0.5;
} else {
// Normal speed with progressive difficulty
for (var i = 0; i < pipes.length; i++) {
pipes[i].speed = baseSpeed;
}
for (var j = 0; j < powerUps.length; j++) {
powerUps[j].speed = baseSpeed;
}
ground.scrollSpeed = baseSpeed * 0.5;
}
if (invincibilityTimer > 0) {
invincibilityTimer--;
// Flash bird when invincible
if (invincibilityTimer % 10 < 5) {
bird.alpha = 0.5;
} else {
bird.alpha = 1.0;
}
} else {
bird.alpha = 1.0;
}
// Scroll ground for visual effect
ground.x += ground.scrollSpeed;
if (ground.x <= -2048) {
ground.x = 0;
}
// Spawn pipes
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnInterval) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= powerUpSpawnInterval) {
spawnPowerUp();
powerUpSpawnTimer = 0;
}
// Add subtle background color shift based on score
var scoreColorShift = LK.getScore() * 0.01;
var newBgColor = 0x87CEEB + Math.floor(scoreColorShift * 0x111111);
if (newBgColor !== game.backgroundColor) {
game.setBackgroundColor(newBgColor);
}
// Update speed indicator
var speedMultiplier = 1 + LK.getScore() * 0.1;
if (speedMultiplier > 3) speedMultiplier = 3;
speedTxt.setText('SPEED: ' + speedMultiplier.toFixed(1) + 'x');
// Check collisions
checkCollisions();
// Clean up off-screen elements
cleanupPipes();
cleanupPowerUps();
cleanupParticles();
cleanupTrails();
}; /****
* 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.flapPower = -12;
self.maxFallSpeed = 15;
self.maxRiseSpeed = -15;
self.flap = function () {
self.velocity = self.flapPower;
LK.getSound('flap').play();
// Rotate bird upward when flapping
tween(birdGraphics, {
rotation: -0.5
}, {
duration: 200
});
};
self.update = function () {
// Apply gravity
self.velocity += self.gravity;
// Limit velocity
if (self.velocity > self.maxFallSpeed) {
self.velocity = self.maxFallSpeed;
}
if (self.velocity < self.maxRiseSpeed) {
self.velocity = self.maxRiseSpeed;
}
// Update position
self.y += self.velocity;
// Rotate bird based on velocity
var targetRotation = self.velocity * 0.1;
if (targetRotation > 1.5) targetRotation = 1.5;
if (targetRotation < -0.5) targetRotation = -0.5;
tween(birdGraphics, {
rotation: targetRotation
}, {
duration: 100
});
};
return self;
});
var Particle = Container.expand(function (x, y, color) {
var self = Container.call(this);
var particle = self.attachAsset('speedPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
particle.tint = color;
particle.scaleX = 0.3;
particle.scaleY = 0.3;
self.x = x;
self.y = y;
self.velocityX = (Math.random() - 0.5) * 8;
self.velocityY = (Math.random() - 0.5) * 8;
self.life = 60; // 1 second at 60fps
self.update = function () {
self.x += self.velocityX;
self.y += self.velocityY;
self.life--;
// Fade out over time
particle.alpha = self.life / 60;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.speed = -4;
self.scored = false;
// Dynamic gap height that decreases with score for progressive difficulty
var gapReduction = LK.getScore() * 5; // Reduce gap by 5px per point
self.gapHeight = Math.max(250, 350 - gapReduction); // Minimum gap of 250px
// 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
});
// Extend pipes to fill entire screen height
self.topPipe.height = 2732;
self.bottomPipe.height = 2732;
self.setGapPosition = function (centerY) {
self.topPipe.y = centerY - self.gapHeight / 2;
self.bottomPipe.y = centerY + self.gapHeight / 2;
};
self.update = function () {
self.x += self.speed;
};
return self;
});
var PowerUp = Container.expand(function (type) {
var self = Container.call(this);
self.speed = -4;
self.type = type;
self.collected = false;
var powerUpGraphics;
if (type === 'speed') {
powerUpGraphics = self.attachAsset('speedPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (type === 'invincibility') {
powerUpGraphics = self.attachAsset('invincibilityPowerUp', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Add pulsing animation
self.pulseTime = 0;
// Add glow effect using tween
tween(powerUpGraphics, {
alpha: 0.6
}, {
duration: 800,
yoyo: true,
repeat: -1
});
self.update = function () {
self.x += self.speed;
// Pulsing animation
self.pulseTime += 0.2;
var scale = 1 + Math.sin(self.pulseTime) * 0.2;
powerUpGraphics.scaleX = scale;
powerUpGraphics.scaleY = scale;
};
return self;
});
var TrailNode = Container.expand(function (x, y) {
var self = Container.call(this);
var trail = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
trail.alpha = 0.3;
trail.scaleX = 0.7;
trail.scaleY = 0.7;
trail.tint = 0x88CCFF;
self.x = x;
self.y = y;
self.life = 20; // Trail lasts 20 frames
self.update = function () {
self.life--;
trail.alpha = self.life / 20 * 0.3;
if (self.life <= 0) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var bird;
var pipes = [];
var powerUps = [];
var particles = [];
var trails = [];
var ground;
var gameStarted = false;
var pipeSpawnTimer = 0;
var pipeSpawnInterval = 240; // Spawn pipe every 4 seconds at 60fps for much more spacing
var powerUpSpawnTimer = 0;
var powerUpSpawnInterval = 480; // Spawn power-up every 8 seconds to match increased spacing
var speedBoostTimer = 0;
var invincibilityTimer = 0;
var comboScore = 0;
var comboTimer = 0;
var trailTimer = 0;
var currentMusicTrack = null;
// Create score display
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// Create speed indicator
var speedTxt = new Text2('SPEED: 1x', {
size: 40,
fill: 0xFFD700
});
speedTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(speedTxt);
speedTxt.x = -20;
speedTxt.y = 120;
// Create combo display
var comboTxt = new Text2('', {
size: 50,
fill: 0xFF6B35
});
comboTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(comboTxt);
comboTxt.y = 150;
comboTxt.visible = false;
// Create ground
ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0
}));
ground.x = 0;
ground.y = 2732 - 100;
ground.width = 2048 * 3; // Make ground wider for scrolling effect
ground.scrollSpeed = -2;
// Create bird
bird = game.addChild(new Bird());
bird.x = 300;
bird.y = 1366; // Middle of screen
bird.startY = 1366;
bird.floatTime = 0;
// Add gentle floating animation before game starts
bird.updateFloat = function () {
if (!gameStarted) {
bird.floatTime += 0.1;
bird.y = bird.startY + Math.sin(bird.floatTime) * 20;
}
};
// Create instruction text
var instructionTxt = new Text2('TAP TO FLAP', {
size: 60,
fill: 0xFFFFFF
});
instructionTxt.anchor.set(0.5, 0.5);
instructionTxt.x = 1024;
instructionTxt.y = 1000;
game.addChild(instructionTxt);
function startGame() {
gameStarted = true;
instructionTxt.visible = false;
bird.flap();
}
function spawnPipe() {
var pipe = new Pipe();
pipe.x = 2048 + 60; // Start off screen
// Random gap position (avoid too high or too low)
var minGapCenter = 200;
var maxGapCenter = 2732 - 200 - 100; // Account for ground
var gapCenter = minGapCenter + Math.random() * (maxGapCenter - minGapCenter);
pipe.setGapPosition(gapCenter);
pipes.push(pipe);
game.addChild(pipe);
}
function createTrail() {
var trail = new TrailNode(bird.x, bird.y);
trails.push(trail);
game.addChild(trail);
}
function updateCombo() {
comboScore++;
comboTimer = 180; // 3 seconds
if (comboScore >= 3) {
comboTxt.setText('COMBO x' + comboScore + '!');
comboTxt.visible = true;
LK.effects.flashObject(comboTxt, 0xFF6B35, 500);
}
}
function resetCombo() {
comboScore = 0;
comboTimer = 0;
comboTxt.visible = false;
}
function spawnPowerUp() {
var types = ['speed', 'invincibility'];
var type = types[Math.floor(Math.random() * types.length)];
var powerUp = new PowerUp(type);
powerUp.x = 2048 + 20;
powerUp.y = 200 + Math.random() * (2732 - 400 - 100);
powerUps.push(powerUp);
game.addChild(powerUp);
}
function createParticleEffect(x, y, color, count) {
for (var i = 0; i < count; i++) {
var particle = new Particle(x, y, color);
particles.push(particle);
game.addChild(particle);
}
}
function checkCollisions() {
// Check ground collision
if (bird.y + 30 > ground.y) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
// Check ceiling collision
if (bird.y - 30 < 0) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
// Check pipe collisions
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
// Check if bird is in pipe's x range
if (bird.x + 30 > pipe.x - 60 && bird.x - 30 < pipe.x + 60) {
// Check collision with top pipe
if (bird.y - 22 < pipe.topPipe.y) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
// Check collision with bottom pipe
if (bird.y + 22 > pipe.bottomPipe.y) {
if (invincibilityTimer <= 0) {
gameOver();
return;
}
}
}
// Check for scoring
if (!pipe.scored && bird.x > pipe.x + 60) {
pipe.scored = true;
var basePoints = 1;
var bonusPoints = comboScore >= 3 ? comboScore : 0;
var totalPoints = basePoints + bonusPoints;
LK.setScore(LK.getScore() + totalPoints);
scoreTxt.setText(LK.getScore());
LK.getSound('score').play();
// Flash score text when scoring
LK.effects.flashObject(scoreTxt, 0xFFD700, 300);
// Update combo system
updateCombo();
// Create particles for high combos
if (comboScore >= 5) {
createParticleEffect(bird.x, bird.y, 0xFFD700, 6);
}
}
}
// Check power-up collisions
for (var j = 0; j < powerUps.length; j++) {
var powerUp = powerUps[j];
if (!powerUp.collected && bird.intersects(powerUp)) {
powerUp.collected = true;
LK.getSound('powerup').play();
if (powerUp.type === 'speed') {
speedBoostTimer = 300; // 5 seconds
createParticleEffect(powerUp.x, powerUp.y, 0xFF6B35, 8);
} else if (powerUp.type === 'invincibility') {
invincibilityTimer = 180; // 3 seconds
createParticleEffect(powerUp.x, powerUp.y, 0x4ECDC4, 8);
}
powerUp.destroy();
powerUps.splice(j, 1);
j--;
}
}
}
function gameOver() {
LK.getSound('hit').play();
LK.showGameOver();
}
function cleanupPipes() {
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
if (pipe.x < -120) {
pipe.destroy();
pipes.splice(i, 1);
}
}
}
function cleanupPowerUps() {
for (var i = powerUps.length - 1; i >= 0; i--) {
var powerUp = powerUps[i];
if (powerUp.x < -60) {
powerUp.destroy();
powerUps.splice(i, 1);
}
}
}
function cleanupParticles() {
for (var i = particles.length - 1; i >= 0; i--) {
var particle = particles[i];
if (particle.life <= 0) {
particles.splice(i, 1);
}
}
}
function cleanupTrails() {
for (var i = trails.length - 1; i >= 0; i--) {
var trail = trails[i];
if (trail.life <= 0) {
trails.splice(i, 1);
}
}
}
// Touch controls
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
} else {
bird.flap();
}
};
// Game update loop
game.update = function () {
// Update bird floating animation
bird.updateFloat();
if (!gameStarted) {
return;
}
// Start background music when game begins
if (currentMusicTrack === null) {
currentMusicTrack = 'bgmusic';
LK.playMusic('bgmusic');
}
// Calculate dynamic base speed based on score for progressive difficulty
var baseSpeed = -4 - LK.getScore() * 0.1; // Gradually increase speed with score
if (baseSpeed < -8) baseSpeed = -8; // Cap maximum speed
// Dynamic music based on game intensity
var gameIntensity = LK.getScore() + (speedBoostTimer > 0 ? 10 : 0);
if (gameIntensity >= 15 && currentMusicTrack !== 'fastmusic') {
currentMusicTrack = 'fastmusic';
LK.playMusic('fastmusic', {
fade: {
start: 0,
end: 0.8,
duration: 1000
}
});
} else if (gameIntensity < 15 && currentMusicTrack !== 'bgmusic') {
currentMusicTrack = 'bgmusic';
LK.playMusic('bgmusic', {
fade: {
start: 0,
end: 0.7,
duration: 1000
}
});
}
// Create bird trail effect
trailTimer++;
if (trailTimer >= 4) {
// Create trail every 4 frames
createTrail();
trailTimer = 0;
}
// Update combo timer
if (comboTimer > 0) {
comboTimer--;
if (comboTimer <= 0) {
resetCombo();
}
}
// Update power-up timers
if (speedBoostTimer > 0) {
speedBoostTimer--;
// Apply speed boost effect to pipes and power-ups
for (var i = 0; i < pipes.length; i++) {
pipes[i].speed = baseSpeed - 2; // Faster speed during boost
}
for (var j = 0; j < powerUps.length; j++) {
powerUps[j].speed = baseSpeed - 2;
}
ground.scrollSpeed = (baseSpeed - 2) * 0.5;
} else {
// Normal speed with progressive difficulty
for (var i = 0; i < pipes.length; i++) {
pipes[i].speed = baseSpeed;
}
for (var j = 0; j < powerUps.length; j++) {
powerUps[j].speed = baseSpeed;
}
ground.scrollSpeed = baseSpeed * 0.5;
}
if (invincibilityTimer > 0) {
invincibilityTimer--;
// Flash bird when invincible
if (invincibilityTimer % 10 < 5) {
bird.alpha = 0.5;
} else {
bird.alpha = 1.0;
}
} else {
bird.alpha = 1.0;
}
// Scroll ground for visual effect
ground.x += ground.scrollSpeed;
if (ground.x <= -2048) {
ground.x = 0;
}
// Spawn pipes
pipeSpawnTimer++;
if (pipeSpawnTimer >= pipeSpawnInterval) {
spawnPipe();
pipeSpawnTimer = 0;
}
// Spawn power-ups
powerUpSpawnTimer++;
if (powerUpSpawnTimer >= powerUpSpawnInterval) {
spawnPowerUp();
powerUpSpawnTimer = 0;
}
// Add subtle background color shift based on score
var scoreColorShift = LK.getScore() * 0.01;
var newBgColor = 0x87CEEB + Math.floor(scoreColorShift * 0x111111);
if (newBgColor !== game.backgroundColor) {
game.setBackgroundColor(newBgColor);
}
// Update speed indicator
var speedMultiplier = 1 + LK.getScore() * 0.1;
if (speedMultiplier > 3) speedMultiplier = 3;
speedTxt.setText('SPEED: ' + speedMultiplier.toFixed(1) + 'x');
// Check collisions
checkCollisions();
// Clean up off-screen elements
cleanupPipes();
cleanupPowerUps();
cleanupParticles();
cleanupTrails();
};