/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Bird = Container.expand(function () { var self = Container.call(this); // Create bird sprite var birdGraphics = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); // Physics properties self.velocity = 0; self.gravity = 0.5; self.flapStrength = -14; // Reduced jump strength for lower jumps self.rotation = 0; self.lastY = 0; self.isDead = false; self.flapping = false; // Flap the bird (jump) self.flap = function () { if (self.isDead) return; self.velocity = self.flapStrength; LK.getSound('flap').play(); // Wing flapping animation using tween if (!self.flapping) { self.flapping = true; // Scale up quickly tween(birdGraphics, { scaleY: 0.8, scaleX: 1.2 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { // Scale back to normal tween(birdGraphics, { scaleY: 1.0, scaleX: 1.0 }, { duration: 200, easing: tween.elasticOut, onFinish: function onFinish() { self.flapping = false; } }); } }); } }; // Update bird position and rotation self.update = function () { self.lastY = self.y; if (!self.isDead) { // Apply gravity and update position self.velocity += self.gravity; self.y += self.velocity; // Update rotation based on velocity var targetRotation = Math.min(Math.PI / 4, Math.max(-Math.PI / 4, self.velocity * 0.05)); self.rotation += (targetRotation - self.rotation) * 0.2; birdGraphics.rotation = self.rotation; } }; // Handle collision self.die = function () { self.isDead = true; LK.getSound('hit').play(); }; return self; }); var Pipe = Container.expand(function () { var self = Container.call(this); // Pipe properties self.speed = 8; self.scored = false; self.lastX = 0; // Create top and bottom pipes var topPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 1.0 }); var bottomPipe = self.attachAsset('pipe', { anchorX: 0.5, anchorY: 0.0 }); // Setup pipe gap self.setGapPosition = function (gapY, gapHeight) { // Calculate top pipe height so its bottom edge is at the top of the gap var topPipeHeight = gapY - gapHeight / 2; if (topPipeHeight < 0) topPipeHeight = 0; topPipe.height = topPipeHeight; topPipe.y = topPipeHeight; // Calculate bottom pipe height so its top edge is at the bottom of the gap var bottomPipeHeight = 2732 - (gapY + gapHeight / 2); if (bottomPipeHeight < 0) bottomPipeHeight = 0; bottomPipe.height = bottomPipeHeight; bottomPipe.y = gapY + gapHeight / 2; }; // Update pipe position self.update = function () { self.lastX = self.x; self.x -= self.speed; }; return self; }); /**** * Initialize Game ****/ // Game constants var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Initialize assets for the game // Game constants var GROUND_Y = 2732 - 100; var GAME_WIDTH = 2048; var GAP_HEIGHT = 500; // Increased gap between pipes var PIPE_DISTANCE = 900; // (not used in current code, but keep for future) var PIPE_SPAWN_X = GAME_WIDTH + 100; // Game state variables var gameStarted = false; var gameOver = false; var pipes = []; var score = 0; var groundOffset = 0; // Set sky background color game.setBackgroundColor(0x87CEEB); // --- Single Background Layer --- // Large background image covering the whole game area var background = game.addChild(LK.getAsset('bacround', { anchorX: 0, anchorY: 0, x: 0, y: 0, scaleX: GAME_WIDTH / 140, scaleY: 2732 / 134.53, tint: 0xFFFFFF })); // Create ground var ground = game.addChild(LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: 0, y: GROUND_Y })); // Create a second ground piece for infinite scrolling var ground2 = game.addChild(LK.getAsset('ground', { anchorX: 0, anchorY: 0, x: GAME_WIDTH, y: GROUND_Y })); // Create player bird var bird = game.addChild(new Bird()); bird.x = GAME_WIDTH * 0.3; bird.y = GROUND_Y * 0.5; // Score display var scoreTxt = new Text2('0', { size: 150, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 50; // Create a pipe at the specified position function createPipe() { var pipe = new Pipe(); pipe.x = PIPE_SPAWN_X; // Random gap position (ensure it's not too close to top or bottom) var minGapY = 300; var maxGapY = GROUND_Y - 300; var gapY = minGapY + Math.random() * (maxGapY - minGapY); pipe.setGapPosition(gapY, GAP_HEIGHT); pipes.push(pipe); game.addChild(pipe); } // Event handlers game.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; } if (!gameOver) { bird.flap(); } }; // Check for collisions function checkCollisions() { // Check if bird hit the ground if (bird.y + bird.height / 2 >= GROUND_Y) { bird.y = GROUND_Y - bird.height / 2; if (!gameOver) { gameOver = true; bird.die(); LK.showGameOver(); } return true; } // Check if bird flew too high if (bird.y - bird.height / 2 <= 0) { bird.y = bird.height / 2; bird.velocity = 0; } // Check collision with pipes for (var i = 0; i < pipes.length; i++) { var pipe = pipes[i]; // Top and bottom pipe children var topPipe = pipe.getChildAt(0); var bottomPipe = pipe.getChildAt(1); // Check if bird collides with either pipe if (bird.intersects(topPipe) || bird.intersects(bottomPipe)) { if (!gameOver) { gameOver = true; bird.die(); LK.showGameOver(); } return true; } // Score point when passing pipe if (!pipe.scored && pipe.lastX >= bird.x && pipe.x < bird.x) { pipe.scored = true; score++; LK.setScore(score); scoreTxt.setText(score.toString()); LK.getSound('score').play(); } } return false; } // Game update loop game.update = function () { if (!gameStarted) { // Bobbing animation before game starts bird.y = GROUND_Y * 0.5 + Math.sin(LK.ticks * 0.05) * 20; return; } // Update bird bird.update(); if (!gameOver) { // No parallax background movement, only static background // Infinite scrolling ground groundOffset = (groundOffset + 8) % GAME_WIDTH; ground.x = -groundOffset; ground2.x = GAME_WIDTH - groundOffset; // Extend ground and return du from the front for continuous scrolling if (ground.x <= -GAME_WIDTH) { ground.x = ground2.x + GAME_WIDTH; } if (ground2.x <= -GAME_WIDTH) { ground2.x = ground.x + GAME_WIDTH; } // Update pipes for (var i = pipes.length - 1; i >= 0; i--) { var pipe = pipes[i]; pipe.update(); // Remove pipes that are off screen if (pipe.x < -200) { pipe.destroy(); pipes.splice(i, 1); } } // Create new pipes if (LK.ticks % 140 === 0 || pipes.length === 0) { createPipe(); } // Check for collisions checkCollisions(); } }; // Tween library for animations
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Bird = Container.expand(function () {
var self = Container.call(this);
// Create bird sprite
var birdGraphics = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Physics properties
self.velocity = 0;
self.gravity = 0.5;
self.flapStrength = -14; // Reduced jump strength for lower jumps
self.rotation = 0;
self.lastY = 0;
self.isDead = false;
self.flapping = false;
// Flap the bird (jump)
self.flap = function () {
if (self.isDead) return;
self.velocity = self.flapStrength;
LK.getSound('flap').play();
// Wing flapping animation using tween
if (!self.flapping) {
self.flapping = true;
// Scale up quickly
tween(birdGraphics, {
scaleY: 0.8,
scaleX: 1.2
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Scale back to normal
tween(birdGraphics, {
scaleY: 1.0,
scaleX: 1.0
}, {
duration: 200,
easing: tween.elasticOut,
onFinish: function onFinish() {
self.flapping = false;
}
});
}
});
}
};
// Update bird position and rotation
self.update = function () {
self.lastY = self.y;
if (!self.isDead) {
// Apply gravity and update position
self.velocity += self.gravity;
self.y += self.velocity;
// Update rotation based on velocity
var targetRotation = Math.min(Math.PI / 4, Math.max(-Math.PI / 4, self.velocity * 0.05));
self.rotation += (targetRotation - self.rotation) * 0.2;
birdGraphics.rotation = self.rotation;
}
};
// Handle collision
self.die = function () {
self.isDead = true;
LK.getSound('hit').play();
};
return self;
});
var Pipe = Container.expand(function () {
var self = Container.call(this);
// Pipe properties
self.speed = 8;
self.scored = false;
self.lastX = 0;
// Create top and bottom pipes
var topPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 1.0
});
var bottomPipe = self.attachAsset('pipe', {
anchorX: 0.5,
anchorY: 0.0
});
// Setup pipe gap
self.setGapPosition = function (gapY, gapHeight) {
// Calculate top pipe height so its bottom edge is at the top of the gap
var topPipeHeight = gapY - gapHeight / 2;
if (topPipeHeight < 0) topPipeHeight = 0;
topPipe.height = topPipeHeight;
topPipe.y = topPipeHeight;
// Calculate bottom pipe height so its top edge is at the bottom of the gap
var bottomPipeHeight = 2732 - (gapY + gapHeight / 2);
if (bottomPipeHeight < 0) bottomPipeHeight = 0;
bottomPipe.height = bottomPipeHeight;
bottomPipe.y = gapY + gapHeight / 2;
};
// Update pipe position
self.update = function () {
self.lastX = self.x;
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
// Game constants
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Initialize assets for the game
// Game constants
var GROUND_Y = 2732 - 100;
var GAME_WIDTH = 2048;
var GAP_HEIGHT = 500; // Increased gap between pipes
var PIPE_DISTANCE = 900; // (not used in current code, but keep for future)
var PIPE_SPAWN_X = GAME_WIDTH + 100;
// Game state variables
var gameStarted = false;
var gameOver = false;
var pipes = [];
var score = 0;
var groundOffset = 0;
// Set sky background color
game.setBackgroundColor(0x87CEEB);
// --- Single Background Layer ---
// Large background image covering the whole game area
var background = game.addChild(LK.getAsset('bacround', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: GAME_WIDTH / 140,
scaleY: 2732 / 134.53,
tint: 0xFFFFFF
}));
// Create ground
var ground = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: GROUND_Y
}));
// Create a second ground piece for infinite scrolling
var ground2 = game.addChild(LK.getAsset('ground', {
anchorX: 0,
anchorY: 0,
x: GAME_WIDTH,
y: GROUND_Y
}));
// Create player bird
var bird = game.addChild(new Bird());
bird.x = GAME_WIDTH * 0.3;
bird.y = GROUND_Y * 0.5;
// Score display
var scoreTxt = new Text2('0', {
size: 150,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
// Create a pipe at the specified position
function createPipe() {
var pipe = new Pipe();
pipe.x = PIPE_SPAWN_X;
// Random gap position (ensure it's not too close to top or bottom)
var minGapY = 300;
var maxGapY = GROUND_Y - 300;
var gapY = minGapY + Math.random() * (maxGapY - minGapY);
pipe.setGapPosition(gapY, GAP_HEIGHT);
pipes.push(pipe);
game.addChild(pipe);
}
// Event handlers
game.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
}
if (!gameOver) {
bird.flap();
}
};
// Check for collisions
function checkCollisions() {
// Check if bird hit the ground
if (bird.y + bird.height / 2 >= GROUND_Y) {
bird.y = GROUND_Y - bird.height / 2;
if (!gameOver) {
gameOver = true;
bird.die();
LK.showGameOver();
}
return true;
}
// Check if bird flew too high
if (bird.y - bird.height / 2 <= 0) {
bird.y = bird.height / 2;
bird.velocity = 0;
}
// Check collision with pipes
for (var i = 0; i < pipes.length; i++) {
var pipe = pipes[i];
// Top and bottom pipe children
var topPipe = pipe.getChildAt(0);
var bottomPipe = pipe.getChildAt(1);
// Check if bird collides with either pipe
if (bird.intersects(topPipe) || bird.intersects(bottomPipe)) {
if (!gameOver) {
gameOver = true;
bird.die();
LK.showGameOver();
}
return true;
}
// Score point when passing pipe
if (!pipe.scored && pipe.lastX >= bird.x && pipe.x < bird.x) {
pipe.scored = true;
score++;
LK.setScore(score);
scoreTxt.setText(score.toString());
LK.getSound('score').play();
}
}
return false;
}
// Game update loop
game.update = function () {
if (!gameStarted) {
// Bobbing animation before game starts
bird.y = GROUND_Y * 0.5 + Math.sin(LK.ticks * 0.05) * 20;
return;
}
// Update bird
bird.update();
if (!gameOver) {
// No parallax background movement, only static background
// Infinite scrolling ground
groundOffset = (groundOffset + 8) % GAME_WIDTH;
ground.x = -groundOffset;
ground2.x = GAME_WIDTH - groundOffset;
// Extend ground and return du from the front for continuous scrolling
if (ground.x <= -GAME_WIDTH) {
ground.x = ground2.x + GAME_WIDTH;
}
if (ground2.x <= -GAME_WIDTH) {
ground2.x = ground.x + GAME_WIDTH;
}
// Update pipes
for (var i = pipes.length - 1; i >= 0; i--) {
var pipe = pipes[i];
pipe.update();
// Remove pipes that are off screen
if (pipe.x < -200) {
pipe.destroy();
pipes.splice(i, 1);
}
}
// Create new pipes
if (LK.ticks % 140 === 0 || pipes.length === 0) {
createPipe();
}
// Check for collisions
checkCollisions();
}
};
// Tween library for animations