/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Chick class: bounces, must be caught in nest or by Jason/Vixen
var Chick = Container.expand(function () {
var self = Container.call(this);
var chickSprite = self.attachAsset('chick', {
anchorX: 0.5,
anchorY: 0.5
});
self.vy = -12 - Math.random() * 4; // initial pop
self.vx = (Math.random() - 0.5) * 8;
self.isSafe = false;
self.update = function () {
if (!self.isSafe) {
self.vy += 0.7; // gravity
self.x += self.vx;
self.y += self.vy;
self.vx *= 0.98;
}
// Check if in nest
if (!self.isSafe && self.intersects(nest)) {
self.isSafe = true;
self.vx = 0;
self.vy = 0;
// Snap to nest
self.y = nest.y - nest.height / 2 + self.height / 2 + 10 + Math.random() * 20;
// Animate happy bounce
tween(self, {
y: self.y - 30
}, {
duration: 180,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 30
}, {
duration: 180,
easing: tween.easeIn
});
}
});
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
}
// If falls off screen
if (self.y > 2732 + 100) {
// Game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
};
return self;
});
// Egg class: can be juggled, hatches into chick after timer
var Egg = Container.expand(function () {
var self = Container.call(this);
var eggSprite = self.attachAsset('egg', {
anchorX: 0.5,
anchorY: 0.5
});
self.vy = 0;
self.vx = 0;
self.hatchTime = 180 + Math.floor(Math.random() * 120); // 3-5 seconds
self.age = 0;
self.isHeld = false;
self.isHatched = false;
self.update = function () {
if (!self.isHeld) {
self.vy += 0.7; // gravity
self.x += self.vx;
self.y += self.vy;
// friction
self.vx *= 0.98;
}
self.age++;
if (!self.isHatched && self.age > self.hatchTime) {
self.hatch();
}
};
self.hatch = function () {
if (self.isHatched) return;
self.isHatched = true;
// Spawn chick at this position
var chick = new Chick();
chick.x = self.x;
chick.y = self.y;
chicks.push(chick);
game.addChild(chick);
// Animate egg fade out
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.destroy();
eggs.splice(eggs.indexOf(self), 1);
}
});
};
return self;
});
// Fire class: moves horizontally, burns eggs/chicks
var Fire = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('fire', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 12 + Math.random() * 8;
self.life = 90;
self.update = function () {
self.x += self.vx;
self.life--;
// Burn eggs
for (var i = eggs.length - 1; i >= 0; i--) {
var egg = eggs[i];
if (self.intersects(egg)) {
// Burn egg
tween(egg, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
egg.destroy();
eggs.splice(eggs.indexOf(egg), 1);
}
});
}
}
// Burn chicks
for (var i = chicks.length - 1; i >= 0; i--) {
var chick = chicks[i];
if (!chick.isSafe && self.intersects(chick)) {
// Burn chick
tween(chick, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
chick.destroy();
chicks.splice(chicks.indexOf(chick), 1);
}
});
// Game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
}
if (self.life <= 0 || self.x > 2048 + 100) {
self.destroy();
fires.splice(fires.indexOf(self), 1);
}
};
return self;
});
// Jason class: draggable, can catch eggs/chicks
var Jason = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('jason', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDragging = false;
self.down = function (x, y, obj) {
self.isDragging = true;
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
return self;
});
// Nest class: static, eggs/chicks must land here
var Nest = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('nest', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Vixen class: draggable, sometimes emits fire
var Vixen = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('vixen', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDragging = false;
self.fireTimer = 0;
self.down = function (x, y, obj) {
self.isDragging = true;
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
self.update = function () {
// Randomly emit fire every 3-6 seconds
self.fireTimer++;
if (self.fireTimer > 180 + Math.floor(Math.random() * 180)) {
self.fireTimer = 0;
self.emitFire();
}
};
self.emitFire = function () {
var fire = new Fire();
fire.x = self.x + 80;
fire.y = self.y;
fires.push(fire);
game.addChild(fire);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf7e7b6
});
/****
* Game Code
****/
// Jason the Crow (gray box), Vixen the Phoenix (orange ellipse), Egg (white ellipse), Chick (yellow ellipse), Nest (brown ellipse), Fire (red ellipse)
// Main arrays
var eggs = [];
var chicks = [];
var fires = [];
// Create nest at bottom center
var nest = new Nest();
nest.x = 2048 / 2;
nest.y = 2732 - 220;
game.addChild(nest);
// Create Jason and Vixen
var jason = new Jason();
jason.x = 2048 / 2 - 220;
jason.y = nest.y - 180;
game.addChild(jason);
var vixen = new Vixen();
vixen.x = 2048 / 2 + 220;
vixen.y = nest.y - 180;
game.addChild(vixen);
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Spawn initial eggs
function spawnEgg() {
var egg = new Egg();
// Place above nest, random offset
egg.x = nest.x + (Math.random() - 0.5) * 220;
egg.y = nest.y - 220 - Math.random() * 80;
eggs.push(egg);
game.addChild(egg);
}
for (var i = 0; i < 3; i++) spawnEgg();
// Dragging logic
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Check if Jason or Vixen pressed
var localJason = jason.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localJason.x) < jason.width / 2 && Math.abs(localJason.y) < jason.height / 2) {
dragNode = jason;
jason.isDragging = true;
return;
}
var localVixen = vixen.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localVixen.x) < vixen.width / 2 && Math.abs(localVixen.y) < vixen.height / 2) {
dragNode = vixen;
vixen.isDragging = true;
return;
}
// Check for eggs
for (var i = eggs.length - 1; i >= 0; i--) {
var egg = eggs[i];
var localEgg = egg.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localEgg.x) < egg.width / 2 && Math.abs(localEgg.y) < egg.height / 2) {
dragNode = egg;
egg.isHeld = true;
egg.vx = 0;
egg.vy = 0;
return;
}
}
// Check for chicks
for (var i = chicks.length - 1; i >= 0; i--) {
var chick = chicks[i];
if (chick.isSafe) continue;
var localChick = chick.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localChick.x) < chick.width / 2 && Math.abs(localChick.y) < chick.height / 2) {
dragNode = chick;
chick.vx = 0;
chick.vy = 0;
return;
}
}
};
game.up = function (x, y, obj) {
if (dragNode) {
// If egg or chick, throw with velocity
if (eggs.indexOf(dragNode) >= 0) {
var egg = dragNode;
egg.isHeld = false;
egg.vx = (Math.random() - 0.5) * 8;
egg.vy = -8 - Math.random() * 4;
}
if (chicks.indexOf(dragNode) >= 0) {
var chick = dragNode;
chick.vx = (Math.random() - 0.5) * 8;
chick.vy = -8 - Math.random() * 4;
}
if (dragNode == jason) jason.isDragging = false;
if (dragNode == vixen) vixen.isDragging = false;
dragNode = null;
}
};
// Game update
var eggSpawnTimer = 0;
game.update = function () {
// Update eggs
for (var i = eggs.length - 1; i >= 0; i--) {
eggs[i].update();
// If egg falls off screen
if (eggs[i].y > 2732 + 100) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
// If egg lands in nest, stop movement
if (!eggs[i].isHeld && eggs[i].vy > 0 && eggs[i].intersects(nest)) {
eggs[i].y = nest.y - nest.height / 2 + eggs[i].height / 2 + 10 + Math.random() * 20;
eggs[i].vx = 0;
eggs[i].vy = 0;
}
// If egg lands on Jason or Vixen, stop movement
if (!eggs[i].isHeld && (eggs[i].intersects(jason) || eggs[i].intersects(vixen))) {
eggs[i].vx = 0;
eggs[i].vy = 0;
}
}
// Update chicks
for (var i = chicks.length - 1; i >= 0; i--) {
chicks[i].update();
// If chick lands on Jason or Vixen, bounce up
if (!chicks[i].isSafe && (chicks[i].intersects(jason) || chicks[i].intersects(vixen))) {
chicks[i].vy = -10 - Math.random() * 4;
chicks[i].vx = (Math.random() - 0.5) * 8;
}
}
// Update fires
for (var i = fires.length - 1; i >= 0; i--) {
fires[i].update();
}
// Update Vixen
vixen.update && vixen.update();
// Egg spawn logic: spawn new egg every 3-5 seconds, max 5 eggs
eggSpawnTimer++;
if (eggSpawnTimer > 180 + Math.floor(Math.random() * 120) && eggs.length < 5) {
eggSpawnTimer = 0;
spawnEgg();
}
// Win condition: 10 chicks safe
var safeChicks = 0;
for (var i = 0; i < chicks.length; i++) if (chicks[i].isSafe) safeChicks++;
if (safeChicks >= 10) {
LK.showYouWin();
}
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Chick class: bounces, must be caught in nest or by Jason/Vixen
var Chick = Container.expand(function () {
var self = Container.call(this);
var chickSprite = self.attachAsset('chick', {
anchorX: 0.5,
anchorY: 0.5
});
self.vy = -12 - Math.random() * 4; // initial pop
self.vx = (Math.random() - 0.5) * 8;
self.isSafe = false;
self.update = function () {
if (!self.isSafe) {
self.vy += 0.7; // gravity
self.x += self.vx;
self.y += self.vy;
self.vx *= 0.98;
}
// Check if in nest
if (!self.isSafe && self.intersects(nest)) {
self.isSafe = true;
self.vx = 0;
self.vy = 0;
// Snap to nest
self.y = nest.y - nest.height / 2 + self.height / 2 + 10 + Math.random() * 20;
// Animate happy bounce
tween(self, {
y: self.y - 30
}, {
duration: 180,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 30
}, {
duration: 180,
easing: tween.easeIn
});
}
});
LK.setScore(LK.getScore() + 1);
scoreTxt.setText(LK.getScore());
}
// If falls off screen
if (self.y > 2732 + 100) {
// Game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
};
return self;
});
// Egg class: can be juggled, hatches into chick after timer
var Egg = Container.expand(function () {
var self = Container.call(this);
var eggSprite = self.attachAsset('egg', {
anchorX: 0.5,
anchorY: 0.5
});
self.vy = 0;
self.vx = 0;
self.hatchTime = 180 + Math.floor(Math.random() * 120); // 3-5 seconds
self.age = 0;
self.isHeld = false;
self.isHatched = false;
self.update = function () {
if (!self.isHeld) {
self.vy += 0.7; // gravity
self.x += self.vx;
self.y += self.vy;
// friction
self.vx *= 0.98;
}
self.age++;
if (!self.isHatched && self.age > self.hatchTime) {
self.hatch();
}
};
self.hatch = function () {
if (self.isHatched) return;
self.isHatched = true;
// Spawn chick at this position
var chick = new Chick();
chick.x = self.x;
chick.y = self.y;
chicks.push(chick);
game.addChild(chick);
// Animate egg fade out
tween(self, {
alpha: 0
}, {
duration: 400,
onFinish: function onFinish() {
self.destroy();
eggs.splice(eggs.indexOf(self), 1);
}
});
};
return self;
});
// Fire class: moves horizontally, burns eggs/chicks
var Fire = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('fire', {
anchorX: 0.5,
anchorY: 0.5
});
self.vx = 12 + Math.random() * 8;
self.life = 90;
self.update = function () {
self.x += self.vx;
self.life--;
// Burn eggs
for (var i = eggs.length - 1; i >= 0; i--) {
var egg = eggs[i];
if (self.intersects(egg)) {
// Burn egg
tween(egg, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
egg.destroy();
eggs.splice(eggs.indexOf(egg), 1);
}
});
}
}
// Burn chicks
for (var i = chicks.length - 1; i >= 0; i--) {
var chick = chicks[i];
if (!chick.isSafe && self.intersects(chick)) {
// Burn chick
tween(chick, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
chick.destroy();
chicks.splice(chicks.indexOf(chick), 1);
}
});
// Game over
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
}
if (self.life <= 0 || self.x > 2048 + 100) {
self.destroy();
fires.splice(fires.indexOf(self), 1);
}
};
return self;
});
// Jason class: draggable, can catch eggs/chicks
var Jason = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('jason', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDragging = false;
self.down = function (x, y, obj) {
self.isDragging = true;
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
return self;
});
// Nest class: static, eggs/chicks must land here
var Nest = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('nest', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Vixen class: draggable, sometimes emits fire
var Vixen = Container.expand(function () {
var self = Container.call(this);
var sprite = self.attachAsset('vixen', {
anchorX: 0.5,
anchorY: 0.5
});
self.isDragging = false;
self.fireTimer = 0;
self.down = function (x, y, obj) {
self.isDragging = true;
};
self.up = function (x, y, obj) {
self.isDragging = false;
};
self.update = function () {
// Randomly emit fire every 3-6 seconds
self.fireTimer++;
if (self.fireTimer > 180 + Math.floor(Math.random() * 180)) {
self.fireTimer = 0;
self.emitFire();
}
};
self.emitFire = function () {
var fire = new Fire();
fire.x = self.x + 80;
fire.y = self.y;
fires.push(fire);
game.addChild(fire);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf7e7b6
});
/****
* Game Code
****/
// Jason the Crow (gray box), Vixen the Phoenix (orange ellipse), Egg (white ellipse), Chick (yellow ellipse), Nest (brown ellipse), Fire (red ellipse)
// Main arrays
var eggs = [];
var chicks = [];
var fires = [];
// Create nest at bottom center
var nest = new Nest();
nest.x = 2048 / 2;
nest.y = 2732 - 220;
game.addChild(nest);
// Create Jason and Vixen
var jason = new Jason();
jason.x = 2048 / 2 - 220;
jason.y = nest.y - 180;
game.addChild(jason);
var vixen = new Vixen();
vixen.x = 2048 / 2 + 220;
vixen.y = nest.y - 180;
game.addChild(vixen);
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: "#222"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Spawn initial eggs
function spawnEgg() {
var egg = new Egg();
// Place above nest, random offset
egg.x = nest.x + (Math.random() - 0.5) * 220;
egg.y = nest.y - 220 - Math.random() * 80;
eggs.push(egg);
game.addChild(egg);
}
for (var i = 0; i < 3; i++) spawnEgg();
// Dragging logic
var dragNode = null;
function handleMove(x, y, obj) {
if (dragNode) {
dragNode.x = x;
dragNode.y = y;
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
// Check if Jason or Vixen pressed
var localJason = jason.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localJason.x) < jason.width / 2 && Math.abs(localJason.y) < jason.height / 2) {
dragNode = jason;
jason.isDragging = true;
return;
}
var localVixen = vixen.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localVixen.x) < vixen.width / 2 && Math.abs(localVixen.y) < vixen.height / 2) {
dragNode = vixen;
vixen.isDragging = true;
return;
}
// Check for eggs
for (var i = eggs.length - 1; i >= 0; i--) {
var egg = eggs[i];
var localEgg = egg.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localEgg.x) < egg.width / 2 && Math.abs(localEgg.y) < egg.height / 2) {
dragNode = egg;
egg.isHeld = true;
egg.vx = 0;
egg.vy = 0;
return;
}
}
// Check for chicks
for (var i = chicks.length - 1; i >= 0; i--) {
var chick = chicks[i];
if (chick.isSafe) continue;
var localChick = chick.toLocal(game.toGlobal({
x: x,
y: y
}));
if (Math.abs(localChick.x) < chick.width / 2 && Math.abs(localChick.y) < chick.height / 2) {
dragNode = chick;
chick.vx = 0;
chick.vy = 0;
return;
}
}
};
game.up = function (x, y, obj) {
if (dragNode) {
// If egg or chick, throw with velocity
if (eggs.indexOf(dragNode) >= 0) {
var egg = dragNode;
egg.isHeld = false;
egg.vx = (Math.random() - 0.5) * 8;
egg.vy = -8 - Math.random() * 4;
}
if (chicks.indexOf(dragNode) >= 0) {
var chick = dragNode;
chick.vx = (Math.random() - 0.5) * 8;
chick.vy = -8 - Math.random() * 4;
}
if (dragNode == jason) jason.isDragging = false;
if (dragNode == vixen) vixen.isDragging = false;
dragNode = null;
}
};
// Game update
var eggSpawnTimer = 0;
game.update = function () {
// Update eggs
for (var i = eggs.length - 1; i >= 0; i--) {
eggs[i].update();
// If egg falls off screen
if (eggs[i].y > 2732 + 100) {
LK.effects.flashScreen(0xff0000, 800);
LK.showGameOver();
}
// If egg lands in nest, stop movement
if (!eggs[i].isHeld && eggs[i].vy > 0 && eggs[i].intersects(nest)) {
eggs[i].y = nest.y - nest.height / 2 + eggs[i].height / 2 + 10 + Math.random() * 20;
eggs[i].vx = 0;
eggs[i].vy = 0;
}
// If egg lands on Jason or Vixen, stop movement
if (!eggs[i].isHeld && (eggs[i].intersects(jason) || eggs[i].intersects(vixen))) {
eggs[i].vx = 0;
eggs[i].vy = 0;
}
}
// Update chicks
for (var i = chicks.length - 1; i >= 0; i--) {
chicks[i].update();
// If chick lands on Jason or Vixen, bounce up
if (!chicks[i].isSafe && (chicks[i].intersects(jason) || chicks[i].intersects(vixen))) {
chicks[i].vy = -10 - Math.random() * 4;
chicks[i].vx = (Math.random() - 0.5) * 8;
}
}
// Update fires
for (var i = fires.length - 1; i >= 0; i--) {
fires[i].update();
}
// Update Vixen
vixen.update && vixen.update();
// Egg spawn logic: spawn new egg every 3-5 seconds, max 5 eggs
eggSpawnTimer++;
if (eggSpawnTimer > 180 + Math.floor(Math.random() * 120) && eggs.length < 5) {
eggSpawnTimer = 0;
spawnEgg();
}
// Win condition: 10 chicks safe
var safeChicks = 0;
for (var i = 0; i < chicks.length; i++) if (chicks[i].isSafe) safeChicks++;
if (safeChicks >= 10) {
LK.showYouWin();
}
};