/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.xSpeed = 10.9375;
self.ySpeed = -20;
self.gravity = 1;
self.lift = -15;
self.flap = function () {
self.ySpeed = self.lift * 1.5;
LK.getSound('flap').play();
};
self._update_migrated = function () {
if (game.isMouseDown) {
self.ySpeed += self.gravity / 3;
} else {
self.ySpeed += self.gravity;
}
self.y += self.ySpeed;
self.x += self.xSpeed;
if (self.y <= 0 || self.y >= 2732) {
self.speed = -self.speed;
}
var targetRotation = Math.atan2(self.ySpeed, self.xSpeed * self.scale.x) / 2;
birdGraphics.rotation += (targetRotation - birdGraphics.rotation) / 10;
};
self.flip = function () {
self.scale.x *= -1;
};
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.speed = 3;
// Start rotation animation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
if (!self.collected) {
tween(coinGraphics, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.linear,
onFinish: arguments.callee
});
}
}
});
self._move_migrated = function (speed) {
self.y += speed;
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
LK.getSound('coinCollect').play();
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var Leaderboard = Container.expand(function () {
var self = Container.call(this);
// Leaderboard background
var leaderBg = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25,
scaleY: 1
});
leaderBg.alpha = 0.9;
leaderBg.tint = 0x2196F3;
// Title
var titleText = new Text2('LEADERBOARD', {
size: 150,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -500;
self.addChild(titleText);
// Get high scores from storage
var highScores = storage.highScores || [0, 0, 0, 0, 0];
// Display top 5 scores
for (var i = 0; i < 5; i++) {
var scoreText = new Text2(i + 1 + '. ' + highScores[i], {
size: 100,
fill: '#ffd700',
font: 'Arial Black',
align: 'center'
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 0;
scoreText.y = -300 + i * 120;
self.addChild(scoreText);
}
// Back button
var backButton = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
});
backButton.tint = 0xFF5722;
backButton.y = 400;
var backText = new Text2('BACK', {
size: 120,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
backText.anchor.set(0.5, 0.5);
backText.x = 0;
backText.y = 400;
self.addChild(backText);
self.down = function (x, y, obj) {
// Use the x, y coordinates directly instead of trying to convert from obj
// Check back button click (button is at y=400, height is about 100)
if (y > 350 && y < 450) {
game.showMenu();
}
};
return self;
});
var Menu = Container.expand(function () {
var self = Container.call(this);
// Menu background
var menuBg = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25,
scaleY: 1
});
menuBg.alpha = 0.8;
menuBg.tint = 0x87CEEB;
// Title
var titleText = new Text2('FLAPPY BIRD', {
size: 200,
fill: '#ff6b35',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 10,
dropShadowDistance: 5,
align: 'center'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -400;
self.addChild(titleText);
// Play button
var playButton = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
});
playButton.tint = 0x4CAF50;
playButton.y = -100;
var playText = new Text2('PLAY', {
size: 120,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
playText.anchor.set(0.5, 0.5);
playText.x = 0;
playText.y = -100;
self.addChild(playText);
// Leaderboard button
var leaderButton = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
});
leaderButton.tint = 0x2196F3;
leaderButton.y = 100;
var leaderText = new Text2('LEADERBOARD', {
size: 100,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
leaderText.anchor.set(0.5, 0.5);
leaderText.x = 0;
leaderText.y = 100;
self.addChild(leaderText);
// Best score display
var bestScore = storage.bestScore || 0;
var bestScoreText = new Text2('Best Score: ' + bestScore, {
size: 80,
fill: '#ffd700',
font: 'Arial Black',
align: 'center'
});
bestScoreText.anchor.set(0.5, 0.5);
bestScoreText.x = 0;
bestScoreText.y = 300;
self.addChild(bestScoreText);
self.down = function (x, y, obj) {
// Use the x, y coordinates directly instead of trying to convert from obj
// Check play button click (button is at y=-100, height is about 100)
if (y > -150 && y < -50) {
game.startGame();
}
// Check leaderboard button click (button is at y=100, height is about 100)
if (y > 50 && y < 150) {
game.showLeaderboard();
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleShadow = self.attachAsset('obstacleShadow', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleShadow.rotation = Math.PI / 4;
var obstacleShadow2 = self.attachAsset('obstacleShadow2', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleShadow2.rotation = Math.PI / 4;
obstacleShadow2.y = -7;
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleGraphics.rotation = Math.PI / 4;
self.speed = 5;
self._move_migrated = function (speed) {
self.y += speed;
};
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var tutorialTextWhite = new Text2('Tap to Flap\nHold to Float', {
size: 150,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
tutorialTextWhite.anchor.set(.5, 1);
tutorialTextWhite.x = -4;
tutorialTextWhite.y = -62;
LK.gui.bottom.addChild(tutorialTextWhite);
var tutorialText = new Text2('Tap to Flap\nHold to Float', {
size: 150,
fill: '#ff6b35',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 8,
dropShadowDistance: 4,
dropShadowAngle: 0,
align: 'center'
});
tutorialText.anchor.set(.5, 1);
tutorialText.y = -50;
LK.gui.bottom.addChild(tutorialText);
game.score = 0;
game.coinsCollected = 0;
game.lives = 1;
game.obstacleSpeed = 5;
game.obstacleSpeedIncrease = 0.005;
game.gameState = 'menu'; // 'menu', 'playing', 'leaderboard'
game.menu = null;
game.leaderboard = null;
game.checkObstacleCollision = function (obstacles) {
for (var i = 0; i < obstacles.length; i++) {
obstacles[i]._move_migrated();
var dist = Math.sqrt(Math.pow(bird.x - obstacles[i].x, 2) + Math.pow(bird.y - obstacles[i].y, 2));
if (dist < 280) {
game.lives--;
livesText.setText('Lives: ' + game.lives);
livesText2.setText('Lives: ' + game.lives);
if (game.lives <= 0) {
game.saveScore();
LK.setScore(game.score);
LK.getSound('gameOverJingle').play();
LK.showGameOver();
} else {
// Flash red to indicate life lost
LK.effects.flashScreen(0xff0000, 500);
// Reset bird position
bird.x = 1024;
bird.y = 1366;
bird.ySpeed = 0;
}
}
}
};
game.saveScore = function () {
// Update best score
var bestScore = storage.bestScore || 0;
if (game.score > bestScore) {
storage.bestScore = game.score;
}
// Update high scores list
var highScores = storage.highScores || [0, 0, 0, 0, 0];
highScores.push(game.score);
highScores.sort(function (a, b) {
return b - a;
});
highScores = highScores.slice(0, 5);
storage.highScores = highScores;
};
game.showMenu = function () {
game.gameState = 'menu';
if (game.leaderboard) {
game.leaderboard.destroy();
game.leaderboard = null;
}
if (!game.menu) {
game.menu = game.addChild(new Menu());
game.menu.x = 1024;
game.menu.y = 1366;
}
// Hide game UI elements
tutorialText.visible = false;
tutorialTextWhite.visible = false;
scoreText.visible = false;
scoreText2.visible = false;
coinText.visible = false;
coinText2.visible = false;
livesText.visible = false;
livesText2.visible = false;
// Hide game objects
bird.visible = false;
leftWall.visible = false;
rightWall.visible = false;
};
game.showLeaderboard = function () {
game.gameState = 'leaderboard';
if (game.menu) {
game.menu.destroy();
game.menu = null;
}
if (!game.leaderboard) {
game.leaderboard = game.addChild(new Leaderboard());
game.leaderboard.x = 1024;
game.leaderboard.y = 1366;
}
};
game.startGame = function () {
game.gameState = 'playing';
if (game.menu) {
game.menu.destroy();
game.menu = null;
}
if (game.leaderboard) {
game.leaderboard.destroy();
game.leaderboard = null;
}
// Reset game state
game.score = 0;
game.coinsCollected = 0;
game.lives = 1;
game.obstacleSpeed = 5;
// Show game UI elements
tutorialText.visible = true;
tutorialTextWhite.visible = true;
scoreText.visible = true;
scoreText2.visible = true;
coinText.visible = true;
coinText2.visible = true;
livesText.visible = true;
livesText2.visible = true;
// Show and reset game objects
bird.visible = true;
bird.x = 1024;
bird.y = 1366;
bird.ySpeed = 0;
leftWall.visible = true;
rightWall.visible = true;
// Clear obstacles and coins
for (var i = leftObstacles.length - 1; i >= 0; i--) {
leftObstacles[i].destroy();
leftObstacles.splice(i, 1);
}
for (var i = rightObstacles.length - 1; i >= 0; i--) {
rightObstacles[i].destroy();
rightObstacles.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
// Update UI
scoreText.setText('0');
scoreText2.setText('0');
coinText.setText('Coins: 0');
coinText2.setText('Coins: 0');
livesText.setText('Lives: 1');
livesText2.setText('Lives: 1');
};
game.setBackgroundColor(0x87CEEB);
var scoreText = new Text2('0', {
size: 150,
fill: '#ff6b35',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 8,
dropShadowDistance: 4,
dropShadowAngle: 0
});
scoreText.anchor.set(.5, 0);
LK.gui.top.addChild(scoreText);
var scoreText2 = new Text2('0', {
size: 150,
fill: '#ffffff',
font: 'Arial Black'
});
scoreText2.anchor.set(.5, 0);
scoreText2.x = -4;
scoreText2.y = -5;
LK.gui.top.addChild(scoreText2);
LK.gui.top.addChild(scoreText);
var coinText = new Text2('Coins: 0', {
size: 80,
fill: '#ffd700',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 5,
dropShadowDistance: 2,
dropShadowAngle: 0
});
coinText.anchor.set(1, 0);
coinText.x = -20;
coinText.y = 20;
LK.gui.topRight.addChild(coinText);
var coinText2 = new Text2('Coins: 0', {
size: 80,
fill: '#ffffff',
font: 'Arial Black'
});
coinText2.anchor.set(1, 0);
coinText2.x = -24;
coinText2.y = 15;
LK.gui.topRight.addChild(coinText2);
LK.gui.topRight.addChild(coinText);
var livesText = new Text2('Lives: 1', {
size: 80,
fill: '#ff4444',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#aa0000',
dropShadowBlur: 5,
dropShadowDistance: 2,
dropShadowAngle: 0
});
livesText.anchor.set(1, 0);
livesText.x = -20;
livesText.y = 120;
LK.gui.topRight.addChild(livesText);
var livesText2 = new Text2('Lives: 1', {
size: 80,
fill: '#ffffff',
font: 'Arial Black'
});
livesText2.anchor.set(1, 0);
livesText2.x = -24;
livesText2.y = 115;
LK.gui.topRight.addChild(livesText2);
LK.gui.topRight.addChild(livesText);
var bird = game.addChild(new Bird());
var leftWall = game.addChild(new Wall());
leftWall.x = 0;
leftWall.y = 1366;
var rightWall = game.addChild(new Wall());
rightWall.x = 2048;
rightWall.y = 1366;
var leftObstacles = [],
rightObstacles = [],
coins = [];
var coinSpawnTime = 120;
var coinSpawnCounter = 0;
var obstacleSpawnRandomness = 180;
var obstacleSpawnRandomnessDecrease = 0.025 * (2 / 3);
var obstacleSpawnY = -500;
var leftObstacleSpawnTime = Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
var rightObstacleSpawnTime = Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
bird.x = 1024;
bird.y = 1366;
game.isMouseDown = false;
// Start with menu
game.showMenu();
game.down = function (x, y, obj) {
if (game.gameState === 'playing') {
bird.flap();
game.isMouseDown = true;
}
};
game.up = function (x, y, obj) {
if (game.gameState === 'playing') {
game.isMouseDown = false;
}
};
game.update = function () {
if (game.gameState !== 'playing') {
return;
}
bird._update_migrated();
if (game.score > 2) {
tutorialText.y += 5;
tutorialTextWhite.y += 5;
}
scoreText.setText(game.score);
scoreText2.setText(game.score);
game.obstacleSpeed += game.obstacleSpeedIncrease;
obstacleSpawnRandomness -= obstacleSpawnRandomnessDecrease;
if (obstacleSpawnRandomness < 40) {
obstacleSpawnRandomness = 40;
}
if (LK.ticks >= leftObstacleSpawnTime) {
var newObstacle = game.addChildAt(new Obstacle(), 0);
newObstacle.x = 0;
newObstacle.y = obstacleSpawnY;
leftObstacles.push(newObstacle);
leftObstacleSpawnTime += Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
}
if (LK.ticks >= rightObstacleSpawnTime) {
var newObstacle = game.addChildAt(new Obstacle(), 0);
newObstacle.x = 2048;
newObstacle.y = -newObstacle.height;
rightObstacles.push(newObstacle);
rightObstacleSpawnTime += Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
}
if (bird.intersects(leftWall) && bird.xSpeed < 0 || bird.intersects(rightWall) && bird.xSpeed > 0) {
bird.xSpeed = -bird.xSpeed;
bird.flip();
game.score++;
LK.setScore(game.score);
LK.getSound('bounce').play();
}
for (var i = leftObstacles.length - 1; i >= 0; i--) {
leftObstacles[i]._move_migrated(game.obstacleSpeed);
if (leftObstacles[i].y > 3232) {
leftObstacles[i].destroy();
leftObstacles.splice(i, 1);
}
}
for (var i = rightObstacles.length - 1; i >= 0; i--) {
rightObstacles[i]._move_migrated(game.obstacleSpeed);
if (rightObstacles[i].y > 3232) {
rightObstacles[i].destroy();
rightObstacles.splice(i, 1);
}
}
// Spawn coins
coinSpawnCounter++;
if (coinSpawnCounter >= coinSpawnTime) {
var newCoin = game.addChild(new Coin());
newCoin.x = Math.random() * 1500 + 300; // Random X between walls
newCoin.y = -100;
coins.push(newCoin);
coinSpawnCounter = 0;
coinSpawnTime = Math.random() * 180 + 60; // Random spawn time
}
// Move and check coin collection
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.collected) {
coin._move_migrated(game.obstacleSpeed);
// Check collision with bird
if (bird.intersects(coin)) {
coin.collect();
game.coinsCollected++;
game.score += 3; // Give bonus points for coins
LK.setScore(game.score);
scoreText.setText(game.score);
scoreText2.setText(game.score);
coinText.setText('Coins: ' + game.coinsCollected);
coinText2.setText('Coins: ' + game.coinsCollected);
// Check for extra life every 10 coins (maximum 3 lives)
if (game.coinsCollected % 10 === 0 && game.lives < 3) {
game.lives++;
livesText.setText('Lives: ' + game.lives);
livesText2.setText('Lives: ' + game.lives);
// Flash the lives text to indicate extra life gained
tween(livesText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(livesText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
coins.splice(i, 1);
continue;
}
// Remove coins that are off screen
if (coin.y > 3000) {
coin.destroy();
coins.splice(i, 1);
}
}
}
game.checkObstacleCollision(leftObstacles);
game.checkObstacleCollision(rightObstacles);
if (bird.y < 0 || bird.y > 2732) {
game.lives--;
livesText.setText('Lives: ' + game.lives);
livesText2.setText('Lives: ' + game.lives);
if (game.lives <= 0) {
game.saveScore();
LK.setScore(game.score);
LK.getSound('gameOverJingle').play();
LK.showGameOver();
} else {
// Flash red to indicate life lost
LK.effects.flashScreen(0xff0000, 500);
// Reset bird position
bird.x = 1024;
bird.y = 1366;
bird.ySpeed = 0;
}
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.xSpeed = 10.9375;
self.ySpeed = -20;
self.gravity = 1;
self.lift = -15;
self.flap = function () {
self.ySpeed = self.lift * 1.5;
LK.getSound('flap').play();
};
self._update_migrated = function () {
if (game.isMouseDown) {
self.ySpeed += self.gravity / 3;
} else {
self.ySpeed += self.gravity;
}
self.y += self.ySpeed;
self.x += self.xSpeed;
if (self.y <= 0 || self.y >= 2732) {
self.speed = -self.speed;
}
var targetRotation = Math.atan2(self.ySpeed, self.xSpeed * self.scale.x) / 2;
birdGraphics.rotation += (targetRotation - birdGraphics.rotation) / 10;
};
self.flip = function () {
self.scale.x *= -1;
};
});
var Coin = Container.expand(function () {
var self = Container.call(this);
var coinGraphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.speed = 3;
// Start rotation animation
tween(coinGraphics, {
rotation: Math.PI * 2
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
if (!self.collected) {
tween(coinGraphics, {
rotation: Math.PI * 4
}, {
duration: 2000,
easing: tween.linear,
onFinish: arguments.callee
});
}
}
});
self._move_migrated = function (speed) {
self.y += speed;
};
self.collect = function () {
if (!self.collected) {
self.collected = true;
LK.getSound('coinCollect').play();
tween(self, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
}
};
return self;
});
var Leaderboard = Container.expand(function () {
var self = Container.call(this);
// Leaderboard background
var leaderBg = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25,
scaleY: 1
});
leaderBg.alpha = 0.9;
leaderBg.tint = 0x2196F3;
// Title
var titleText = new Text2('LEADERBOARD', {
size: 150,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -500;
self.addChild(titleText);
// Get high scores from storage
var highScores = storage.highScores || [0, 0, 0, 0, 0];
// Display top 5 scores
for (var i = 0; i < 5; i++) {
var scoreText = new Text2(i + 1 + '. ' + highScores[i], {
size: 100,
fill: '#ffd700',
font: 'Arial Black',
align: 'center'
});
scoreText.anchor.set(0.5, 0.5);
scoreText.x = 0;
scoreText.y = -300 + i * 120;
self.addChild(scoreText);
}
// Back button
var backButton = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
});
backButton.tint = 0xFF5722;
backButton.y = 400;
var backText = new Text2('BACK', {
size: 120,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
backText.anchor.set(0.5, 0.5);
backText.x = 0;
backText.y = 400;
self.addChild(backText);
self.down = function (x, y, obj) {
// Use the x, y coordinates directly instead of trying to convert from obj
// Check back button click (button is at y=400, height is about 100)
if (y > 350 && y < 450) {
game.showMenu();
}
};
return self;
});
var Menu = Container.expand(function () {
var self = Container.call(this);
// Menu background
var menuBg = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 25,
scaleY: 1
});
menuBg.alpha = 0.8;
menuBg.tint = 0x87CEEB;
// Title
var titleText = new Text2('FLAPPY BIRD', {
size: 200,
fill: '#ff6b35',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 10,
dropShadowDistance: 5,
align: 'center'
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 0;
titleText.y = -400;
self.addChild(titleText);
// Play button
var playButton = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
});
playButton.tint = 0x4CAF50;
playButton.y = -100;
var playText = new Text2('PLAY', {
size: 120,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
playText.anchor.set(0.5, 0.5);
playText.x = 0;
playText.y = -100;
self.addChild(playText);
// Leaderboard button
var leaderButton = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 1
});
leaderButton.tint = 0x2196F3;
leaderButton.y = 100;
var leaderText = new Text2('LEADERBOARD', {
size: 100,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
leaderText.anchor.set(0.5, 0.5);
leaderText.x = 0;
leaderText.y = 100;
self.addChild(leaderText);
// Best score display
var bestScore = storage.bestScore || 0;
var bestScoreText = new Text2('Best Score: ' + bestScore, {
size: 80,
fill: '#ffd700',
font: 'Arial Black',
align: 'center'
});
bestScoreText.anchor.set(0.5, 0.5);
bestScoreText.x = 0;
bestScoreText.y = 300;
self.addChild(bestScoreText);
self.down = function (x, y, obj) {
// Use the x, y coordinates directly instead of trying to convert from obj
// Check play button click (button is at y=-100, height is about 100)
if (y > -150 && y < -50) {
game.startGame();
}
// Check leaderboard button click (button is at y=100, height is about 100)
if (y > 50 && y < 150) {
game.showLeaderboard();
}
};
return self;
});
var Obstacle = Container.expand(function () {
var self = Container.call(this);
var obstacleShadow = self.attachAsset('obstacleShadow', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleShadow.rotation = Math.PI / 4;
var obstacleShadow2 = self.attachAsset('obstacleShadow2', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleShadow2.rotation = Math.PI / 4;
obstacleShadow2.y = -7;
var obstacleGraphics = self.attachAsset('obstacle', {
anchorX: 0.5,
anchorY: 0.5
});
obstacleGraphics.rotation = Math.PI / 4;
self.speed = 5;
self._move_migrated = function (speed) {
self.y += speed;
};
});
var Wall = Container.expand(function () {
var self = Container.call(this);
var wallGraphics = self.attachAsset('wall', {
anchorX: 0.5,
anchorY: 0.5
});
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var tutorialTextWhite = new Text2('Tap to Flap\nHold to Float', {
size: 150,
fill: '#ffffff',
font: 'Arial Black',
align: 'center'
});
tutorialTextWhite.anchor.set(.5, 1);
tutorialTextWhite.x = -4;
tutorialTextWhite.y = -62;
LK.gui.bottom.addChild(tutorialTextWhite);
var tutorialText = new Text2('Tap to Flap\nHold to Float', {
size: 150,
fill: '#ff6b35',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 8,
dropShadowDistance: 4,
dropShadowAngle: 0,
align: 'center'
});
tutorialText.anchor.set(.5, 1);
tutorialText.y = -50;
LK.gui.bottom.addChild(tutorialText);
game.score = 0;
game.coinsCollected = 0;
game.lives = 1;
game.obstacleSpeed = 5;
game.obstacleSpeedIncrease = 0.005;
game.gameState = 'menu'; // 'menu', 'playing', 'leaderboard'
game.menu = null;
game.leaderboard = null;
game.checkObstacleCollision = function (obstacles) {
for (var i = 0; i < obstacles.length; i++) {
obstacles[i]._move_migrated();
var dist = Math.sqrt(Math.pow(bird.x - obstacles[i].x, 2) + Math.pow(bird.y - obstacles[i].y, 2));
if (dist < 280) {
game.lives--;
livesText.setText('Lives: ' + game.lives);
livesText2.setText('Lives: ' + game.lives);
if (game.lives <= 0) {
game.saveScore();
LK.setScore(game.score);
LK.getSound('gameOverJingle').play();
LK.showGameOver();
} else {
// Flash red to indicate life lost
LK.effects.flashScreen(0xff0000, 500);
// Reset bird position
bird.x = 1024;
bird.y = 1366;
bird.ySpeed = 0;
}
}
}
};
game.saveScore = function () {
// Update best score
var bestScore = storage.bestScore || 0;
if (game.score > bestScore) {
storage.bestScore = game.score;
}
// Update high scores list
var highScores = storage.highScores || [0, 0, 0, 0, 0];
highScores.push(game.score);
highScores.sort(function (a, b) {
return b - a;
});
highScores = highScores.slice(0, 5);
storage.highScores = highScores;
};
game.showMenu = function () {
game.gameState = 'menu';
if (game.leaderboard) {
game.leaderboard.destroy();
game.leaderboard = null;
}
if (!game.menu) {
game.menu = game.addChild(new Menu());
game.menu.x = 1024;
game.menu.y = 1366;
}
// Hide game UI elements
tutorialText.visible = false;
tutorialTextWhite.visible = false;
scoreText.visible = false;
scoreText2.visible = false;
coinText.visible = false;
coinText2.visible = false;
livesText.visible = false;
livesText2.visible = false;
// Hide game objects
bird.visible = false;
leftWall.visible = false;
rightWall.visible = false;
};
game.showLeaderboard = function () {
game.gameState = 'leaderboard';
if (game.menu) {
game.menu.destroy();
game.menu = null;
}
if (!game.leaderboard) {
game.leaderboard = game.addChild(new Leaderboard());
game.leaderboard.x = 1024;
game.leaderboard.y = 1366;
}
};
game.startGame = function () {
game.gameState = 'playing';
if (game.menu) {
game.menu.destroy();
game.menu = null;
}
if (game.leaderboard) {
game.leaderboard.destroy();
game.leaderboard = null;
}
// Reset game state
game.score = 0;
game.coinsCollected = 0;
game.lives = 1;
game.obstacleSpeed = 5;
// Show game UI elements
tutorialText.visible = true;
tutorialTextWhite.visible = true;
scoreText.visible = true;
scoreText2.visible = true;
coinText.visible = true;
coinText2.visible = true;
livesText.visible = true;
livesText2.visible = true;
// Show and reset game objects
bird.visible = true;
bird.x = 1024;
bird.y = 1366;
bird.ySpeed = 0;
leftWall.visible = true;
rightWall.visible = true;
// Clear obstacles and coins
for (var i = leftObstacles.length - 1; i >= 0; i--) {
leftObstacles[i].destroy();
leftObstacles.splice(i, 1);
}
for (var i = rightObstacles.length - 1; i >= 0; i--) {
rightObstacles[i].destroy();
rightObstacles.splice(i, 1);
}
for (var i = coins.length - 1; i >= 0; i--) {
coins[i].destroy();
coins.splice(i, 1);
}
// Update UI
scoreText.setText('0');
scoreText2.setText('0');
coinText.setText('Coins: 0');
coinText2.setText('Coins: 0');
livesText.setText('Lives: 1');
livesText2.setText('Lives: 1');
};
game.setBackgroundColor(0x87CEEB);
var scoreText = new Text2('0', {
size: 150,
fill: '#ff6b35',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 8,
dropShadowDistance: 4,
dropShadowAngle: 0
});
scoreText.anchor.set(.5, 0);
LK.gui.top.addChild(scoreText);
var scoreText2 = new Text2('0', {
size: 150,
fill: '#ffffff',
font: 'Arial Black'
});
scoreText2.anchor.set(.5, 0);
scoreText2.x = -4;
scoreText2.y = -5;
LK.gui.top.addChild(scoreText2);
LK.gui.top.addChild(scoreText);
var coinText = new Text2('Coins: 0', {
size: 80,
fill: '#ffd700',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#b8860b',
dropShadowBlur: 5,
dropShadowDistance: 2,
dropShadowAngle: 0
});
coinText.anchor.set(1, 0);
coinText.x = -20;
coinText.y = 20;
LK.gui.topRight.addChild(coinText);
var coinText2 = new Text2('Coins: 0', {
size: 80,
fill: '#ffffff',
font: 'Arial Black'
});
coinText2.anchor.set(1, 0);
coinText2.x = -24;
coinText2.y = 15;
LK.gui.topRight.addChild(coinText2);
LK.gui.topRight.addChild(coinText);
var livesText = new Text2('Lives: 1', {
size: 80,
fill: '#ff4444',
font: 'Arial Black',
dropShadow: true,
dropShadowColor: '#aa0000',
dropShadowBlur: 5,
dropShadowDistance: 2,
dropShadowAngle: 0
});
livesText.anchor.set(1, 0);
livesText.x = -20;
livesText.y = 120;
LK.gui.topRight.addChild(livesText);
var livesText2 = new Text2('Lives: 1', {
size: 80,
fill: '#ffffff',
font: 'Arial Black'
});
livesText2.anchor.set(1, 0);
livesText2.x = -24;
livesText2.y = 115;
LK.gui.topRight.addChild(livesText2);
LK.gui.topRight.addChild(livesText);
var bird = game.addChild(new Bird());
var leftWall = game.addChild(new Wall());
leftWall.x = 0;
leftWall.y = 1366;
var rightWall = game.addChild(new Wall());
rightWall.x = 2048;
rightWall.y = 1366;
var leftObstacles = [],
rightObstacles = [],
coins = [];
var coinSpawnTime = 120;
var coinSpawnCounter = 0;
var obstacleSpawnRandomness = 180;
var obstacleSpawnRandomnessDecrease = 0.025 * (2 / 3);
var obstacleSpawnY = -500;
var leftObstacleSpawnTime = Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
var rightObstacleSpawnTime = Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
bird.x = 1024;
bird.y = 1366;
game.isMouseDown = false;
// Start with menu
game.showMenu();
game.down = function (x, y, obj) {
if (game.gameState === 'playing') {
bird.flap();
game.isMouseDown = true;
}
};
game.up = function (x, y, obj) {
if (game.gameState === 'playing') {
game.isMouseDown = false;
}
};
game.update = function () {
if (game.gameState !== 'playing') {
return;
}
bird._update_migrated();
if (game.score > 2) {
tutorialText.y += 5;
tutorialTextWhite.y += 5;
}
scoreText.setText(game.score);
scoreText2.setText(game.score);
game.obstacleSpeed += game.obstacleSpeedIncrease;
obstacleSpawnRandomness -= obstacleSpawnRandomnessDecrease;
if (obstacleSpawnRandomness < 40) {
obstacleSpawnRandomness = 40;
}
if (LK.ticks >= leftObstacleSpawnTime) {
var newObstacle = game.addChildAt(new Obstacle(), 0);
newObstacle.x = 0;
newObstacle.y = obstacleSpawnY;
leftObstacles.push(newObstacle);
leftObstacleSpawnTime += Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
}
if (LK.ticks >= rightObstacleSpawnTime) {
var newObstacle = game.addChildAt(new Obstacle(), 0);
newObstacle.x = 2048;
newObstacle.y = -newObstacle.height;
rightObstacles.push(newObstacle);
rightObstacleSpawnTime += Math.floor(Math.random() * obstacleSpawnRandomness) + obstacleSpawnRandomness;
}
if (bird.intersects(leftWall) && bird.xSpeed < 0 || bird.intersects(rightWall) && bird.xSpeed > 0) {
bird.xSpeed = -bird.xSpeed;
bird.flip();
game.score++;
LK.setScore(game.score);
LK.getSound('bounce').play();
}
for (var i = leftObstacles.length - 1; i >= 0; i--) {
leftObstacles[i]._move_migrated(game.obstacleSpeed);
if (leftObstacles[i].y > 3232) {
leftObstacles[i].destroy();
leftObstacles.splice(i, 1);
}
}
for (var i = rightObstacles.length - 1; i >= 0; i--) {
rightObstacles[i]._move_migrated(game.obstacleSpeed);
if (rightObstacles[i].y > 3232) {
rightObstacles[i].destroy();
rightObstacles.splice(i, 1);
}
}
// Spawn coins
coinSpawnCounter++;
if (coinSpawnCounter >= coinSpawnTime) {
var newCoin = game.addChild(new Coin());
newCoin.x = Math.random() * 1500 + 300; // Random X between walls
newCoin.y = -100;
coins.push(newCoin);
coinSpawnCounter = 0;
coinSpawnTime = Math.random() * 180 + 60; // Random spawn time
}
// Move and check coin collection
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
if (!coin.collected) {
coin._move_migrated(game.obstacleSpeed);
// Check collision with bird
if (bird.intersects(coin)) {
coin.collect();
game.coinsCollected++;
game.score += 3; // Give bonus points for coins
LK.setScore(game.score);
scoreText.setText(game.score);
scoreText2.setText(game.score);
coinText.setText('Coins: ' + game.coinsCollected);
coinText2.setText('Coins: ' + game.coinsCollected);
// Check for extra life every 10 coins (maximum 3 lives)
if (game.coinsCollected % 10 === 0 && game.lives < 3) {
game.lives++;
livesText.setText('Lives: ' + game.lives);
livesText2.setText('Lives: ' + game.lives);
// Flash the lives text to indicate extra life gained
tween(livesText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(livesText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
coins.splice(i, 1);
continue;
}
// Remove coins that are off screen
if (coin.y > 3000) {
coin.destroy();
coins.splice(i, 1);
}
}
}
game.checkObstacleCollision(leftObstacles);
game.checkObstacleCollision(rightObstacles);
if (bird.y < 0 || bird.y > 2732) {
game.lives--;
livesText.setText('Lives: ' + game.lives);
livesText2.setText('Lives: ' + game.lives);
if (game.lives <= 0) {
game.saveScore();
LK.setScore(game.score);
LK.getSound('gameOverJingle').play();
LK.showGameOver();
} else {
// Flash red to indicate life lost
LK.effects.flashScreen(0xff0000, 500);
// Reset bird position
bird.x = 1024;
bird.y = 1366;
bird.ySpeed = 0;
}
}
};