/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Acid hazard class
var Acid = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('acid', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = asset.width / 2;
// Acid moves in a wobbly path
self.vx = (Math.random() - 0.5) * 6;
self.vy = 2 + Math.random() * 2;
self.angle = Math.random() * Math.PI * 2;
self.amp = 30 + Math.random() * 30;
self.update = function () {
self.angle += 0.07;
self.x += self.vx + Math.sin(self.angle) * 1.5;
self.y += self.vy + Math.cos(self.angle) * 0.7;
};
return self;
});
// Animal class
var Animal = Container.expand(function () {
var self = Container.call(this);
// Properties: type, can be 'pig', 'bee', etc.
self.type = 'pig';
self.isEscaped = false;
// Attach asset
var asset = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
// For dragging
self.isDragging = false;
// For collision
self.radius = asset.width / 2;
// For movement
self.targetX = self.x;
self.targetY = self.y;
// Set animal type and update asset
self.setType = function (type) {
self.type = type;
asset.setAsset(type);
// Update radius
self.radius = asset.width / 2;
};
// Animate to a new position
self.moveTo = function (x, y) {
self.targetX = x;
self.targetY = y;
tween(self, {
x: x,
y: y
}, {
duration: 220,
easing: tween.easeOut,
onFinish: function onFinish() {
self.x = x;
self.y = y;
}
});
};
// Flash when hit
self.flash = function () {
LK.effects.flashObject(self, 0xff0000, 400);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfadadd // Light pink stomach color
});
/****
* Game Code
****/
// Sound for escape
// Sound for acid pop
// Sound for animal move
// Exit (esophagus opening)
// Digestive hazard (acid bubble)
// Stomach wall (background)
// Animal shapes (unique color for each)
// Center of the stomach
var stomachCenterX = 2048 / 2;
var stomachCenterY = 2732 / 2;
// Add stomach wall background
var stomachWall = LK.getAsset('stomachWall', {
anchorX: 0.5,
anchorY: 0.5,
x: stomachCenterX,
y: stomachCenterY
});
game.addChild(stomachWall);
// Add exit (esophagus opening) at the top center
var exitY = 350;
var exit = LK.getAsset('exit', {
anchorX: 0.5,
anchorY: 0.5,
x: stomachCenterX,
y: exitY
});
game.addChild(exit);
// Animal definitions
var animalTypes = [{
type: 'pig',
name: 'Peter the Pig'
}, {
type: 'bee',
name: 'Zee the Bee'
}, {
type: 'snake',
name: 'Marvin the Snake'
}, {
type: 'mouse',
name: 'Ron the Mouse'
}, {
type: 'lamb',
name: 'Mild the Lamb'
}, {
type: 'bunny',
name: 'Joy the Easter Bunny'
}];
// Store animals
var animals = [];
// Store acids
var acids = [];
// Track dragging
var dragAnimal = null;
// Track offset for dragging
var dragOffsetX = 0;
var dragOffsetY = 0;
// Track if game is won
var gameWon = false;
// Place animals in a circle in the stomach
var animalCircleRadius = 500;
for (var i = 0; i < animalTypes.length; i++) {
var a = new Animal();
a.setType(animalTypes[i].type);
// Place in a circle
var angle = Math.PI * 2 * i / animalTypes.length;
a.x = stomachCenterX + Math.cos(angle) * animalCircleRadius;
a.y = stomachCenterY + Math.sin(angle) * animalCircleRadius;
a.targetX = a.x;
a.targetY = a.y;
a.animalName = animalTypes[i].name;
a.isEscaped = false;
animals.push(a);
game.addChild(a);
}
// Acid spawn timer
var acidTimer = 0;
var acidInterval = 90; // frames
// Score: number of animals escaped
var score = 0;
// Score text
var scoreTxt = new Text2('Escaped: 0/6', {
size: 100,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Instructions text
var instrTxt = new Text2('Drag animals to the blue exit!\nAvoid the acid bubbles!', {
size: 60,
fill: 0x333333
});
instrTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(instrTxt);
instrTxt.y = 120;
// Helper: check circle collision
function circlesCollide(x1, y1, r1, x2, y2, r2) {
var dx = x1 - x2;
var dy = y1 - y2;
var dist = Math.sqrt(dx * dx + dy * dy);
return dist < r1 + r2 - 10; // -10 for a little overlap forgiveness
}
// Helper: keep inside stomach wall
function keepInsideStomach(animal) {
var dx = animal.x - stomachCenterX;
var dy = animal.y - stomachCenterY;
var stomachR = stomachWall.width / 2 - animal.radius - 10;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > stomachR) {
// Push back to edge
var angle = Math.atan2(dy, dx);
animal.x = stomachCenterX + Math.cos(angle) * stomachR;
animal.y = stomachCenterY + Math.sin(angle) * stomachR;
}
}
// Helper: prevent animal overlap
function resolveAnimalCollisions() {
for (var i = 0; i < animals.length; i++) {
var a1 = animals[i];
if (a1.isEscaped) continue;
for (var j = i + 1; j < animals.length; j++) {
var a2 = animals[j];
if (a2.isEscaped) continue;
var dx = a1.x - a2.x;
var dy = a1.y - a2.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var minDist = a1.radius + a2.radius - 8;
if (dist < minDist && dist > 0.1) {
// Push apart
var overlap = (minDist - dist) / 2;
var nx = dx / dist;
var ny = dy / dist;
a1.x += nx * overlap;
a1.y += ny * overlap;
a2.x -= nx * overlap;
a2.y -= ny * overlap;
}
}
}
}
// Dragging logic
game.down = function (x, y, obj) {
if (gameWon) return;
// Find topmost animal under pointer
for (var i = animals.length - 1; i >= 0; i--) {
var a = animals[i];
if (a.isEscaped) continue;
var dx = x - a.x;
var dy = y - a.y;
if (dx * dx + dy * dy < a.radius * a.radius) {
dragAnimal = a;
dragOffsetX = a.x - x;
dragOffsetY = a.y - y;
a.isDragging = true;
// Bring to top
game.removeChild(a);
game.addChild(a);
LK.getSound('move').play();
break;
}
}
};
game.move = function (x, y, obj) {
if (gameWon) return;
if (dragAnimal && !dragAnimal.isEscaped) {
// Move animal with finger, with offset
dragAnimal.x = x + dragOffsetX;
dragAnimal.y = y + dragOffsetY;
keepInsideStomach(dragAnimal);
resolveAnimalCollisions();
}
};
game.up = function (x, y, obj) {
if (dragAnimal) {
dragAnimal.isDragging = false;
dragAnimal = null;
}
};
// Main update loop
game.update = function () {
if (gameWon) return;
// Acid spawn
acidTimer++;
if (acidTimer >= acidInterval) {
acidTimer = 0;
// Spawn acid at random bottom edge
var angle = Math.PI + (Math.random() - 0.5) * Math.PI / 2;
var r = stomachWall.width / 2 - 80;
var ax = stomachCenterX + Math.cos(angle) * r;
var ay = stomachCenterY + Math.sin(angle) * r;
var acid = new Acid();
acid.x = ax;
acid.y = ay;
acids.push(acid);
game.addChild(acid);
}
// Update acids
for (var i = acids.length - 1; i >= 0; i--) {
var acid = acids[i];
acid.update();
// Remove if out of stomach
var dx = acid.x - stomachCenterX;
var dy = acid.y - stomachCenterY;
var stomachR = stomachWall.width / 2 - acid.radius - 10;
if (dx * dx + dy * dy > stomachR * stomachR) {
acid.destroy();
acids.splice(i, 1);
continue;
}
// Check collision with animals
for (var j = 0; j < animals.length; j++) {
var a = animals[j];
if (a.isEscaped) continue;
if (circlesCollide(acid.x, acid.y, acid.radius, a.x, a.y, a.radius)) {
// Animal hit!
a.flash();
LK.effects.flashScreen(0xff0000, 400);
LK.getSound('pop').play();
// Game over
LK.showGameOver();
return;
}
}
}
// Check for escape
for (var i = 0; i < animals.length; i++) {
var a = animals[i];
if (a.isEscaped) continue;
// If animal is at exit
if (circlesCollide(a.x, a.y, a.radius, exit.x, exit.y, exit.width / 2)) {
a.isEscaped = true;
score++;
scoreTxt.setText('Escaped: ' + score + '/6');
LK.getSound('escape').play();
// Animate animal out
tween(a, {
y: exit.y - 300,
alpha: 0
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
a.visible = false;
}
});
// Win if all escaped
if (score >= animals.length) {
gameWon = true;
LK.effects.flashScreen(0x8ecae6, 800);
LK.setScore(score);
LK.showYouWin();
return;
}
}
}
// Animals not being dragged: gently move to their target positions (for future puzzle logic)
for (var i = 0; i < animals.length; i++) {
var a = animals[i];
if (a.isEscaped) continue;
if (!a.isDragging) {
// Could add idle movement here for more life
}
keepInsideStomach(a);
}
// Prevent animal overlap
resolveAnimalCollisions();
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Acid hazard class
var Acid = Container.expand(function () {
var self = Container.call(this);
var asset = self.attachAsset('acid', {
anchorX: 0.5,
anchorY: 0.5
});
self.radius = asset.width / 2;
// Acid moves in a wobbly path
self.vx = (Math.random() - 0.5) * 6;
self.vy = 2 + Math.random() * 2;
self.angle = Math.random() * Math.PI * 2;
self.amp = 30 + Math.random() * 30;
self.update = function () {
self.angle += 0.07;
self.x += self.vx + Math.sin(self.angle) * 1.5;
self.y += self.vy + Math.cos(self.angle) * 0.7;
};
return self;
});
// Animal class
var Animal = Container.expand(function () {
var self = Container.call(this);
// Properties: type, can be 'pig', 'bee', etc.
self.type = 'pig';
self.isEscaped = false;
// Attach asset
var asset = self.attachAsset(self.type, {
anchorX: 0.5,
anchorY: 0.5
});
// For dragging
self.isDragging = false;
// For collision
self.radius = asset.width / 2;
// For movement
self.targetX = self.x;
self.targetY = self.y;
// Set animal type and update asset
self.setType = function (type) {
self.type = type;
asset.setAsset(type);
// Update radius
self.radius = asset.width / 2;
};
// Animate to a new position
self.moveTo = function (x, y) {
self.targetX = x;
self.targetY = y;
tween(self, {
x: x,
y: y
}, {
duration: 220,
easing: tween.easeOut,
onFinish: function onFinish() {
self.x = x;
self.y = y;
}
});
};
// Flash when hit
self.flash = function () {
LK.effects.flashObject(self, 0xff0000, 400);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfadadd // Light pink stomach color
});
/****
* Game Code
****/
// Sound for escape
// Sound for acid pop
// Sound for animal move
// Exit (esophagus opening)
// Digestive hazard (acid bubble)
// Stomach wall (background)
// Animal shapes (unique color for each)
// Center of the stomach
var stomachCenterX = 2048 / 2;
var stomachCenterY = 2732 / 2;
// Add stomach wall background
var stomachWall = LK.getAsset('stomachWall', {
anchorX: 0.5,
anchorY: 0.5,
x: stomachCenterX,
y: stomachCenterY
});
game.addChild(stomachWall);
// Add exit (esophagus opening) at the top center
var exitY = 350;
var exit = LK.getAsset('exit', {
anchorX: 0.5,
anchorY: 0.5,
x: stomachCenterX,
y: exitY
});
game.addChild(exit);
// Animal definitions
var animalTypes = [{
type: 'pig',
name: 'Peter the Pig'
}, {
type: 'bee',
name: 'Zee the Bee'
}, {
type: 'snake',
name: 'Marvin the Snake'
}, {
type: 'mouse',
name: 'Ron the Mouse'
}, {
type: 'lamb',
name: 'Mild the Lamb'
}, {
type: 'bunny',
name: 'Joy the Easter Bunny'
}];
// Store animals
var animals = [];
// Store acids
var acids = [];
// Track dragging
var dragAnimal = null;
// Track offset for dragging
var dragOffsetX = 0;
var dragOffsetY = 0;
// Track if game is won
var gameWon = false;
// Place animals in a circle in the stomach
var animalCircleRadius = 500;
for (var i = 0; i < animalTypes.length; i++) {
var a = new Animal();
a.setType(animalTypes[i].type);
// Place in a circle
var angle = Math.PI * 2 * i / animalTypes.length;
a.x = stomachCenterX + Math.cos(angle) * animalCircleRadius;
a.y = stomachCenterY + Math.sin(angle) * animalCircleRadius;
a.targetX = a.x;
a.targetY = a.y;
a.animalName = animalTypes[i].name;
a.isEscaped = false;
animals.push(a);
game.addChild(a);
}
// Acid spawn timer
var acidTimer = 0;
var acidInterval = 90; // frames
// Score: number of animals escaped
var score = 0;
// Score text
var scoreTxt = new Text2('Escaped: 0/6', {
size: 100,
fill: 0x222222
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Instructions text
var instrTxt = new Text2('Drag animals to the blue exit!\nAvoid the acid bubbles!', {
size: 60,
fill: 0x333333
});
instrTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(instrTxt);
instrTxt.y = 120;
// Helper: check circle collision
function circlesCollide(x1, y1, r1, x2, y2, r2) {
var dx = x1 - x2;
var dy = y1 - y2;
var dist = Math.sqrt(dx * dx + dy * dy);
return dist < r1 + r2 - 10; // -10 for a little overlap forgiveness
}
// Helper: keep inside stomach wall
function keepInsideStomach(animal) {
var dx = animal.x - stomachCenterX;
var dy = animal.y - stomachCenterY;
var stomachR = stomachWall.width / 2 - animal.radius - 10;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > stomachR) {
// Push back to edge
var angle = Math.atan2(dy, dx);
animal.x = stomachCenterX + Math.cos(angle) * stomachR;
animal.y = stomachCenterY + Math.sin(angle) * stomachR;
}
}
// Helper: prevent animal overlap
function resolveAnimalCollisions() {
for (var i = 0; i < animals.length; i++) {
var a1 = animals[i];
if (a1.isEscaped) continue;
for (var j = i + 1; j < animals.length; j++) {
var a2 = animals[j];
if (a2.isEscaped) continue;
var dx = a1.x - a2.x;
var dy = a1.y - a2.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var minDist = a1.radius + a2.radius - 8;
if (dist < minDist && dist > 0.1) {
// Push apart
var overlap = (minDist - dist) / 2;
var nx = dx / dist;
var ny = dy / dist;
a1.x += nx * overlap;
a1.y += ny * overlap;
a2.x -= nx * overlap;
a2.y -= ny * overlap;
}
}
}
}
// Dragging logic
game.down = function (x, y, obj) {
if (gameWon) return;
// Find topmost animal under pointer
for (var i = animals.length - 1; i >= 0; i--) {
var a = animals[i];
if (a.isEscaped) continue;
var dx = x - a.x;
var dy = y - a.y;
if (dx * dx + dy * dy < a.radius * a.radius) {
dragAnimal = a;
dragOffsetX = a.x - x;
dragOffsetY = a.y - y;
a.isDragging = true;
// Bring to top
game.removeChild(a);
game.addChild(a);
LK.getSound('move').play();
break;
}
}
};
game.move = function (x, y, obj) {
if (gameWon) return;
if (dragAnimal && !dragAnimal.isEscaped) {
// Move animal with finger, with offset
dragAnimal.x = x + dragOffsetX;
dragAnimal.y = y + dragOffsetY;
keepInsideStomach(dragAnimal);
resolveAnimalCollisions();
}
};
game.up = function (x, y, obj) {
if (dragAnimal) {
dragAnimal.isDragging = false;
dragAnimal = null;
}
};
// Main update loop
game.update = function () {
if (gameWon) return;
// Acid spawn
acidTimer++;
if (acidTimer >= acidInterval) {
acidTimer = 0;
// Spawn acid at random bottom edge
var angle = Math.PI + (Math.random() - 0.5) * Math.PI / 2;
var r = stomachWall.width / 2 - 80;
var ax = stomachCenterX + Math.cos(angle) * r;
var ay = stomachCenterY + Math.sin(angle) * r;
var acid = new Acid();
acid.x = ax;
acid.y = ay;
acids.push(acid);
game.addChild(acid);
}
// Update acids
for (var i = acids.length - 1; i >= 0; i--) {
var acid = acids[i];
acid.update();
// Remove if out of stomach
var dx = acid.x - stomachCenterX;
var dy = acid.y - stomachCenterY;
var stomachR = stomachWall.width / 2 - acid.radius - 10;
if (dx * dx + dy * dy > stomachR * stomachR) {
acid.destroy();
acids.splice(i, 1);
continue;
}
// Check collision with animals
for (var j = 0; j < animals.length; j++) {
var a = animals[j];
if (a.isEscaped) continue;
if (circlesCollide(acid.x, acid.y, acid.radius, a.x, a.y, a.radius)) {
// Animal hit!
a.flash();
LK.effects.flashScreen(0xff0000, 400);
LK.getSound('pop').play();
// Game over
LK.showGameOver();
return;
}
}
}
// Check for escape
for (var i = 0; i < animals.length; i++) {
var a = animals[i];
if (a.isEscaped) continue;
// If animal is at exit
if (circlesCollide(a.x, a.y, a.radius, exit.x, exit.y, exit.width / 2)) {
a.isEscaped = true;
score++;
scoreTxt.setText('Escaped: ' + score + '/6');
LK.getSound('escape').play();
// Animate animal out
tween(a, {
y: exit.y - 300,
alpha: 0
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
a.visible = false;
}
});
// Win if all escaped
if (score >= animals.length) {
gameWon = true;
LK.effects.flashScreen(0x8ecae6, 800);
LK.setScore(score);
LK.showYouWin();
return;
}
}
}
// Animals not being dragged: gently move to their target positions (for future puzzle logic)
for (var i = 0; i < animals.length; i++) {
var a = animals[i];
if (a.isEscaped) continue;
if (!a.isDragging) {
// Could add idle movement here for more life
}
keepInsideStomach(a);
}
// Prevent animal overlap
resolveAnimalCollisions();
};