/****
* 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,
width: 100,
height: 100
});
self.velocity = 0;
self.gravity = 0.5;
self.flapStrength = -10;
self.rotation = 0;
self.isDead = false;
self.flap = function () {
if (self.isDead) return;
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Rotate bird upward when flapping
tween(self, {
rotation: -0.5
}, {
duration: 100
});
};
self.update = function () {
if (self.isDead) return;
// Apply gravity and update position
self.velocity += self.gravity;
self.y += self.velocity;
// Update rotation based on velocity
if (self.velocity > 0) {
var targetRotation = Math.min(Math.PI / 2, self.velocity * 0.05);
tween(self, {
rotation: targetRotation
}, {
duration: 200
});
}
};
return self;
});
var Ground = Container.expand(function () {
var self = Container.call(this);
var groundGraphics = self.attachAsset('ground', {
anchorX: 0.0,
anchorY: 0.0,
height: 100
});
self.height = 100;
self.speed = 5;
self.update = function () {
self.x -= self.speed;
// Loop ground for infinite scrolling
if (self.x <= -groundGraphics.width) {
self.x = 0;
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1.0
});
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0.0
});
self.speed = 5;
self.isPassed = false;
self.setGapPosition = function (gapY, gapHeight) {
self.topPipe.y = gapY - gapHeight / 2;
self.bottomPipe.y = gapY + gapHeight / 2;
// Adjust the scale of the bottom pipe to ensure it reaches the ground
// Use the actual height of grounds when available, otherwise use a default value
var groundHeight = grounds.length > 0 ? grounds[0].height : 100;
// Calculate how much we need to scale the pipe to reach the ground
var distanceToGround = game.height - self.bottomPipe.y - groundHeight;
self.bottomPipe.scale.y = distanceToGround / self.bottomPipe.height;
// Adjust the scale of the top pipe to ensure it reaches the top of the screen
self.topPipe.scale.y = self.topPipe.y / self.topPipe.height;
self.gapY = gapY;
};
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var bird;
var pipes = [];
var grounds = [];
var gameStarted = false;
var isGameOver = false;
var pipeGapHeight = 300;
var timeSinceLastPipe = 0;
var pipeInterval = 120; // Frames between pipe spawns
var score = 0;
var bestScore = storage.bestScore || 0;
// Create score text
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create tap to start text
var startTxt = new Text2('Tap to Start', {
size: 100,
fill: 0xFFFFFF
});
startTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startTxt);
// Create bird
function createBird() {
bird = new Bird();
bird.x = 400;
bird.y = game.height / 2;
game.addChild(bird);
}
// Create ground
function createGround() {
var ground = new Ground();
ground.y = game.height - ground.height;
grounds.push(ground);
game.addChild(ground);
// Add second ground piece for continuous scrolling
var ground2 = new Ground();
ground2.x = ground.width;
ground2.y = game.height - ground2.height;
grounds.push(ground2);
game.addChild(ground2);
}
// Create pipe
function createPipe() {
var pipe = new Pipe();
pipe.x = game.width + 100;
// Random gap position, but keep within bounds
var minGapY = pipeGapHeight / 2 + 100;
var maxGapY = game.height - pipeGapHeight / 2 - 150; // Account for ground
var gapY = minGapY + Math.random() * (maxGapY - minGapY);
pipe.setGapPosition(gapY, pipeGapHeight);
pipes.push(pipe);
game.addChild(pipe);
}
// Check collisions
function checkCollisions() {
if (isGameOver) return;
// Ground collision
if (bird.y + bird.height / 2 > game.height - grounds[0].height) {
gameOver();
return;
}
// Ceiling collision
if (bird.y - bird.height / 2 < 0) {
bird.y = bird.height / 2;
bird.velocity = 0;
}
// Pipe collisions
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
if (bird.intersects(pipe.topPipe) || bird.intersects(pipe.bottomPipe)) {
gameOver();
return;
}
// Check if bird passed the pipe
if (!pipe.isPassed && bird.x > pipe.x) {
pipe.isPassed = true;
score++;
scoreTxt.setText(score.toString());
LK.getSound('point').play();
}
}
}
// Game over
function gameOver() {
isGameOver = true;
bird.isDead = true;
// Update best score
if (score > bestScore) {
bestScore = score;
storage.bestScore = bestScore;
}
// Play hit sound
LK.getSound('hit').play();
// Visual feedback
LK.effects.flashScreen(0xff0000, 300);
// Show game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Initialize game
function initGame() {
// Reset variables
gameStarted = false;
isGameOver = false;
timeSinceLastPipe = 0;
score = 0;
// Clear existing elements
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
for (var i = 0; i < grounds.length; i++) {
grounds[i].destroy();
}
grounds = [];
if (bird) {
bird.destroy();
}
// Setup new game
scoreTxt.setText("0");
startTxt.visible = true;
createBird();
createGround();
// Set score based on LK.getScore()
score = LK.getScore();
scoreTxt.setText(score.toString());
// Play background music
LK.playMusic('bgmusic');
}
// Start the game
function startGame() {
if (!gameStarted && !isGameOver) {
gameStarted = true;
startTxt.visible = false;
bird.flap();
}
}
// Event handlers
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
} else if (!isGameOver) {
bird.flap();
}
};
// Update function
game.update = function () {
if (isGameOver) return;
// Update bird
if (gameStarted) {
bird.update();
}
// Update grounds
for (var i = 0; i < grounds.length; i++) {
if (gameStarted) {
grounds[i].update();
}
}
// Update pipes and check for cleanup
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
if (gameStarted) {
pipe.update();
}
// Remove pipes that have moved off screen
if (pipe.x < -300) {
pipe.destroy();
pipes.splice(i, 1);
}
}
// Create new pipes
if (gameStarted) {
timeSinceLastPipe++;
if (timeSinceLastPipe >= pipeInterval) {
createPipe();
timeSinceLastPipe = 0;
}
}
// Check collisions
if (gameStarted) {
checkCollisions();
}
// Update score display
LK.setScore(score);
};
// Initialize the game on startup
initGame(); /****
* 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,
width: 100,
height: 100
});
self.velocity = 0;
self.gravity = 0.5;
self.flapStrength = -10;
self.rotation = 0;
self.isDead = false;
self.flap = function () {
if (self.isDead) return;
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Rotate bird upward when flapping
tween(self, {
rotation: -0.5
}, {
duration: 100
});
};
self.update = function () {
if (self.isDead) return;
// Apply gravity and update position
self.velocity += self.gravity;
self.y += self.velocity;
// Update rotation based on velocity
if (self.velocity > 0) {
var targetRotation = Math.min(Math.PI / 2, self.velocity * 0.05);
tween(self, {
rotation: targetRotation
}, {
duration: 200
});
}
};
return self;
});
var Ground = Container.expand(function () {
var self = Container.call(this);
var groundGraphics = self.attachAsset('ground', {
anchorX: 0.0,
anchorY: 0.0,
height: 100
});
self.height = 100;
self.speed = 5;
self.update = function () {
self.x -= self.speed;
// Loop ground for infinite scrolling
if (self.x <= -groundGraphics.width) {
self.x = 0;
}
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1.0
});
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0.0
});
self.speed = 5;
self.isPassed = false;
self.setGapPosition = function (gapY, gapHeight) {
self.topPipe.y = gapY - gapHeight / 2;
self.bottomPipe.y = gapY + gapHeight / 2;
// Adjust the scale of the bottom pipe to ensure it reaches the ground
// Use the actual height of grounds when available, otherwise use a default value
var groundHeight = grounds.length > 0 ? grounds[0].height : 100;
// Calculate how much we need to scale the pipe to reach the ground
var distanceToGround = game.height - self.bottomPipe.y - groundHeight;
self.bottomPipe.scale.y = distanceToGround / self.bottomPipe.height;
// Adjust the scale of the top pipe to ensure it reaches the top of the screen
self.topPipe.scale.y = self.topPipe.y / self.topPipe.height;
self.gapY = gapY;
};
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var bird;
var pipes = [];
var grounds = [];
var gameStarted = false;
var isGameOver = false;
var pipeGapHeight = 300;
var timeSinceLastPipe = 0;
var pipeInterval = 120; // Frames between pipe spawns
var score = 0;
var bestScore = storage.bestScore || 0;
// Create score text
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Create tap to start text
var startTxt = new Text2('Tap to Start', {
size: 100,
fill: 0xFFFFFF
});
startTxt.anchor.set(0.5, 0.5);
LK.gui.center.addChild(startTxt);
// Create bird
function createBird() {
bird = new Bird();
bird.x = 400;
bird.y = game.height / 2;
game.addChild(bird);
}
// Create ground
function createGround() {
var ground = new Ground();
ground.y = game.height - ground.height;
grounds.push(ground);
game.addChild(ground);
// Add second ground piece for continuous scrolling
var ground2 = new Ground();
ground2.x = ground.width;
ground2.y = game.height - ground2.height;
grounds.push(ground2);
game.addChild(ground2);
}
// Create pipe
function createPipe() {
var pipe = new Pipe();
pipe.x = game.width + 100;
// Random gap position, but keep within bounds
var minGapY = pipeGapHeight / 2 + 100;
var maxGapY = game.height - pipeGapHeight / 2 - 150; // Account for ground
var gapY = minGapY + Math.random() * (maxGapY - minGapY);
pipe.setGapPosition(gapY, pipeGapHeight);
pipes.push(pipe);
game.addChild(pipe);
}
// Check collisions
function checkCollisions() {
if (isGameOver) return;
// Ground collision
if (bird.y + bird.height / 2 > game.height - grounds[0].height) {
gameOver();
return;
}
// Ceiling collision
if (bird.y - bird.height / 2 < 0) {
bird.y = bird.height / 2;
bird.velocity = 0;
}
// Pipe collisions
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
if (bird.intersects(pipe.topPipe) || bird.intersects(pipe.bottomPipe)) {
gameOver();
return;
}
// Check if bird passed the pipe
if (!pipe.isPassed && bird.x > pipe.x) {
pipe.isPassed = true;
score++;
scoreTxt.setText(score.toString());
LK.getSound('point').play();
}
}
}
// Game over
function gameOver() {
isGameOver = true;
bird.isDead = true;
// Update best score
if (score > bestScore) {
bestScore = score;
storage.bestScore = bestScore;
}
// Play hit sound
LK.getSound('hit').play();
// Visual feedback
LK.effects.flashScreen(0xff0000, 300);
// Show game over after a short delay
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
}
// Initialize game
function initGame() {
// Reset variables
gameStarted = false;
isGameOver = false;
timeSinceLastPipe = 0;
score = 0;
// Clear existing elements
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
for (var i = 0; i < grounds.length; i++) {
grounds[i].destroy();
}
grounds = [];
if (bird) {
bird.destroy();
}
// Setup new game
scoreTxt.setText("0");
startTxt.visible = true;
createBird();
createGround();
// Set score based on LK.getScore()
score = LK.getScore();
scoreTxt.setText(score.toString());
// Play background music
LK.playMusic('bgmusic');
}
// Start the game
function startGame() {
if (!gameStarted && !isGameOver) {
gameStarted = true;
startTxt.visible = false;
bird.flap();
}
}
// Event handlers
game.down = function (x, y, obj) {
if (!gameStarted) {
startGame();
} else if (!isGameOver) {
bird.flap();
}
};
// Update function
game.update = function () {
if (isGameOver) return;
// Update bird
if (gameStarted) {
bird.update();
}
// Update grounds
for (var i = 0; i < grounds.length; i++) {
if (gameStarted) {
grounds[i].update();
}
}
// Update pipes and check for cleanup
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
if (gameStarted) {
pipe.update();
}
// Remove pipes that have moved off screen
if (pipe.x < -300) {
pipe.destroy();
pipes.splice(i, 1);
}
}
// Create new pipes
if (gameStarted) {
timeSinceLastPipe++;
if (timeSinceLastPipe >= pipeInterval) {
createPipe();
timeSinceLastPipe = 0;
}
}
// Check collisions
if (gameStarted) {
checkCollisions();
}
// Update score display
LK.setScore(score);
};
// Initialize the game on startup
initGame();