/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Basket class
var Basket = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('basket', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Fruit class
var Fruit = Container.expand(function () {
var self = Container.call(this);
// Fruit types: apple, banana, orange, grape, golden, bomb
self.type = 'apple'; // default, will be set on creation
self.speed = 6; // will be set on creation
self.points = 1; // will be set on creation
// Attach asset based on type
self.setType = function (type) {
self.type = type;
if (self.asset) {
self.removeChild(self.asset);
}
var assetId = '';
if (type === 'apple') assetId = 'fruit_apple';else if (type === 'banana') assetId = 'fruit_banana';else if (type === 'orange') assetId = 'fruit_orange';else if (type === 'grape') assetId = 'fruit_grape';else if (type === 'golden') assetId = 'fruit_golden';else if (type === 'bomb') assetId = 'bomb';
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Music
// Sound effects
// Basket
// Bomb
// Fruits
// Game variables
var basket = null;
var fruits = [];
var score = 0;
var scoreTxt = null;
var dragNode = null;
var lastBasketX = 0;
var gameSpeed = 1;
var spawnInterval = 60; // ticks between spawns
var ticksSinceLastSpawn = 0;
var gameOver = false;
// Only bombs will fall!
var fruitTypes = [{
type: 'bomb',
weight: 1,
points: 0,
speed: 13
}];
// Helper: always pick bomb
function pickRandomFruitType() {
return fruitTypes[0];
}
// Helper: spawn a fruit as a meteor from left or right edge, moving diagonally
function spawnFruit() {
var fruitInfo = pickRandomFruitType();
var fruit = new Fruit();
fruit.setType(fruitInfo.type);
fruit.points = fruitInfo.points;
fruit.speed = fruitInfo.speed * gameSpeed;
// Decide spawn side: 0 = left, 1 = right
var side = Math.random() < 0.5 ? 0 : 1;
// Spawn from higher up: Y between -200 and 400
var minY = -200;
var maxY = 400;
fruit.y = minY + Math.random() * (maxY - minY);
// Set start and end X for diagonal movement
var marginX = 80;
if (side === 0) {
// Spawn from left edge, move right
fruit.x = -100;
fruit.targetX = 2048 + 100;
} else {
// Spawn from right edge, move left
fruit.x = 2048 + 100;
fruit.targetX = -100;
}
// Save start/end for update
fruit.startX = fruit.x;
fruit.startY = fruit.y;
fruit.endX = fruit.targetX;
// Calculate how many frames it will take to cross the screen
var dx = fruit.targetX - fruit.x;
var dy = 2732 + 200 - fruit.y; // go off bottom
var dist = Math.sqrt(dx * dx + dy * dy);
fruit.framesToCross = dist / fruit.speed;
fruit.frameCount = 0;
// Override update for diagonal movement
fruit.update = function () {
this.frameCount++;
var t = this.frameCount / this.framesToCross;
if (t > 1) t = 1;
// Linear interpolation
this.x = this.startX + (this.endX - this.startX) * t;
this.y = this.startY + (2732 + 200 - this.startY) * t;
};
fruits.push(fruit);
game.addChild(fruit);
}
// Score text
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Basket
basket = new Basket();
basket.x = 1024;
basket.y = 2732 - 120;
game.addChild(basket);
// Move handler for dragging basket
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp basket inside screen
var halfW = basket.asset.width / 2;
var minX = halfW;
var maxX = 2048 - halfW;
dragNode.x = Math.max(minX, Math.min(maxX, x));
}
}
game.move = handleMove;
// Down handler: start dragging if touch is on basket or near bottom
game.down = function (x, y, obj) {
// Only allow drag if touch is near basket (bottom 400px)
if (y > 2732 - 400) {
dragNode = basket;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Update function
game.update = function () {
if (gameOver) return;
// Increase game speed as time passes (bombs get faster over time)
if (!game.startTick) game.startTick = LK.ticks;
var elapsedSeconds = (LK.ticks - game.startTick) / 60;
gameSpeed = 1 + Math.min(1.5, elapsedSeconds * 0.07); // up to 2.5x after ~21s
// Spawn fruits
ticksSinceLastSpawn++;
var interval = Math.max(18, Math.floor(spawnInterval / gameSpeed));
if (ticksSinceLastSpawn >= interval) {
spawnFruit();
ticksSinceLastSpawn = 0;
}
// Update fruits
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
fruit.update();
// Check for collision with basket
if (fruit.intersects(basket)) {
if (fruit.type === 'bomb') {
// Bomb caught: game over
LK.getSound('bomb').play();
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
LK.showGameOver();
return;
} else {
// Fruit caught
if (fruit.type === 'golden') {
LK.getSound('golden').play();
LK.effects.flashObject(basket, 0xffe700, 600);
} else {
LK.getSound('catch').play();
LK.effects.flashObject(basket, 0xffffff, 200);
}
score += fruit.points;
LK.setScore(score);
scoreTxt.setText(score);
// Remove fruit
fruit.destroy();
fruits.splice(i, 1);
continue;
}
}
// Missed fruit (not bomb): if it goes off screen (bottom or left/right)
if (fruit.y > 2732 + 120 || fruit.x < -150 || fruit.x > 2048 + 150) {
if (fruit.type !== 'bomb') {
// Missed a fruit: game over
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
LK.showGameOver();
return;
} else {
// Bomb missed: just remove
fruit.destroy();
fruits.splice(i, 1);
continue;
}
}
}
};
// Play background music
LK.playMusic('bgmusic'); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Basket class
var Basket = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('basket', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Fruit class
var Fruit = Container.expand(function () {
var self = Container.call(this);
// Fruit types: apple, banana, orange, grape, golden, bomb
self.type = 'apple'; // default, will be set on creation
self.speed = 6; // will be set on creation
self.points = 1; // will be set on creation
// Attach asset based on type
self.setType = function (type) {
self.type = type;
if (self.asset) {
self.removeChild(self.asset);
}
var assetId = '';
if (type === 'apple') assetId = 'fruit_apple';else if (type === 'banana') assetId = 'fruit_banana';else if (type === 'orange') assetId = 'fruit_orange';else if (type === 'grape') assetId = 'fruit_grape';else if (type === 'golden') assetId = 'fruit_golden';else if (type === 'bomb') assetId = 'bomb';
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.update = function () {
self.y += self.speed;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a1a
});
/****
* Game Code
****/
// Music
// Sound effects
// Basket
// Bomb
// Fruits
// Game variables
var basket = null;
var fruits = [];
var score = 0;
var scoreTxt = null;
var dragNode = null;
var lastBasketX = 0;
var gameSpeed = 1;
var spawnInterval = 60; // ticks between spawns
var ticksSinceLastSpawn = 0;
var gameOver = false;
// Only bombs will fall!
var fruitTypes = [{
type: 'bomb',
weight: 1,
points: 0,
speed: 13
}];
// Helper: always pick bomb
function pickRandomFruitType() {
return fruitTypes[0];
}
// Helper: spawn a fruit as a meteor from left or right edge, moving diagonally
function spawnFruit() {
var fruitInfo = pickRandomFruitType();
var fruit = new Fruit();
fruit.setType(fruitInfo.type);
fruit.points = fruitInfo.points;
fruit.speed = fruitInfo.speed * gameSpeed;
// Decide spawn side: 0 = left, 1 = right
var side = Math.random() < 0.5 ? 0 : 1;
// Spawn from higher up: Y between -200 and 400
var minY = -200;
var maxY = 400;
fruit.y = minY + Math.random() * (maxY - minY);
// Set start and end X for diagonal movement
var marginX = 80;
if (side === 0) {
// Spawn from left edge, move right
fruit.x = -100;
fruit.targetX = 2048 + 100;
} else {
// Spawn from right edge, move left
fruit.x = 2048 + 100;
fruit.targetX = -100;
}
// Save start/end for update
fruit.startX = fruit.x;
fruit.startY = fruit.y;
fruit.endX = fruit.targetX;
// Calculate how many frames it will take to cross the screen
var dx = fruit.targetX - fruit.x;
var dy = 2732 + 200 - fruit.y; // go off bottom
var dist = Math.sqrt(dx * dx + dy * dy);
fruit.framesToCross = dist / fruit.speed;
fruit.frameCount = 0;
// Override update for diagonal movement
fruit.update = function () {
this.frameCount++;
var t = this.frameCount / this.framesToCross;
if (t > 1) t = 1;
// Linear interpolation
this.x = this.startX + (this.endX - this.startX) * t;
this.y = this.startY + (2732 + 200 - this.startY) * t;
};
fruits.push(fruit);
game.addChild(fruit);
}
// Score text
scoreTxt = new Text2('0', {
size: 120,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Basket
basket = new Basket();
basket.x = 1024;
basket.y = 2732 - 120;
game.addChild(basket);
// Move handler for dragging basket
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp basket inside screen
var halfW = basket.asset.width / 2;
var minX = halfW;
var maxX = 2048 - halfW;
dragNode.x = Math.max(minX, Math.min(maxX, x));
}
}
game.move = handleMove;
// Down handler: start dragging if touch is on basket or near bottom
game.down = function (x, y, obj) {
// Only allow drag if touch is near basket (bottom 400px)
if (y > 2732 - 400) {
dragNode = basket;
handleMove(x, y, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// Update function
game.update = function () {
if (gameOver) return;
// Increase game speed as time passes (bombs get faster over time)
if (!game.startTick) game.startTick = LK.ticks;
var elapsedSeconds = (LK.ticks - game.startTick) / 60;
gameSpeed = 1 + Math.min(1.5, elapsedSeconds * 0.07); // up to 2.5x after ~21s
// Spawn fruits
ticksSinceLastSpawn++;
var interval = Math.max(18, Math.floor(spawnInterval / gameSpeed));
if (ticksSinceLastSpawn >= interval) {
spawnFruit();
ticksSinceLastSpawn = 0;
}
// Update fruits
for (var i = fruits.length - 1; i >= 0; i--) {
var fruit = fruits[i];
fruit.update();
// Check for collision with basket
if (fruit.intersects(basket)) {
if (fruit.type === 'bomb') {
// Bomb caught: game over
LK.getSound('bomb').play();
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
LK.showGameOver();
return;
} else {
// Fruit caught
if (fruit.type === 'golden') {
LK.getSound('golden').play();
LK.effects.flashObject(basket, 0xffe700, 600);
} else {
LK.getSound('catch').play();
LK.effects.flashObject(basket, 0xffffff, 200);
}
score += fruit.points;
LK.setScore(score);
scoreTxt.setText(score);
// Remove fruit
fruit.destroy();
fruits.splice(i, 1);
continue;
}
}
// Missed fruit (not bomb): if it goes off screen (bottom or left/right)
if (fruit.y > 2732 + 120 || fruit.x < -150 || fruit.x > 2048 + 150) {
if (fruit.type !== 'bomb') {
// Missed a fruit: game over
LK.effects.flashScreen(0xff0000, 800);
gameOver = true;
LK.showGameOver();
return;
} else {
// Bomb missed: just remove
fruit.destroy();
fruits.splice(i, 1);
continue;
}
}
}
};
// Play background music
LK.playMusic('bgmusic');