/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Animal base class var Animal = Container.expand(function () { var self = Container.call(this); self.speed = 0; self.dir = 0; // in radians self.isDragging = false; self.name = ''; self.asset = null; self.radius = 0; // for collision self.actionCooldown = 0; // ticks until next action allowed // Move animal by its speed and direction self.moveStep = function () { if (self.isDragging) return; var dx = Math.cos(self.dir) * self.speed; var dy = Math.sin(self.dir) * self.speed; self.x += dx; self.y += dy; }; // Clamp animal inside stomach bounds (ellipse) self.clampInStomach = function (cx, cy, rx, ry) { var px = self.x - cx; var py = self.y - cy; var d = px * px / (rx * rx) + py * py / (ry * ry); if (d > 1) { var angle = Math.atan2(py, px); self.x = cx + Math.cos(angle) * rx * 0.95; self.y = cy + Math.sin(angle) * ry * 0.95; } }; // Called every tick self.update = function () { if (self.actionCooldown > 0) self.actionCooldown--; self.moveStep(); }; return self; }); // Peter the Pig var Pig = Animal.expand(function () { var self = Animal.call(this); self.name = 'Peter the Pig'; self.asset = self.attachAsset('pig', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.speed = 0; self.dir = 0; return self; }); // Ron the Mouse var Mouse = Animal.expand(function () { var self = Animal.call(this); self.name = 'Ron the Mouse'; self.asset = self.attachAsset('mouse', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.speed = 0; self.dir = 0; return self; }); // Mild the Lamb var Lamb = Animal.expand(function () { var self = Animal.call(this); self.name = 'Mild the Lamb'; self.asset = self.attachAsset('lamb', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.speed = 0; self.dir = 0; return self; }); // Zee the Bee var Bee = Animal.expand(function () { var self = Animal.call(this); self.name = 'Zee the Bee'; self.asset = self.attachAsset('bee', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; self.speed = 0; self.dir = 0; return self; }); // Oily Patch (hazard) var OilPatch = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('oil', { anchorX: 0.5, anchorY: 0.5 }); self.radius = self.asset.width / 2; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2d1e1b }); /**** * Game Code ****/ // Sound for action // Hope bar background and fill // Oily patch (hazard) // Olive's stomach (background) // Animal shapes (distinct colors for each) // Center of stomach var stomachCenterX = 2048 / 2; var stomachCenterY = 2732 / 2 + 100; // slightly lower for UI // Stomach ellipse radii var stomachRadiusX = 700; var stomachRadiusY = 950; // Add stomach background var stomachBg = LK.getAsset('stomach', { anchorX: 0.5, anchorY: 0.5, x: stomachCenterX, y: stomachCenterY }); game.addChild(stomachBg); // Animals array var animals = []; var pig = new Pig(); var bee = new Bee(); var mouse = new Mouse(); var lamb = new Lamb(); animals.push(pig, bee, mouse, lamb); // Initial positions (spread out) pig.x = stomachCenterX - 200; pig.y = stomachCenterY + 200; bee.x = stomachCenterX + 180; bee.y = stomachCenterY - 250; mouse.x = stomachCenterX - 120; mouse.y = stomachCenterY - 180; lamb.x = stomachCenterX + 150; lamb.y = stomachCenterY + 180; // Add animals to game for (var i = 0; i < animals.length; ++i) { game.addChild(animals[i]); } // Oily patches (hazards) var oilPatches = []; for (var i = 0; i < 3; ++i) { var oil = new OilPatch(); // Place randomly inside stomach var angle = Math.PI * 2 * (i / 3) + Math.random() * 0.5; var r = stomachRadiusX * 0.6 + Math.random() * stomachRadiusX * 0.2; oil.x = stomachCenterX + Math.cos(angle) * r; oil.y = stomachCenterY + Math.sin(angle) * stomachRadiusY * 0.5; oilPatches.push(oil); game.addChild(oil); } // Hope meter (depletes over time, game ends at 0) var hope = 100; // 0-100 var hopeBarBg = LK.getAsset('hopeBarBg', { anchorX: 0.5, anchorY: 0.5 }); var hopeBarFill = LK.getAsset('hopeBarFill', { anchorX: 0, anchorY: 0.5 }); hopeBarBg.x = 2048 / 2; hopeBarBg.y = 120; hopeBarFill.x = 2048 / 2 - 395; hopeBarFill.y = 120; LK.gui.top.addChild(hopeBarBg); LK.gui.top.addChild(hopeBarFill); // Hope text var hopeText = new Text2('Hope: 100', { size: 60, fill: '#ffffff' }); hopeText.anchor.set(0.5, 0.5); hopeText.x = 2048 / 2; hopeText.y = 200; LK.gui.top.addChild(hopeText); // Animal selection UI var selectedAnimal = pig; var animalNames = ['Pig', 'Bee', 'Mouse', 'Lamb']; var animalBtns = []; for (var i = 0; i < 4; ++i) { var btn = new Text2(animalNames[i], { size: 60, fill: '#fff' }); btn.anchor.set(0.5, 0.5); btn.x = 400 + i * 400; btn.y = 60; (function (idx) { btn.down = function (x, y, obj) { selectedAnimal = animals[idx]; for (var j = 0; j < animalBtns.length; ++j) { animalBtns[j].setStyle({ fill: '#fff' }); } btn.setStyle({ fill: '#6ad1e3' }); }; })(i); LK.gui.top.addChild(btn); animalBtns.push(btn); } animalBtns[0].setStyle({ fill: '#6ad1e3' }); // Dragging logic var dragNode = null; var dragOffsetX = 0; var dragOffsetY = 0; // Show animal name and action var actionText = new Text2('', { size: 60, fill: '#fff' }); actionText.anchor.set(0.5, 0.5); actionText.x = 2048 / 2; actionText.y = 260; LK.gui.top.addChild(actionText); // Helper: distance between two points function dist(ax, ay, bx, by) { var dx = ax - bx, dy = ay - by; return Math.sqrt(dx * dx + dy * dy); } // Helper: check collision with oil function isOnOil(animal) { for (var i = 0; i < oilPatches.length; ++i) { var oil = oilPatches[i]; if (dist(animal.x, animal.y, oil.x, oil.y) < oil.radius + animal.radius * 0.7) { return true; } } return false; } // Move handler: drag selected animal function handleMove(x, y, obj) { if (dragNode) { // Clamp to stomach bounds dragNode.x = x - dragOffsetX; dragNode.y = y - dragOffsetY; dragNode.clampInStomach(stomachCenterX, stomachCenterY, stomachRadiusX, stomachRadiusY); } } game.move = handleMove; // Down handler: start dragging selected animal if touched game.down = function (x, y, obj) { // Check if touch is on selected animal var a = selectedAnimal; var dx = x - a.x, dy = y - a.y; if (dx * dx + dy * dy < a.radius * a.radius) { dragNode = a; dragNode.isDragging = true; dragOffsetX = x - a.x; dragOffsetY = y - a.y; actionText.setText(a.name + ': Drag to move'); } }; game.up = function (x, y, obj) { if (dragNode) { dragNode.isDragging = false; actionText.setText(''); dragNode = null; } }; // Double tap for animal action (unique per animal) var lastTapTime = 0; var lastTapX = 0, lastTapY = 0; game.down = function (x, y, obj) { // Animal selection UI for (var i = 0; i < animalBtns.length; ++i) { var btn = animalBtns[i]; var bx = btn.x, by = btn.y; if (x > bx - 120 && x < bx + 120 && y > by - 40 && y < by + 40) { btn.down(x, y, obj); return; } } // Check if touch is on selected animal var a = selectedAnimal; var dx = x - a.x, dy = y - a.y; if (dx * dx + dy * dy < a.radius * a.radius) { var now = Date.now(); if (now - lastTapTime < 350 && dist(x, y, lastTapX, lastTapY) < 60) { // Double tap: perform animal action if (a.actionCooldown === 0) { performAnimalAction(a); a.actionCooldown = 60; // 1s cooldown } } else { // Start drag dragNode = a; dragNode.isDragging = true; dragOffsetX = x - a.x; dragOffsetY = y - a.y; actionText.setText(a.name + ': Drag to move'); } lastTapTime = now; lastTapX = x; lastTapY = y; } }; game.up = function (x, y, obj) { if (dragNode) { dragNode.isDragging = false; actionText.setText(''); dragNode = null; } }; // Animal unique actions function performAnimalAction(a) { if (a === pig) { // Pig: Squish forward (short dash) var angle = Math.random() * Math.PI * 2; a.dir = angle; a.speed = 28; tween(a, { speed: 0 }, { duration: 400, easing: tween.easeOut }); LK.getSound('squish').play(); actionText.setText('Peter the Pig: Squish!'); } else if (a === bee) { // Bee: Buzz and move randomly (teleport) var angle = Math.random() * Math.PI * 2; var r = Math.random() * stomachRadiusX * 0.7; a.x = stomachCenterX + Math.cos(angle) * r; a.y = stomachCenterY + Math.sin(angle) * stomachRadiusY * 0.7; LK.getSound('buzz').play(); actionText.setText('Zee the Bee: Buzz!'); } else if (a === mouse) { // Mouse: Squeeze through (move to edge) var angle = Math.atan2(a.y - stomachCenterY, a.x - stomachCenterX); a.x = stomachCenterX + Math.cos(angle) * stomachRadiusX * 0.92; a.y = stomachCenterY + Math.sin(angle) * stomachRadiusY * 0.92; LK.getSound('squeak').play(); actionText.setText('Ron the Mouse: Squeeze!'); } else if (a === lamb) { // Lamb: Baa, restore hope a little hope = Math.min(hope + 8, 100); LK.getSound('baa').play(); actionText.setText('Mild the Lamb: Baa! (+Hope)'); } } // Game update loop game.update = function () { // Update animals for (var i = 0; i < animals.length; ++i) { animals[i].update(); // Clamp inside stomach animals[i].clampInStomach(stomachCenterX, stomachCenterY, stomachRadiusX, stomachRadiusY); // Oil hazard: if on oil, slip and lose hope if (isOnOil(animals[i])) { if (!animals[i].onOil) { LK.getSound('slip').play(); animals[i].onOil = true; hope -= 2; LK.effects.flashObject(animals[i], 0x8c7c4a, 400); } } else { animals[i].onOil = false; } } // Hope drains slowly if (LK.ticks % 30 === 0) { hope -= 0.5; } if (hope < 0) hope = 0; // Update hope bar var fillW = Math.max(10, 790 * (hope / 100)); hopeBarFill.width = fillW; hopeText.setText('Hope: ' + Math.round(hope)); // Game over if hope is gone if (hope <= 0) { LK.effects.flashScreen(0x000000, 1200); LK.showGameOver(); } // Win condition: survive 120 seconds if (LK.ticks > 60 * 120) { LK.showYouWin(); } }; // Initial message actionText.setText('Drag an animal or double tap for action. Survive!');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Animal base class
var Animal = Container.expand(function () {
var self = Container.call(this);
self.speed = 0;
self.dir = 0; // in radians
self.isDragging = false;
self.name = '';
self.asset = null;
self.radius = 0; // for collision
self.actionCooldown = 0; // ticks until next action allowed
// Move animal by its speed and direction
self.moveStep = function () {
if (self.isDragging) return;
var dx = Math.cos(self.dir) * self.speed;
var dy = Math.sin(self.dir) * self.speed;
self.x += dx;
self.y += dy;
};
// Clamp animal inside stomach bounds (ellipse)
self.clampInStomach = function (cx, cy, rx, ry) {
var px = self.x - cx;
var py = self.y - cy;
var d = px * px / (rx * rx) + py * py / (ry * ry);
if (d > 1) {
var angle = Math.atan2(py, px);
self.x = cx + Math.cos(angle) * rx * 0.95;
self.y = cy + Math.sin(angle) * ry * 0.95;
}
};
// Called every tick
self.update = function () {
if (self.actionCooldown > 0) self.actionCooldown--;
self.moveStep();
};
return self;
});
// Peter the Pig
var Pig = Animal.expand(function () {
var self = Animal.call(this);
self.name = 'Peter the Pig';
self.asset = self.attachAsset('pig', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.asset.width / 2;
self.speed = 0;
self.dir = 0;
return self;
});
// Ron the Mouse
var Mouse = Animal.expand(function () {
var self = Animal.call(this);
self.name = 'Ron the Mouse';
self.asset = self.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.asset.width / 2;
self.speed = 0;
self.dir = 0;
return self;
});
// Mild the Lamb
var Lamb = Animal.expand(function () {
var self = Animal.call(this);
self.name = 'Mild the Lamb';
self.asset = self.attachAsset('lamb', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.asset.width / 2;
self.speed = 0;
self.dir = 0;
return self;
});
// Zee the Bee
var Bee = Animal.expand(function () {
var self = Animal.call(this);
self.name = 'Zee the Bee';
self.asset = self.attachAsset('bee', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.asset.width / 2;
self.speed = 0;
self.dir = 0;
return self;
});
// Oily Patch (hazard)
var OilPatch = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('oil', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = self.asset.width / 2;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d1e1b
});
/****
* Game Code
****/
// Sound for action
// Hope bar background and fill
// Oily patch (hazard)
// Olive's stomach (background)
// Animal shapes (distinct colors for each)
// Center of stomach
var stomachCenterX = 2048 / 2;
var stomachCenterY = 2732 / 2 + 100; // slightly lower for UI
// Stomach ellipse radii
var stomachRadiusX = 700;
var stomachRadiusY = 950;
// Add stomach background
var stomachBg = LK.getAsset('stomach', {
anchorX: 0.5,
anchorY: 0.5,
x: stomachCenterX,
y: stomachCenterY
});
game.addChild(stomachBg);
// Animals array
var animals = [];
var pig = new Pig();
var bee = new Bee();
var mouse = new Mouse();
var lamb = new Lamb();
animals.push(pig, bee, mouse, lamb);
// Initial positions (spread out)
pig.x = stomachCenterX - 200;
pig.y = stomachCenterY + 200;
bee.x = stomachCenterX + 180;
bee.y = stomachCenterY - 250;
mouse.x = stomachCenterX - 120;
mouse.y = stomachCenterY - 180;
lamb.x = stomachCenterX + 150;
lamb.y = stomachCenterY + 180;
// Add animals to game
for (var i = 0; i < animals.length; ++i) {
game.addChild(animals[i]);
}
// Oily patches (hazards)
var oilPatches = [];
for (var i = 0; i < 3; ++i) {
var oil = new OilPatch();
// Place randomly inside stomach
var angle = Math.PI * 2 * (i / 3) + Math.random() * 0.5;
var r = stomachRadiusX * 0.6 + Math.random() * stomachRadiusX * 0.2;
oil.x = stomachCenterX + Math.cos(angle) * r;
oil.y = stomachCenterY + Math.sin(angle) * stomachRadiusY * 0.5;
oilPatches.push(oil);
game.addChild(oil);
}
// Hope meter (depletes over time, game ends at 0)
var hope = 100; // 0-100
var hopeBarBg = LK.getAsset('hopeBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
var hopeBarFill = LK.getAsset('hopeBarFill', {
anchorX: 0,
anchorY: 0.5
});
hopeBarBg.x = 2048 / 2;
hopeBarBg.y = 120;
hopeBarFill.x = 2048 / 2 - 395;
hopeBarFill.y = 120;
LK.gui.top.addChild(hopeBarBg);
LK.gui.top.addChild(hopeBarFill);
// Hope text
var hopeText = new Text2('Hope: 100', {
size: 60,
fill: '#ffffff'
});
hopeText.anchor.set(0.5, 0.5);
hopeText.x = 2048 / 2;
hopeText.y = 200;
LK.gui.top.addChild(hopeText);
// Animal selection UI
var selectedAnimal = pig;
var animalNames = ['Pig', 'Bee', 'Mouse', 'Lamb'];
var animalBtns = [];
for (var i = 0; i < 4; ++i) {
var btn = new Text2(animalNames[i], {
size: 60,
fill: '#fff'
});
btn.anchor.set(0.5, 0.5);
btn.x = 400 + i * 400;
btn.y = 60;
(function (idx) {
btn.down = function (x, y, obj) {
selectedAnimal = animals[idx];
for (var j = 0; j < animalBtns.length; ++j) {
animalBtns[j].setStyle({
fill: '#fff'
});
}
btn.setStyle({
fill: '#6ad1e3'
});
};
})(i);
LK.gui.top.addChild(btn);
animalBtns.push(btn);
}
animalBtns[0].setStyle({
fill: '#6ad1e3'
});
// Dragging logic
var dragNode = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Show animal name and action
var actionText = new Text2('', {
size: 60,
fill: '#fff'
});
actionText.anchor.set(0.5, 0.5);
actionText.x = 2048 / 2;
actionText.y = 260;
LK.gui.top.addChild(actionText);
// Helper: distance between two points
function dist(ax, ay, bx, by) {
var dx = ax - bx,
dy = ay - by;
return Math.sqrt(dx * dx + dy * dy);
}
// Helper: check collision with oil
function isOnOil(animal) {
for (var i = 0; i < oilPatches.length; ++i) {
var oil = oilPatches[i];
if (dist(animal.x, animal.y, oil.x, oil.y) < oil.radius + animal.radius * 0.7) {
return true;
}
}
return false;
}
// Move handler: drag selected animal
function handleMove(x, y, obj) {
if (dragNode) {
// Clamp to stomach bounds
dragNode.x = x - dragOffsetX;
dragNode.y = y - dragOffsetY;
dragNode.clampInStomach(stomachCenterX, stomachCenterY, stomachRadiusX, stomachRadiusY);
}
}
game.move = handleMove;
// Down handler: start dragging selected animal if touched
game.down = function (x, y, obj) {
// Check if touch is on selected animal
var a = selectedAnimal;
var dx = x - a.x,
dy = y - a.y;
if (dx * dx + dy * dy < a.radius * a.radius) {
dragNode = a;
dragNode.isDragging = true;
dragOffsetX = x - a.x;
dragOffsetY = y - a.y;
actionText.setText(a.name + ': Drag to move');
}
};
game.up = function (x, y, obj) {
if (dragNode) {
dragNode.isDragging = false;
actionText.setText('');
dragNode = null;
}
};
// Double tap for animal action (unique per animal)
var lastTapTime = 0;
var lastTapX = 0,
lastTapY = 0;
game.down = function (x, y, obj) {
// Animal selection UI
for (var i = 0; i < animalBtns.length; ++i) {
var btn = animalBtns[i];
var bx = btn.x,
by = btn.y;
if (x > bx - 120 && x < bx + 120 && y > by - 40 && y < by + 40) {
btn.down(x, y, obj);
return;
}
}
// Check if touch is on selected animal
var a = selectedAnimal;
var dx = x - a.x,
dy = y - a.y;
if (dx * dx + dy * dy < a.radius * a.radius) {
var now = Date.now();
if (now - lastTapTime < 350 && dist(x, y, lastTapX, lastTapY) < 60) {
// Double tap: perform animal action
if (a.actionCooldown === 0) {
performAnimalAction(a);
a.actionCooldown = 60; // 1s cooldown
}
} else {
// Start drag
dragNode = a;
dragNode.isDragging = true;
dragOffsetX = x - a.x;
dragOffsetY = y - a.y;
actionText.setText(a.name + ': Drag to move');
}
lastTapTime = now;
lastTapX = x;
lastTapY = y;
}
};
game.up = function (x, y, obj) {
if (dragNode) {
dragNode.isDragging = false;
actionText.setText('');
dragNode = null;
}
};
// Animal unique actions
function performAnimalAction(a) {
if (a === pig) {
// Pig: Squish forward (short dash)
var angle = Math.random() * Math.PI * 2;
a.dir = angle;
a.speed = 28;
tween(a, {
speed: 0
}, {
duration: 400,
easing: tween.easeOut
});
LK.getSound('squish').play();
actionText.setText('Peter the Pig: Squish!');
} else if (a === bee) {
// Bee: Buzz and move randomly (teleport)
var angle = Math.random() * Math.PI * 2;
var r = Math.random() * stomachRadiusX * 0.7;
a.x = stomachCenterX + Math.cos(angle) * r;
a.y = stomachCenterY + Math.sin(angle) * stomachRadiusY * 0.7;
LK.getSound('buzz').play();
actionText.setText('Zee the Bee: Buzz!');
} else if (a === mouse) {
// Mouse: Squeeze through (move to edge)
var angle = Math.atan2(a.y - stomachCenterY, a.x - stomachCenterX);
a.x = stomachCenterX + Math.cos(angle) * stomachRadiusX * 0.92;
a.y = stomachCenterY + Math.sin(angle) * stomachRadiusY * 0.92;
LK.getSound('squeak').play();
actionText.setText('Ron the Mouse: Squeeze!');
} else if (a === lamb) {
// Lamb: Baa, restore hope a little
hope = Math.min(hope + 8, 100);
LK.getSound('baa').play();
actionText.setText('Mild the Lamb: Baa! (+Hope)');
}
}
// Game update loop
game.update = function () {
// Update animals
for (var i = 0; i < animals.length; ++i) {
animals[i].update();
// Clamp inside stomach
animals[i].clampInStomach(stomachCenterX, stomachCenterY, stomachRadiusX, stomachRadiusY);
// Oil hazard: if on oil, slip and lose hope
if (isOnOil(animals[i])) {
if (!animals[i].onOil) {
LK.getSound('slip').play();
animals[i].onOil = true;
hope -= 2;
LK.effects.flashObject(animals[i], 0x8c7c4a, 400);
}
} else {
animals[i].onOil = false;
}
}
// Hope drains slowly
if (LK.ticks % 30 === 0) {
hope -= 0.5;
}
if (hope < 0) hope = 0;
// Update hope bar
var fillW = Math.max(10, 790 * (hope / 100));
hopeBarFill.width = fillW;
hopeText.setText('Hope: ' + Math.round(hope));
// Game over if hope is gone
if (hope <= 0) {
LK.effects.flashScreen(0x000000, 1200);
LK.showGameOver();
}
// Win condition: survive 120 seconds
if (LK.ticks > 60 * 120) {
LK.showYouWin();
}
};
// Initial message
actionText.setText('Drag an animal or double tap for action. Survive!');