/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); var birdSprite = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); self.vy = 0; // vertical velocity // Bird physics constants self.gravity = 0.8; // px per frame^2 (further reduced for even slower fall) self.flapStrength = -24; // px per frame (reduced for less ascent) // Flap method self.flap = function () { self.vy = self.flapStrength; // Animate a quick scale for feedback tween(birdSprite, { scaleY: 0.7 }, { duration: 60, easing: tween.cubicOut, onFinish: function onFinish() { tween(birdSprite, { scaleY: 1 }, { duration: 120, easing: tween.cubicOut }); } }); }; // Update method self.update = function () { self.vy += self.gravity; self.y += self.vy; // Clamp rotation for visual feedback var maxAngle = Math.PI / 4; var minAngle = -Math.PI / 6; var angle = self.vy / 40 * maxAngle; if (angle > maxAngle) angle = maxAngle; if (angle < minAngle) angle = minAngle; birdSprite.rotation = angle; }; return self; }); // PipePair class (top and bottom pipes) var PipePair = Container.expand(function () { var self = Container.call(this); // Pipe gap size and min/max Y for gap center self.gap = 600; // Increased gap size for easier play self.pipeWidth = 200; self.pipeHeight = 900; // Top pipe self.topPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 1, width: self.pipeWidth, height: self.pipeHeight }); // Bottom pipe self.bottomPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 0, width: self.pipeWidth, height: self.pipeHeight }); // Set pipes' positions based on gapY self.setGapY = function (gapY) { // Top pipe: bottom at gapY - gap/2, top at y=0 self.topPipe.y = gapY - self.gap / 2; self.topPipe.height = self.topPipe.y; // height from top to bottom of top pipe // Bottom pipe: top at gapY + gap/2, bottom at ground var groundY = 2732 - 60; // GROUND_Y self.bottomPipe.y = gapY + self.gap / 2; self.bottomPipe.height = groundY - self.bottomPipe.y; // height from top of bottom pipe to ground }; // For scoring self.passed = false; // Update method self.update = function () { self.x -= pipeSpeed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // Game constants // Bird: yellow ellipse // Pipe: green box // Ground: brown box var BIRD_START_X = 600; var BIRD_START_Y = 1200; var GROUND_Y = 2732 - 60; // ground height is 120, anchorY=0 var PIPE_INTERVAL = 105; // frames between pipes (~1.75s at 60fps) var PIPE_MIN_Y = 500; var PIPE_MAX_Y = 2732 - 500 - 420; // leave space for gap and ground var pipeSpeed = 16; // px per frame, increases with score // Game state var bird; var pipes = []; var ground; var score = 0; var scoreTxt; var lastPipeTick = 0; var gameStarted = false; var gameOver = false; // Add ground ground = LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: GROUND_Y }); game.addChild(ground); // Add score text to GUI scoreTxt = new Text2('0', { size: 160, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Add bird bird = new Bird(); bird.x = BIRD_START_X; bird.y = BIRD_START_Y; game.addChild(bird); // Start game on first tap function startGame() { if (!gameStarted) { gameStarted = true; score = 0; LK.setScore(0); scoreTxt.setText('0'); // Remove old pipes for (var i = 0; i < pipes.length; i++) { pipes[i].destroy(); } pipes = []; // Reset bird bird.x = BIRD_START_X; bird.y = BIRD_START_Y; bird.vy = 0; pipeSpeed = 16; lastPipeTick = LK.ticks; gameOver = false; } } // Flap on tap game.down = function (x, y, obj) { if (gameOver) return; if (!gameStarted) { startGame(); } bird.flap(); }; // Main update loop game.update = function () { if (!gameStarted || gameOver) return; // Bird physics bird.update(); // Clamp bird to top of screen if (bird.y < 0) bird.y = 0; // Pipes for (var i = pipes.length - 1; i >= 0; i--) { var pipePair = pipes[i]; pipePair.update(); // Remove pipes off screen if (pipePair.x < -pipePair.pipeWidth) { pipePair.destroy(); pipes.splice(i, 1); continue; } // Scoring: passed center of pipes if (!pipePair.passed && bird.x > pipePair.x + pipePair.pipeWidth / 2) { pipePair.passed = true; score += 1; LK.setScore(score); scoreTxt.setText(score + ''); // Increase speed every 10 points if (score % 10 === 0) { pipeSpeed += 2; } } // Collision detection // Top pipe if (bird.intersects(pipePair.topPipe) || bird.intersects(pipePair.bottomPipe)) { endGame(); return; } } // Add new pipes if (LK.ticks - lastPipeTick > PIPE_INTERVAL) { var gapY = PIPE_MIN_Y + Math.floor(Math.random() * (PIPE_MAX_Y - PIPE_MIN_Y)); var pipePair = new PipePair(); pipePair.x = 2048 + 200; // start just off right edge pipePair.setGapY(gapY); pipes.push(pipePair); game.addChild(pipePair); lastPipeTick = LK.ticks; } // Ground collision if (bird.y + bird.height / 2 > GROUND_Y) { bird.y = GROUND_Y - bird.height / 2; endGame(); return; } }; // End game function endGame() { if (gameOver) return; gameOver = true; // Flash red LK.effects.flashScreen(0xff0000, 600); // Show game over popup (handled by LK) LK.showGameOver(); } // Reset on game over (handled by LK engine, but for safety) game.onGameOver = function () { gameStarted = false; gameOver = false; score = 0; LK.setScore(0); scoreTxt.setText('0'); // Remove pipes for (var i = 0; i < pipes.length; i++) { pipes[i].destroy(); } pipes = []; // Reset bird bird.x = BIRD_START_X; bird.y = BIRD_START_Y; bird.vy = 0; pipeSpeed = 16; lastPipeTick = LK.ticks; };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
var birdSprite = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
self.vy = 0; // vertical velocity
// Bird physics constants
self.gravity = 0.8; // px per frame^2 (further reduced for even slower fall)
self.flapStrength = -24; // px per frame (reduced for less ascent)
// Flap method
self.flap = function () {
self.vy = self.flapStrength;
// Animate a quick scale for feedback
tween(birdSprite, {
scaleY: 0.7
}, {
duration: 60,
easing: tween.cubicOut,
onFinish: function onFinish() {
tween(birdSprite, {
scaleY: 1
}, {
duration: 120,
easing: tween.cubicOut
});
}
});
};
// Update method
self.update = function () {
self.vy += self.gravity;
self.y += self.vy;
// Clamp rotation for visual feedback
var maxAngle = Math.PI / 4;
var minAngle = -Math.PI / 6;
var angle = self.vy / 40 * maxAngle;
if (angle > maxAngle) angle = maxAngle;
if (angle < minAngle) angle = minAngle;
birdSprite.rotation = angle;
};
return self;
});
// PipePair class (top and bottom pipes)
var PipePair = Container.expand(function () {
var self = Container.call(this);
// Pipe gap size and min/max Y for gap center
self.gap = 600; // Increased gap size for easier play
self.pipeWidth = 200;
self.pipeHeight = 900;
// Top pipe
self.topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1,
width: self.pipeWidth,
height: self.pipeHeight
});
// Bottom pipe
self.bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0,
width: self.pipeWidth,
height: self.pipeHeight
});
// Set pipes' positions based on gapY
self.setGapY = function (gapY) {
// Top pipe: bottom at gapY - gap/2, top at y=0
self.topPipe.y = gapY - self.gap / 2;
self.topPipe.height = self.topPipe.y; // height from top to bottom of top pipe
// Bottom pipe: top at gapY + gap/2, bottom at ground
var groundY = 2732 - 60; // GROUND_Y
self.bottomPipe.y = gapY + self.gap / 2;
self.bottomPipe.height = groundY - self.bottomPipe.y; // height from top of bottom pipe to ground
};
// For scoring
self.passed = false;
// Update method
self.update = function () {
self.x -= pipeSpeed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// Game constants
// Bird: yellow ellipse
// Pipe: green box
// Ground: brown box
var BIRD_START_X = 600;
var BIRD_START_Y = 1200;
var GROUND_Y = 2732 - 60; // ground height is 120, anchorY=0
var PIPE_INTERVAL = 105; // frames between pipes (~1.75s at 60fps)
var PIPE_MIN_Y = 500;
var PIPE_MAX_Y = 2732 - 500 - 420; // leave space for gap and ground
var pipeSpeed = 16; // px per frame, increases with score
// Game state
var bird;
var pipes = [];
var ground;
var score = 0;
var scoreTxt;
var lastPipeTick = 0;
var gameStarted = false;
var gameOver = false;
// Add ground
ground = LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: GROUND_Y
});
game.addChild(ground);
// Add score text to GUI
scoreTxt = new Text2('0', {
size: 160,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Add bird
bird = new Bird();
bird.x = BIRD_START_X;
bird.y = BIRD_START_Y;
game.addChild(bird);
// Start game on first tap
function startGame() {
if (!gameStarted) {
gameStarted = true;
score = 0;
LK.setScore(0);
scoreTxt.setText('0');
// Remove old pipes
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
// Reset bird
bird.x = BIRD_START_X;
bird.y = BIRD_START_Y;
bird.vy = 0;
pipeSpeed = 16;
lastPipeTick = LK.ticks;
gameOver = false;
}
}
// Flap on tap
game.down = function (x, y, obj) {
if (gameOver) return;
if (!gameStarted) {
startGame();
}
bird.flap();
};
// Main update loop
game.update = function () {
if (!gameStarted || gameOver) return;
// Bird physics
bird.update();
// Clamp bird to top of screen
if (bird.y < 0) bird.y = 0;
// Pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipePair = pipes[i];
pipePair.update();
// Remove pipes off screen
if (pipePair.x < -pipePair.pipeWidth) {
pipePair.destroy();
pipes.splice(i, 1);
continue;
}
// Scoring: passed center of pipes
if (!pipePair.passed && bird.x > pipePair.x + pipePair.pipeWidth / 2) {
pipePair.passed = true;
score += 1;
LK.setScore(score);
scoreTxt.setText(score + '');
// Increase speed every 10 points
if (score % 10 === 0) {
pipeSpeed += 2;
}
}
// Collision detection
// Top pipe
if (bird.intersects(pipePair.topPipe) || bird.intersects(pipePair.bottomPipe)) {
endGame();
return;
}
}
// Add new pipes
if (LK.ticks - lastPipeTick > PIPE_INTERVAL) {
var gapY = PIPE_MIN_Y + Math.floor(Math.random() * (PIPE_MAX_Y - PIPE_MIN_Y));
var pipePair = new PipePair();
pipePair.x = 2048 + 200; // start just off right edge
pipePair.setGapY(gapY);
pipes.push(pipePair);
game.addChild(pipePair);
lastPipeTick = LK.ticks;
}
// Ground collision
if (bird.y + bird.height / 2 > GROUND_Y) {
bird.y = GROUND_Y - bird.height / 2;
endGame();
return;
}
};
// End game
function endGame() {
if (gameOver) return;
gameOver = true;
// Flash red
LK.effects.flashScreen(0xff0000, 600);
// Show game over popup (handled by LK)
LK.showGameOver();
}
// Reset on game over (handled by LK engine, but for safety)
game.onGameOver = function () {
gameStarted = false;
gameOver = false;
score = 0;
LK.setScore(0);
scoreTxt.setText('0');
// Remove pipes
for (var i = 0; i < pipes.length; i++) {
pipes[i].destroy();
}
pipes = [];
// Reset bird
bird.x = BIRD_START_X;
bird.y = BIRD_START_Y;
bird.vy = 0;
pipeSpeed = 16;
lastPipeTick = LK.ticks;
};