/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird class (player) var Bird = Container.expand(function () { var self = Container.call(this); // Attach bird asset (ellipse, yellow) var birdAsset = self.attachAsset('bird', { anchorX: 0.5, anchorY: 0.5 }); // Bird is now half the size of yacht: 240x240 birdAsset.width = 240; birdAsset.height = 240; birdAsset.color = 0xffe066; birdAsset.shape = 'ellipse'; // No update needed; movement is handled in game.move return self; }); // Coin class var Coin = Container.expand(function () { var self = Container.call(this); // Attach coin asset (ellipse, gold) var coinAsset = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); // For MVP, coin is 120x120 ellipse, gold (increased size) coinAsset.width = 120; coinAsset.height = 120; coinAsset.color = 0xffd700; coinAsset.shape = 'ellipse'; // Coin speed (matches background speed) self.speed = 12; // Update: move left, destroy if off screen self.update = function () { self.x -= self.speed; }; return self; }); // Sea background class (scrolling effect) var Sea = Container.expand(function () { var self = Container.call(this); // Attach sea asset (box, blue) var seaAsset = self.attachAsset('sea', { anchorX: 0, anchorY: 0 }); // Sea covers full width, lower 60% of screen seaAsset.width = 2048; seaAsset.height = 1640; // 60% of 2732 seaAsset.color = 0x3ca0e8; seaAsset.shape = 'box'; // For scrolling, we use two sea objects, so no update needed here return self; }); // Yacht (obstacle) class var Yacht = Container.expand(function () { var self = Container.call(this); // Attach yacht asset (box, white) var yachtAsset = self.attachAsset('yacht', { anchorX: 0.5, anchorY: 0.5 }); // For MVP, yacht is slightly smaller (400x400), white yachtAsset.width = 400; yachtAsset.height = 400; yachtAsset.color = 0xffffff; yachtAsset.shape = 'box'; // Yacht speed (matches background speed) self.speed = 12; // Update: move left, destroy if off screen self.update = function () { self.x -= self.speed; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87ceeb // Sky blue }); /**** * Game Code ****/ // --- Global variables --- // Tween plugin for simple animations (not used in MVP, but included for future use) var bird; var coins = []; var yachts = []; var dragNode = null; var score = 0; var gameStarted = false; var lastCoinSpawn = 0; var lastYachtSpawn = 0; var coinSpawnInterval = 0.7; // seconds var yachtSpawnInterval = 1.2; // seconds var sea1, sea2; var scoreTxt; // --- Sea background (scrolling) --- sea1 = new Sea(); sea2 = new Sea(); game.addChild(sea1); game.addChild(sea2); // Position sea1 at bottom, sea2 right after it (to the right) sea1.x = 0; sea1.y = 2732 - sea1.height; sea2.x = 2048; sea2.y = sea1.y; // --- Bird (player) --- bird = new Bird(); game.addChild(bird); // Start position: left quarter, vertically centered above sea bird.x = 350; bird.y = 2732 / 2; // --- GUI: Score --- scoreTxt = new Text2('0', { size: 120, fill: 0xFFF700 }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // (Timer GUI removed) // --- Helper: Clamp bird within play area --- function clampBirdY(y) { // Bird must stay above sea, and not go off top var minY = 0 + bird.height / 2 + 20; var maxY = 2732 - sea1.height - bird.height / 2 - 20 + sea1.height; if (y < minY) return minY; if (y > maxY) return maxY; return y; } // --- Touch/drag controls --- function handleMove(x, y, obj) { if (dragNode) { // Clamp Y to play area dragNode.y = clampBirdY(y); } } game.move = handleMove; game.down = function (x, y, obj) { // Only allow drag if touch is on bird or near bird var dx = x - bird.x; var dy = y - bird.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < bird.width) { dragNode = bird; handleMove(x, y, obj); } }; game.up = function (x, y, obj) { dragNode = null; }; // --- Main game update loop --- game.update = function () { // --- Start timer on first move --- if (!gameStarted && LK.ticks > 0) { gameStarted = true; } // --- Scroll sea background --- var seaSpeed = 12; sea1.x -= seaSpeed; sea2.x -= seaSpeed; // If a sea is fully off screen, move it to the right if (sea1.x <= -2048) sea1.x = sea2.x + 2048; if (sea2.x <= -2048) sea2.x = sea1.x + 2048; // --- Spawn coins --- if (gameStarted) { if (LK.ticks - lastCoinSpawn > coinSpawnInterval * 60) { var coin = new Coin(); // Spawn at right edge, random Y above sea coin.x = 2048 + coin.width; var minY = 0 + coin.height / 2 + 100; var maxY = 2732 - sea1.height - coin.height / 2 - 100 + sea1.height; coin.y = minY + Math.random() * (maxY - minY); coins.push(coin); game.addChild(coin); lastCoinSpawn = LK.ticks; } } // --- Spawn yachts (obstacles) --- if (gameStarted) { if (LK.ticks - lastYachtSpawn > yachtSpawnInterval * 60) { var yacht = new Yacht(); // Spawn at right edge, random Y on sea yacht.x = 2048 + yacht.width; var minY = 2732 - sea1.height + yacht.height / 2 + 40; var maxY = 2732 - yacht.height / 2 - 40; yacht.y = minY + Math.random() * (maxY - minY); yachts.push(yacht); game.addChild(yacht); lastYachtSpawn = LK.ticks; } } // --- Update coins --- for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; coin.update(); // Off screen if (coin.x < -coin.width) { coin.destroy(); coins.splice(i, 1); continue; } // Collision with bird if (coin.intersects(bird)) { score += 1; scoreTxt.setText(score); // --- Bird grows slightly with each coin, but not too much --- if (typeof bird.growScale === "undefined") bird.growScale = 1; if (bird.growScale < 1.7) { // Limit max growth (1.7x original) bird.growScale += 0.07; bird.scaleX = bird.growScale; bird.scaleY = bird.growScale; } coin.destroy(); coins.splice(i, 1); continue; } } // --- Update yachts --- for (var j = yachts.length - 1; j >= 0; j--) { var yacht = yachts[j]; yacht.update(); // Off screen if (yacht.x < -yacht.width) { yacht.destroy(); yachts.splice(j, 1); continue; } // Collision with bird (game over) - use yacht itself if (yacht.intersects(bird)) { LK.effects.flashScreen(0xff0000, 800); LK.showGameOver(); return; } } // (Timer update and win condition removed) }; // --- Initial score and timer display --- scoreTxt.setText('0');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class (player)
var Bird = Container.expand(function () {
var self = Container.call(this);
// Attach bird asset (ellipse, yellow)
var birdAsset = self.attachAsset('bird', {
anchorX: 0.5,
anchorY: 0.5
});
// Bird is now half the size of yacht: 240x240
birdAsset.width = 240;
birdAsset.height = 240;
birdAsset.color = 0xffe066;
birdAsset.shape = 'ellipse';
// No update needed; movement is handled in game.move
return self;
});
// Coin class
var Coin = Container.expand(function () {
var self = Container.call(this);
// Attach coin asset (ellipse, gold)
var coinAsset = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
// For MVP, coin is 120x120 ellipse, gold (increased size)
coinAsset.width = 120;
coinAsset.height = 120;
coinAsset.color = 0xffd700;
coinAsset.shape = 'ellipse';
// Coin speed (matches background speed)
self.speed = 12;
// Update: move left, destroy if off screen
self.update = function () {
self.x -= self.speed;
};
return self;
});
// Sea background class (scrolling effect)
var Sea = Container.expand(function () {
var self = Container.call(this);
// Attach sea asset (box, blue)
var seaAsset = self.attachAsset('sea', {
anchorX: 0,
anchorY: 0
});
// Sea covers full width, lower 60% of screen
seaAsset.width = 2048;
seaAsset.height = 1640; // 60% of 2732
seaAsset.color = 0x3ca0e8;
seaAsset.shape = 'box';
// For scrolling, we use two sea objects, so no update needed here
return self;
});
// Yacht (obstacle) class
var Yacht = Container.expand(function () {
var self = Container.call(this);
// Attach yacht asset (box, white)
var yachtAsset = self.attachAsset('yacht', {
anchorX: 0.5,
anchorY: 0.5
});
// For MVP, yacht is slightly smaller (400x400), white
yachtAsset.width = 400;
yachtAsset.height = 400;
yachtAsset.color = 0xffffff;
yachtAsset.shape = 'box';
// Yacht speed (matches background speed)
self.speed = 12;
// Update: move left, destroy if off screen
self.update = function () {
self.x -= self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87ceeb // Sky blue
});
/****
* Game Code
****/
// --- Global variables ---
// Tween plugin for simple animations (not used in MVP, but included for future use)
var bird;
var coins = [];
var yachts = [];
var dragNode = null;
var score = 0;
var gameStarted = false;
var lastCoinSpawn = 0;
var lastYachtSpawn = 0;
var coinSpawnInterval = 0.7; // seconds
var yachtSpawnInterval = 1.2; // seconds
var sea1, sea2;
var scoreTxt;
// --- Sea background (scrolling) ---
sea1 = new Sea();
sea2 = new Sea();
game.addChild(sea1);
game.addChild(sea2);
// Position sea1 at bottom, sea2 right after it (to the right)
sea1.x = 0;
sea1.y = 2732 - sea1.height;
sea2.x = 2048;
sea2.y = sea1.y;
// --- Bird (player) ---
bird = new Bird();
game.addChild(bird);
// Start position: left quarter, vertically centered above sea
bird.x = 350;
bird.y = 2732 / 2;
// --- GUI: Score ---
scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFF700
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// (Timer GUI removed)
// --- Helper: Clamp bird within play area ---
function clampBirdY(y) {
// Bird must stay above sea, and not go off top
var minY = 0 + bird.height / 2 + 20;
var maxY = 2732 - sea1.height - bird.height / 2 - 20 + sea1.height;
if (y < minY) return minY;
if (y > maxY) return maxY;
return y;
}
// --- Touch/drag controls ---
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp Y to play area
dragNode.y = clampBirdY(y);
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Only allow drag if touch is on bird or near bird
var dx = x - bird.x;
var dy = y - bird.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < bird.width) {
dragNode = bird;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Main game update loop ---
game.update = function () {
// --- Start timer on first move ---
if (!gameStarted && LK.ticks > 0) {
gameStarted = true;
}
// --- Scroll sea background ---
var seaSpeed = 12;
sea1.x -= seaSpeed;
sea2.x -= seaSpeed;
// If a sea is fully off screen, move it to the right
if (sea1.x <= -2048) sea1.x = sea2.x + 2048;
if (sea2.x <= -2048) sea2.x = sea1.x + 2048;
// --- Spawn coins ---
if (gameStarted) {
if (LK.ticks - lastCoinSpawn > coinSpawnInterval * 60) {
var coin = new Coin();
// Spawn at right edge, random Y above sea
coin.x = 2048 + coin.width;
var minY = 0 + coin.height / 2 + 100;
var maxY = 2732 - sea1.height - coin.height / 2 - 100 + sea1.height;
coin.y = minY + Math.random() * (maxY - minY);
coins.push(coin);
game.addChild(coin);
lastCoinSpawn = LK.ticks;
}
}
// --- Spawn yachts (obstacles) ---
if (gameStarted) {
if (LK.ticks - lastYachtSpawn > yachtSpawnInterval * 60) {
var yacht = new Yacht();
// Spawn at right edge, random Y on sea
yacht.x = 2048 + yacht.width;
var minY = 2732 - sea1.height + yacht.height / 2 + 40;
var maxY = 2732 - yacht.height / 2 - 40;
yacht.y = minY + Math.random() * (maxY - minY);
yachts.push(yacht);
game.addChild(yacht);
lastYachtSpawn = LK.ticks;
}
}
// --- Update coins ---
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
coin.update();
// Off screen
if (coin.x < -coin.width) {
coin.destroy();
coins.splice(i, 1);
continue;
}
// Collision with bird
if (coin.intersects(bird)) {
score += 1;
scoreTxt.setText(score);
// --- Bird grows slightly with each coin, but not too much ---
if (typeof bird.growScale === "undefined") bird.growScale = 1;
if (bird.growScale < 1.7) {
// Limit max growth (1.7x original)
bird.growScale += 0.07;
bird.scaleX = bird.growScale;
bird.scaleY = bird.growScale;
}
coin.destroy();
coins.splice(i, 1);
continue;
}
}
// --- Update yachts ---
for (var j = yachts.length - 1; j >= 0; j--) {
var yacht = yachts[j];
yacht.update();
// Off screen
if (yacht.x < -yacht.width) {
yacht.destroy();
yachts.splice(j, 1);
continue;
}
// Collision with bird (game over) - use yacht itself
if (yacht.intersects(bird)) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
return;
}
}
// (Timer update and win condition removed)
};
// --- Initial score and timer display ---
scoreTxt.setText('0');