/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Bird class var Bird = Container.expand(function () { var self = Container.call(this); // Attach asset (birdType: 'falcon', 'eagle', 'chough') self.init = function (birdType) { self.birdType = birdType; self.asset = self.attachAsset(birdType, { anchorX: 0.5, anchorY: 0.5 }); self.hasApple = false; self.cooldown = 0; // Used for apple rejection self.name = ''; }; // Called every tick self.update = function () { // Cooldown for apple rejection if (self.cooldown > 0) self.cooldown--; }; // Called when bird grabs the apple self.grabApple = function () { self.hasApple = true; self.cooldown = 60; // 1 second cooldown before apple can reject LK.getSound('grab').play(); }; // Called when bird loses the apple self.loseApple = function () { self.hasApple = false; self.cooldown = 30; // Short cooldown before can grab again }; return self; }); // Apple class var MagicApple = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('magicApple', { anchorX: 0.5, anchorY: 0.5 }); self.holder = null; // Bird currently holding the apple self.state = 'idle'; // 'idle', 'held', 'moving' self.timer = 0; // Used for random events // Called every tick self.update = function () { // If held, follow the bird if (self.holder) { // Tween apple to bird's position for smoothness tween(self, { x: self.holder.x, y: self.holder.y - 90 }, { duration: 120, easing: tween.easeOut }); self.state = 'held'; self.timer++; // If held too long, apple may reject if (self.timer > 180 && self.holder.cooldown === 0) { // 3 seconds // 50% chance to reject if (LK.ticks % 60 === 0 && Math.random() < 0.5) { self.rejectHolder(); } } } else { self.state = 'idle'; self.timer = 0; } }; // Called when a bird tries to grab the apple self.tryGrab = function (bird) { if (self.holder === null && bird.cooldown === 0) { self.holder = bird; bird.grabApple(); self.timer = 0; } }; // Apple rejects the current holder self.rejectHolder = function () { if (self.holder) { LK.getSound('reject').play(); // Apple jumps away to a random position var oldHolder = self.holder; oldHolder.loseApple(); self.holder = null; self.state = 'moving'; var newX = 400 + Math.random() * 1248; var newY = 800 + Math.random() * 1200; tween(self, { x: newX, y: newY }, { duration: 500, easing: tween.bounceOut, onFinish: function onFinish() { self.state = 'idle'; } }); // Flash apple yellow tween(self.asset, { tint: 0xffff00 }, { duration: 200, onFinish: function onFinish() { tween(self.asset, { tint: 0xff2d55 }, { duration: 200 }); } }); } }; // Called when a bird loses the apple (e.g. another bird grabs it) self.loseApple = function () { if (self.holder) { self.holder.loseApple(); self.holder = null; self.state = 'idle'; self.timer = 0; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xfbeee0 // Desert sand color }); /**** * Game Code ****/ // Music (background, optional) // Sound effects // Sand Dune asset (background flavor, not interactive) // Apple asset (magical apple) // Bird assets (three birds, each a different color and shape) // Play background music LK.playMusic('desertTune'); // Add some dunes for flavor (not interactive) for (var i = 0; i < 4; i++) { var dune = LK.getAsset('dune', { anchorX: 0.5, anchorY: 0.5, x: 400 + i * 400, y: 2200 + Math.random() * 200, scaleX: 1 + Math.random() * 0.5, scaleY: 1 + Math.random() * 0.3 }); game.addChild(dune); } // Bird names var birdNames = [{ type: 'falcon', name: 'Richard' }, { type: 'eagle', name: 'Geoffrey' }, { type: 'chough', name: 'Quinn' }]; // Bird starting positions (spread horizontally) var birdStartX = [600, 1024, 1448]; var birdStartY = [2000, 2100, 2000]; // Create birds var birds = []; for (var i = 0; i < 3; i++) { var bird = new Bird(); bird.init(birdNames[i].type); bird.x = birdStartX[i]; bird.y = birdStartY[i]; bird.name = birdNames[i].name; birds.push(bird); game.addChild(bird); // Add name label above each bird var nameTxt = new Text2(bird.name, { size: 60, fill: 0x222222 }); nameTxt.anchor.set(0.5, 1); nameTxt.x = 0; nameTxt.y = -70; bird.addChild(nameTxt); } // Create the magic apple, place at center var apple = new MagicApple(); apple.x = 1024; apple.y = 1200; game.addChild(apple); // Scoreboard (shows who is holding the apple) var statusTxt = new Text2('Grab the magical apple!', { size: 90, fill: 0xD35400 }); statusTxt.anchor.set(0.5, 0); LK.gui.top.addChild(statusTxt); // Timer for win condition var winTimer = 0; var WIN_HOLD_TIME = 300; // 5 seconds // Track dragging var dragBird = null; // Helper: get which bird is at (x, y) function getBirdAt(x, y) { for (var i = 0; i < birds.length; i++) { var b = birds[i]; // Use bounding box for hit test var dx = x - b.x; var dy = y - b.y; if (Math.abs(dx) < b.asset.width / 2 && Math.abs(dy) < b.asset.height / 2) { return b; } } return null; } // Helper: clamp position to game area function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } // Main move handler (drag birds) function handleMove(x, y, obj) { if (dragBird) { // Clamp to game area (leave 100px margin) dragBird.x = clamp(x, 100, 1948); dragBird.y = clamp(y, 400, 2200); // If not holding apple, check for apple grab if (!dragBird.hasApple && apple.holder === null && dragBird.cooldown === 0) { // If close enough to apple var dx = dragBird.x - apple.x; var dy = dragBird.y - apple.y; if (dx * dx + dy * dy < 120 * 120) { apple.tryGrab(dragBird); } } // If another bird is holding apple, and this bird collides, steal! if (apple.holder && apple.holder !== dragBird && dragBird.cooldown === 0) { var dx2 = dragBird.x - apple.x; var dy2 = dragBird.y - apple.y; if (dx2 * dx2 + dy2 * dy2 < 120 * 120) { // Steal apple apple.loseApple(); apple.tryGrab(dragBird); } } } } // Touch/mouse down: start dragging a bird game.down = function (x, y, obj) { var b = getBirdAt(x, y); if (b) { dragBird = b; handleMove(x, y, obj); } }; // Touch/mouse up: stop dragging game.up = function (x, y, obj) { dragBird = null; }; // Touch/mouse move game.move = handleMove; // Main game update game.update = function () { // Update birds for (var i = 0; i < birds.length; i++) { birds[i].update(); } // Update apple apple.update(); // Update status text if (apple.holder) { statusTxt.setText(apple.holder.name + " is holding the apple!"); // Win timer winTimer++; // If held for WIN_HOLD_TIME, win! if (winTimer >= WIN_HOLD_TIME) { LK.effects.flashScreen(0x00ff00, 800); LK.showYouWin(); } } else { statusTxt.setText('Grab the magical apple!'); winTimer = 0; } }; // On game over or win, everything resets automatically by LK
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bird class
var Bird = Container.expand(function () {
var self = Container.call(this);
// Attach asset (birdType: 'falcon', 'eagle', 'chough')
self.init = function (birdType) {
self.birdType = birdType;
self.asset = self.attachAsset(birdType, {
anchorX: 0.5,
anchorY: 0.5
});
self.hasApple = false;
self.cooldown = 0; // Used for apple rejection
self.name = '';
};
// Called every tick
self.update = function () {
// Cooldown for apple rejection
if (self.cooldown > 0) self.cooldown--;
};
// Called when bird grabs the apple
self.grabApple = function () {
self.hasApple = true;
self.cooldown = 60; // 1 second cooldown before apple can reject
LK.getSound('grab').play();
};
// Called when bird loses the apple
self.loseApple = function () {
self.hasApple = false;
self.cooldown = 30; // Short cooldown before can grab again
};
return self;
});
// Apple class
var MagicApple = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('magicApple', {
anchorX: 0.5,
anchorY: 0.5
});
self.holder = null; // Bird currently holding the apple
self.state = 'idle'; // 'idle', 'held', 'moving'
self.timer = 0; // Used for random events
// Called every tick
self.update = function () {
// If held, follow the bird
if (self.holder) {
// Tween apple to bird's position for smoothness
tween(self, {
x: self.holder.x,
y: self.holder.y - 90
}, {
duration: 120,
easing: tween.easeOut
});
self.state = 'held';
self.timer++;
// If held too long, apple may reject
if (self.timer > 180 && self.holder.cooldown === 0) {
// 3 seconds
// 50% chance to reject
if (LK.ticks % 60 === 0 && Math.random() < 0.5) {
self.rejectHolder();
}
}
} else {
self.state = 'idle';
self.timer = 0;
}
};
// Called when a bird tries to grab the apple
self.tryGrab = function (bird) {
if (self.holder === null && bird.cooldown === 0) {
self.holder = bird;
bird.grabApple();
self.timer = 0;
}
};
// Apple rejects the current holder
self.rejectHolder = function () {
if (self.holder) {
LK.getSound('reject').play();
// Apple jumps away to a random position
var oldHolder = self.holder;
oldHolder.loseApple();
self.holder = null;
self.state = 'moving';
var newX = 400 + Math.random() * 1248;
var newY = 800 + Math.random() * 1200;
tween(self, {
x: newX,
y: newY
}, {
duration: 500,
easing: tween.bounceOut,
onFinish: function onFinish() {
self.state = 'idle';
}
});
// Flash apple yellow
tween(self.asset, {
tint: 0xffff00
}, {
duration: 200,
onFinish: function onFinish() {
tween(self.asset, {
tint: 0xff2d55
}, {
duration: 200
});
}
});
}
};
// Called when a bird loses the apple (e.g. another bird grabs it)
self.loseApple = function () {
if (self.holder) {
self.holder.loseApple();
self.holder = null;
self.state = 'idle';
self.timer = 0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfbeee0 // Desert sand color
});
/****
* Game Code
****/
// Music (background, optional)
// Sound effects
// Sand Dune asset (background flavor, not interactive)
// Apple asset (magical apple)
// Bird assets (three birds, each a different color and shape)
// Play background music
LK.playMusic('desertTune');
// Add some dunes for flavor (not interactive)
for (var i = 0; i < 4; i++) {
var dune = LK.getAsset('dune', {
anchorX: 0.5,
anchorY: 0.5,
x: 400 + i * 400,
y: 2200 + Math.random() * 200,
scaleX: 1 + Math.random() * 0.5,
scaleY: 1 + Math.random() * 0.3
});
game.addChild(dune);
}
// Bird names
var birdNames = [{
type: 'falcon',
name: 'Richard'
}, {
type: 'eagle',
name: 'Geoffrey'
}, {
type: 'chough',
name: 'Quinn'
}];
// Bird starting positions (spread horizontally)
var birdStartX = [600, 1024, 1448];
var birdStartY = [2000, 2100, 2000];
// Create birds
var birds = [];
for (var i = 0; i < 3; i++) {
var bird = new Bird();
bird.init(birdNames[i].type);
bird.x = birdStartX[i];
bird.y = birdStartY[i];
bird.name = birdNames[i].name;
birds.push(bird);
game.addChild(bird);
// Add name label above each bird
var nameTxt = new Text2(bird.name, {
size: 60,
fill: 0x222222
});
nameTxt.anchor.set(0.5, 1);
nameTxt.x = 0;
nameTxt.y = -70;
bird.addChild(nameTxt);
}
// Create the magic apple, place at center
var apple = new MagicApple();
apple.x = 1024;
apple.y = 1200;
game.addChild(apple);
// Scoreboard (shows who is holding the apple)
var statusTxt = new Text2('Grab the magical apple!', {
size: 90,
fill: 0xD35400
});
statusTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(statusTxt);
// Timer for win condition
var winTimer = 0;
var WIN_HOLD_TIME = 300; // 5 seconds
// Track dragging
var dragBird = null;
// Helper: get which bird is at (x, y)
function getBirdAt(x, y) {
for (var i = 0; i < birds.length; i++) {
var b = birds[i];
// Use bounding box for hit test
var dx = x - b.x;
var dy = y - b.y;
if (Math.abs(dx) < b.asset.width / 2 && Math.abs(dy) < b.asset.height / 2) {
return b;
}
}
return null;
}
// Helper: clamp position to game area
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
// Main move handler (drag birds)
function handleMove(x, y, obj) {
if (dragBird) {
// Clamp to game area (leave 100px margin)
dragBird.x = clamp(x, 100, 1948);
dragBird.y = clamp(y, 400, 2200);
// If not holding apple, check for apple grab
if (!dragBird.hasApple && apple.holder === null && dragBird.cooldown === 0) {
// If close enough to apple
var dx = dragBird.x - apple.x;
var dy = dragBird.y - apple.y;
if (dx * dx + dy * dy < 120 * 120) {
apple.tryGrab(dragBird);
}
}
// If another bird is holding apple, and this bird collides, steal!
if (apple.holder && apple.holder !== dragBird && dragBird.cooldown === 0) {
var dx2 = dragBird.x - apple.x;
var dy2 = dragBird.y - apple.y;
if (dx2 * dx2 + dy2 * dy2 < 120 * 120) {
// Steal apple
apple.loseApple();
apple.tryGrab(dragBird);
}
}
}
}
// Touch/mouse down: start dragging a bird
game.down = function (x, y, obj) {
var b = getBirdAt(x, y);
if (b) {
dragBird = b;
handleMove(x, y, obj);
}
};
// Touch/mouse up: stop dragging
game.up = function (x, y, obj) {
dragBird = null;
};
// Touch/mouse move
game.move = handleMove;
// Main game update
game.update = function () {
// Update birds
for (var i = 0; i < birds.length; i++) {
birds[i].update();
}
// Update apple
apple.update();
// Update status text
if (apple.holder) {
statusTxt.setText(apple.holder.name + " is holding the apple!");
// Win timer
winTimer++;
// If held for WIN_HOLD_TIME, win!
if (winTimer >= WIN_HOLD_TIME) {
LK.effects.flashScreen(0x00ff00, 800);
LK.showYouWin();
}
} else {
statusTxt.setText('Grab the magical apple!');
winTimer = 0;
}
};
// On game over or win, everything resets automatically by LK