/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
// Bird graphics
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Add slow flapping animation
tween(birdGraphics, {
y: 10
}, {
duration: 1000,
easing: tween.easeInOutQuad,
loop: true,
yoyo: true
});
// Bird physics properties
self.velocity = 0;
self.gravity = 0.6; // Decreased gravity for less realistic falling
self.terminalVelocity = 12; // Decreased maximum falling speed
self.flapStrength = -11; // Decreased from -14 to make bird jump less dramatic
self.isDead = false;
// Flap the bird
self.flap = function () {
if (!self.isDead) {
self.velocity = self.flapStrength;
// Add a small immediate position change for less natural, more game-like movement
tween(self, {
y: self.y - 20
}, {
duration: 50,
easing: tween.easeOutQuad
});
LK.getSound('flap').play();
// Rotate bird up when flapping with more immediate rotation
tween(self, {
rotation: -0.4
}, {
duration: 150,
easing: tween.easeOutCubic // Faster rotation
});
}
};
self.die = function () {
self.isDead = true;
LK.getSound('hit').play();
LK.effects.flashObject(self, 0xFF0000, 500);
LK.effects.flashScreen(0xFF0000, 800); // Flash entire screen red
// Create text to inform player about the cycle
var cycleText = new Text2('REPEAT THE CYCLE', {
size: 120,
fill: 0xFF0000
});
cycleText.anchor.set(0.5, 0.5);
cycleText.x = 2048 / 2;
cycleText.y = 2732 / 2 - 300;
game.addChild(cycleText);
};
self.update = function () {
if (self.isDead) {
return;
}
// Apply gravity with acceleration curve
self.velocity += self.gravity;
// Apply terminal velocity - prevents bird from falling too fast
if (self.velocity > self.terminalVelocity) {
self.velocity = self.terminalVelocity;
} else if (self.velocity > 8) {
// When bird reaches certain speed, start to slow it down
self.velocity -= 0.1; // Gradually reduce velocity
}
self.y += self.velocity;
// Simpler rotation based on velocity with less dampening for arcade-style movement
var targetRotation = Math.min(0.8, Math.max(-0.4, self.velocity * 0.04));
tween(self, {
rotation: targetRotation
}, {
duration: 100,
// Faster rotation transition
easing: tween.easeOutQuad
});
// Check boundaries
if (self.y < 0) {
self.y = 0;
self.velocity = 0;
}
if (self.y > 2732) {
self.die();
// Add delay before game over to show the message
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Pipe properties
self.speed = baseSpeed;
self.scored = false;
// Create top pipe (now much taller to extend to top of screen)
var topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1.0,
height: 2000 // Much taller to ensure it reaches top of screen
});
// Create top pipe cap
var topPipeCap = self.attachAsset('pipeTop', {
anchorX: 0.5,
anchorY: 1.0,
y: -500
});
// Create bottom pipe (now much taller to extend to bottom of screen)
var bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0.0,
height: 2000,
// Much taller to ensure it reaches bottom of screen
y: 200 // Gap will be between top and bottom pipes
});
// Create bottom pipe cap
var bottomPipeCap = self.attachAsset('pipeTop', {
anchorX: 0.5,
anchorY: 0.0,
y: 200
});
// Set pipe gap
self.setGap = function (gapPosition, gapSize) {
topPipe.y = gapPosition - gapSize / 2;
topPipeCap.y = topPipe.y;
bottomPipe.y = gapPosition + gapSize / 2;
bottomPipeCap.y = bottomPipe.y;
};
self.update = function () {
// Move pipe left
self.x -= self.speed;
// Check if pipe is offscreen (adjusted for wider pipes)
if (self.x < -250) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var bird;
var pipes = [];
var isGameStarted = false;
var spawnInterval;
var score = 0;
var highScore = storage.highScore || 0;
var difficulty = 1;
var baseSpeed = 8; // Increased from 5 to make the game faster
var baseInterval = 2300; // Decreased from 2500 to create slightly closer pipes
var gameTimeElapsed = 0; // Track time elapsed in milliseconds
var timerInterval; // Interval for tracking game time
var deathTimeLimit = 320000; // 5 minutes and 20 seconds in milliseconds
// Background
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
background.scale.set(1.5); // Scale up background for zoomed effect
game.addChild(background);
// Score text
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// High score text
var highScoreTxt = new Text2('Best: 0', {
size: 80,
fill: 0xFFFFFF
});
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.setText('Best: ' + highScore);
LK.gui.top.addChild(highScoreTxt);
highScoreTxt.y = 220;
// Timer text to show countdown
var timerTxt = new Text2('5:20', {
size: 80,
fill: 0xFFFFFF
});
// Ensure style object exists
timerTxt.style = timerTxt.style || {};
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
timerTxt.y = 310;
// Initialize bird
function initBird() {
bird = new Bird();
bird.x = 500; // Position bird more to the left for better zoomed view
bird.y = 2732 / 2;
// Scale bird up for zoomed in effect
bird.scale.set(1.5);
game.addChild(bird);
}
// Create a new pipe
function spawnPipe() {
if (!isGameStarted) {
return;
}
var pipe = new Pipe();
// Position pipes further right for zoomed view
pipe.x = 2048 + 150;
// Set pipe speed based on current difficulty
pipe.speed = baseSpeed * difficulty;
// Move gap position higher (40% of screen height instead of 50%)
var gapPosition = 2732 * 0.4 + (Math.random() * 200 - 100); // Higher placement ± 100px random variation
// Fixed gap size that's comfortable to navigate through
var gapSize = 550; // Slightly larger gap for zoomed view
pipe.setGap(gapPosition, gapSize);
// Scale pipes up for zoomed in effect
pipe.scale.set(1.5);
pipes.push(pipe);
game.addChild(pipe);
}
// Start game
function startGame() {
if (isGameStarted) {
return;
}
isGameStarted = true;
score = 0;
difficulty = 1;
gameTimeElapsed = 0; // Reset game time elapsed
scoreTxt.setText(score);
// Clear any existing pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroy();
}
pipes = [];
// Reset bird position
if (bird) {
bird.destroy();
}
initBird();
// Start spawning pipes with fixed interval
spawnInterval = LK.setInterval(spawnPipe, baseInterval);
// Start timer to track game time
if (timerInterval) {
LK.clearInterval(timerInterval);
}
timerInterval = LK.setInterval(function () {
gameTimeElapsed += 100; // Increment by 100ms each tick
}, 100);
// Stop any existing music before playing new music
LK.stopMusic();
// Play background music only once
LK.playMusic('bgMusic', {
loop: false
});
// Listen for game pause/resume events to control audio
LK.on('pause', function () {
// Pause music when game is paused
LK.stopMusic();
});
LK.on('resume', function () {
// Resume music when game is resumed
LK.playMusic('bgMusic');
});
} //}1m}
// Initialize game
initBird();
highScoreTxt.setText('Best: ' + highScore);
// Game input
game.down = function (x, y, obj) {
if (!isGameStarted) {
startGame();
}
if (bird && !bird.isDead) {
bird.flap();
}
};
// Main game update
game.update = function () {
if (!isGameStarted) {
return;
}
// Update timer display
if (gameTimeElapsed < deathTimeLimit) {
var timeLeft = deathTimeLimit - gameTimeElapsed;
var minutes = Math.floor(timeLeft / 60000);
var seconds = Math.floor(timeLeft % 60000 / 1000);
timerTxt.setText(minutes + ':' + (seconds < 10 ? '0' + seconds : seconds));
// Change color when time is running out (last 30 seconds)
if (timeLeft <= 30000) {
timerTxt.style.fill = 0xFF0000;
// Make text blink when time is really low (last 10 seconds)
if (timeLeft <= 10000) {
timerTxt.alpha = Math.sin(gameTimeElapsed / 200) * 0.5 + 0.5;
}
}
}
// Check if time limit has been reached (5 minutes and 5 seconds)
if (gameTimeElapsed >= deathTimeLimit && bird && !bird.isDead) {
// Brutally kill the bird after time limit
LK.clearInterval(timerInterval); // Stop the timer
timerTxt.setText('0:00');
timerTxt.style.fill = 0xFF0000;
timerTxt.alpha = 1;
// Create brutal death effect
LK.effects.flashScreen(0xFF0000, 800); // Flash screen red
LK.getSound('hit').play(); // Play hit sound
// Make bird explode with dramatic scale and color changes
tween(bird, {
rotation: Math.PI * 4,
// Spin multiple times
scaleX: 3,
scaleY: 3,
alpha: 0 // Fade out bird
}, {
duration: 1000,
easing: tween.easeInBack,
onFinish: function onFinish() {
// Show game over after animation finishes
LK.showGameOver();
}
});
// Set bird as dead to prevent further updates
bird.isDead = true;
// Create text to inform player
var deathText = new Text2('REPEAT THE CYCLE', {
size: 120,
fill: 0xFF0000
});
deathText.anchor.set(0.5, 0.5);
deathText.x = 2048 / 2;
deathText.y = 2732 / 2 - 300;
game.addChild(deathText);
return; // Skip the rest of the update
}
// Update all pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
// Check for scoring (when bird passes pipe)
if (!pipe.scored && bird && bird.x > pipe.x) {
pipe.scored = true;
score += 1;
scoreTxt.setText(score);
LK.setScore(score);
LK.getSound('score').play();
// Increase difficulty every 5 points
if (score % 5 === 0) {
difficulty += 0.2;
// Update all existing pipes to the new speed
for (var k = 0; k < pipes.length; k++) {
pipes[k].speed = baseSpeed * difficulty;
}
// Clear and reset spawn interval with fixed timing
LK.clearInterval(spawnInterval);
spawnInterval = LK.setInterval(spawnPipe, baseInterval);
}
// Update high score if needed
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('Best: ' + highScore);
}
}
// Check for collision with bird
if (bird && !bird.isDead) {
// Get pipe children for collision checks
var pipeChildren = pipe.children;
for (var j = 0; j < pipeChildren.length; j++) {
if (bird.intersects(pipeChildren[j])) {
bird.die();
// Add delay before game over to show the message
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
break;
}
}
}
// Remove pipe if it's off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0
});
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
// Bird graphics
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Add slow flapping animation
tween(birdGraphics, {
y: 10
}, {
duration: 1000,
easing: tween.easeInOutQuad,
loop: true,
yoyo: true
});
// Bird physics properties
self.velocity = 0;
self.gravity = 0.6; // Decreased gravity for less realistic falling
self.terminalVelocity = 12; // Decreased maximum falling speed
self.flapStrength = -11; // Decreased from -14 to make bird jump less dramatic
self.isDead = false;
// Flap the bird
self.flap = function () {
if (!self.isDead) {
self.velocity = self.flapStrength;
// Add a small immediate position change for less natural, more game-like movement
tween(self, {
y: self.y - 20
}, {
duration: 50,
easing: tween.easeOutQuad
});
LK.getSound('flap').play();
// Rotate bird up when flapping with more immediate rotation
tween(self, {
rotation: -0.4
}, {
duration: 150,
easing: tween.easeOutCubic // Faster rotation
});
}
};
self.die = function () {
self.isDead = true;
LK.getSound('hit').play();
LK.effects.flashObject(self, 0xFF0000, 500);
LK.effects.flashScreen(0xFF0000, 800); // Flash entire screen red
// Create text to inform player about the cycle
var cycleText = new Text2('REPEAT THE CYCLE', {
size: 120,
fill: 0xFF0000
});
cycleText.anchor.set(0.5, 0.5);
cycleText.x = 2048 / 2;
cycleText.y = 2732 / 2 - 300;
game.addChild(cycleText);
};
self.update = function () {
if (self.isDead) {
return;
}
// Apply gravity with acceleration curve
self.velocity += self.gravity;
// Apply terminal velocity - prevents bird from falling too fast
if (self.velocity > self.terminalVelocity) {
self.velocity = self.terminalVelocity;
} else if (self.velocity > 8) {
// When bird reaches certain speed, start to slow it down
self.velocity -= 0.1; // Gradually reduce velocity
}
self.y += self.velocity;
// Simpler rotation based on velocity with less dampening for arcade-style movement
var targetRotation = Math.min(0.8, Math.max(-0.4, self.velocity * 0.04));
tween(self, {
rotation: targetRotation
}, {
duration: 100,
// Faster rotation transition
easing: tween.easeOutQuad
});
// Check boundaries
if (self.y < 0) {
self.y = 0;
self.velocity = 0;
}
if (self.y > 2732) {
self.die();
// Add delay before game over to show the message
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Pipe properties
self.speed = baseSpeed;
self.scored = false;
// Create top pipe (now much taller to extend to top of screen)
var topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1.0,
height: 2000 // Much taller to ensure it reaches top of screen
});
// Create top pipe cap
var topPipeCap = self.attachAsset('pipeTop', {
anchorX: 0.5,
anchorY: 1.0,
y: -500
});
// Create bottom pipe (now much taller to extend to bottom of screen)
var bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0.0,
height: 2000,
// Much taller to ensure it reaches bottom of screen
y: 200 // Gap will be between top and bottom pipes
});
// Create bottom pipe cap
var bottomPipeCap = self.attachAsset('pipeTop', {
anchorX: 0.5,
anchorY: 0.0,
y: 200
});
// Set pipe gap
self.setGap = function (gapPosition, gapSize) {
topPipe.y = gapPosition - gapSize / 2;
topPipeCap.y = topPipe.y;
bottomPipe.y = gapPosition + gapSize / 2;
bottomPipeCap.y = bottomPipe.y;
};
self.update = function () {
// Move pipe left
self.x -= self.speed;
// Check if pipe is offscreen (adjusted for wider pipes)
if (self.x < -250) {
self.destroy();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state variables
var bird;
var pipes = [];
var isGameStarted = false;
var spawnInterval;
var score = 0;
var highScore = storage.highScore || 0;
var difficulty = 1;
var baseSpeed = 8; // Increased from 5 to make the game faster
var baseInterval = 2300; // Decreased from 2500 to create slightly closer pipes
var gameTimeElapsed = 0; // Track time elapsed in milliseconds
var timerInterval; // Interval for tracking game time
var deathTimeLimit = 320000; // 5 minutes and 20 seconds in milliseconds
// Background
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
background.scale.set(1.5); // Scale up background for zoomed effect
game.addChild(background);
// Score text
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// High score text
var highScoreTxt = new Text2('Best: 0', {
size: 80,
fill: 0xFFFFFF
});
highScoreTxt.anchor.set(0.5, 0);
highScoreTxt.setText('Best: ' + highScore);
LK.gui.top.addChild(highScoreTxt);
highScoreTxt.y = 220;
// Timer text to show countdown
var timerTxt = new Text2('5:20', {
size: 80,
fill: 0xFFFFFF
});
// Ensure style object exists
timerTxt.style = timerTxt.style || {};
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
timerTxt.y = 310;
// Initialize bird
function initBird() {
bird = new Bird();
bird.x = 500; // Position bird more to the left for better zoomed view
bird.y = 2732 / 2;
// Scale bird up for zoomed in effect
bird.scale.set(1.5);
game.addChild(bird);
}
// Create a new pipe
function spawnPipe() {
if (!isGameStarted) {
return;
}
var pipe = new Pipe();
// Position pipes further right for zoomed view
pipe.x = 2048 + 150;
// Set pipe speed based on current difficulty
pipe.speed = baseSpeed * difficulty;
// Move gap position higher (40% of screen height instead of 50%)
var gapPosition = 2732 * 0.4 + (Math.random() * 200 - 100); // Higher placement ± 100px random variation
// Fixed gap size that's comfortable to navigate through
var gapSize = 550; // Slightly larger gap for zoomed view
pipe.setGap(gapPosition, gapSize);
// Scale pipes up for zoomed in effect
pipe.scale.set(1.5);
pipes.push(pipe);
game.addChild(pipe);
}
// Start game
function startGame() {
if (isGameStarted) {
return;
}
isGameStarted = true;
score = 0;
difficulty = 1;
gameTimeElapsed = 0; // Reset game time elapsed
scoreTxt.setText(score);
// Clear any existing pipes
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].destroy();
}
pipes = [];
// Reset bird position
if (bird) {
bird.destroy();
}
initBird();
// Start spawning pipes with fixed interval
spawnInterval = LK.setInterval(spawnPipe, baseInterval);
// Start timer to track game time
if (timerInterval) {
LK.clearInterval(timerInterval);
}
timerInterval = LK.setInterval(function () {
gameTimeElapsed += 100; // Increment by 100ms each tick
}, 100);
// Stop any existing music before playing new music
LK.stopMusic();
// Play background music only once
LK.playMusic('bgMusic', {
loop: false
});
// Listen for game pause/resume events to control audio
LK.on('pause', function () {
// Pause music when game is paused
LK.stopMusic();
});
LK.on('resume', function () {
// Resume music when game is resumed
LK.playMusic('bgMusic');
});
} //}1m}
// Initialize game
initBird();
highScoreTxt.setText('Best: ' + highScore);
// Game input
game.down = function (x, y, obj) {
if (!isGameStarted) {
startGame();
}
if (bird && !bird.isDead) {
bird.flap();
}
};
// Main game update
game.update = function () {
if (!isGameStarted) {
return;
}
// Update timer display
if (gameTimeElapsed < deathTimeLimit) {
var timeLeft = deathTimeLimit - gameTimeElapsed;
var minutes = Math.floor(timeLeft / 60000);
var seconds = Math.floor(timeLeft % 60000 / 1000);
timerTxt.setText(minutes + ':' + (seconds < 10 ? '0' + seconds : seconds));
// Change color when time is running out (last 30 seconds)
if (timeLeft <= 30000) {
timerTxt.style.fill = 0xFF0000;
// Make text blink when time is really low (last 10 seconds)
if (timeLeft <= 10000) {
timerTxt.alpha = Math.sin(gameTimeElapsed / 200) * 0.5 + 0.5;
}
}
}
// Check if time limit has been reached (5 minutes and 5 seconds)
if (gameTimeElapsed >= deathTimeLimit && bird && !bird.isDead) {
// Brutally kill the bird after time limit
LK.clearInterval(timerInterval); // Stop the timer
timerTxt.setText('0:00');
timerTxt.style.fill = 0xFF0000;
timerTxt.alpha = 1;
// Create brutal death effect
LK.effects.flashScreen(0xFF0000, 800); // Flash screen red
LK.getSound('hit').play(); // Play hit sound
// Make bird explode with dramatic scale and color changes
tween(bird, {
rotation: Math.PI * 4,
// Spin multiple times
scaleX: 3,
scaleY: 3,
alpha: 0 // Fade out bird
}, {
duration: 1000,
easing: tween.easeInBack,
onFinish: function onFinish() {
// Show game over after animation finishes
LK.showGameOver();
}
});
// Set bird as dead to prevent further updates
bird.isDead = true;
// Create text to inform player
var deathText = new Text2('REPEAT THE CYCLE', {
size: 120,
fill: 0xFF0000
});
deathText.anchor.set(0.5, 0.5);
deathText.x = 2048 / 2;
deathText.y = 2732 / 2 - 300;
game.addChild(deathText);
return; // Skip the rest of the update
}
// Update all pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
// Check for scoring (when bird passes pipe)
if (!pipe.scored && bird && bird.x > pipe.x) {
pipe.scored = true;
score += 1;
scoreTxt.setText(score);
LK.setScore(score);
LK.getSound('score').play();
// Increase difficulty every 5 points
if (score % 5 === 0) {
difficulty += 0.2;
// Update all existing pipes to the new speed
for (var k = 0; k < pipes.length; k++) {
pipes[k].speed = baseSpeed * difficulty;
}
// Clear and reset spawn interval with fixed timing
LK.clearInterval(spawnInterval);
spawnInterval = LK.setInterval(spawnPipe, baseInterval);
}
// Update high score if needed
if (score > highScore) {
highScore = score;
storage.highScore = highScore;
highScoreTxt.setText('Best: ' + highScore);
}
}
// Check for collision with bird
if (bird && !bird.isDead) {
// Get pipe children for collision checks
var pipeChildren = pipe.children;
for (var j = 0; j < pipeChildren.length; j++) {
if (bird.intersects(pipeChildren[j])) {
bird.die();
// Add delay before game over to show the message
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
break;
}
}
}
// Remove pipe if it's off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
}
}
};