/****
* 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');