/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Obstacle: acid pool (hazard)
var Acid = Container.expand(function () {
var self = Container.call(this);
var acid = self.attachAsset('acid', {
anchorX: 0.5,
anchorY: 0.5
});
// Acid can move left/right for challenge
self.speed = 0;
self.direction = 1;
self.update = function () {
if (self.speed !== 0) {
self.x += self.speed * self.direction;
if (self.x < 200 || self.x > 2048 - 200) {
self.direction *= -1;
}
}
};
return self;
});
// Animal base class
var Animal = Container.expand(function () {
var self = Container.call(this);
// These will be set by subclasses
self.assetId = '';
self.moveType = 'normal'; // 'normal', 'hop', 'slide', 'float', etc.
self.speed = 12; // Default speed
self.jumpPower = 0; // For animals that can jump
self.gravity = 0; // For animals affected by gravity
self.vy = 0; // Vertical velocity
// Attach animal asset
var animalSprite = self.attachAsset(self.assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Used for per-animal movement logic
self.update = function () {
// Movement logic handled in main game loop
};
// Called when switching to this animal
self.onSwitchIn = function () {
// Flash or animate to show selection
tween(animalSprite, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(animalSprite, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.easeIn
});
}
});
};
// Called when switching away from this animal
self.onSwitchOut = function () {
// No-op for now
};
return self;
});
// Snail: very slow, can stick to walls
var Snail = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'snail';
self.speed = 4;
return self;
});
// Polar Bear: slow, immune to acid
var PolarBear = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'polarBear';
self.speed = 7;
return self;
});
// Pig: slow, can push food chunks
var Pig = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'pig';
self.speed = 8;
return self;
});
// Frog: can hop
var Frog = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'frog';
self.speed = 10;
self.jumpPower = 48;
self.gravity = 3.5;
self.isJumping = false;
return self;
});
// Elephant: can push obstacles, slowest
var Elephant = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'elephant';
self.speed = 6;
return self;
});
// Cat: fast, can jump
var Cat = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'cat';
self.speed = 16;
self.jumpPower = 38;
self.gravity = 3.2;
self.isJumping = false;
return self;
});
// Bird: can fly (ignores gravity)
var Bird = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'bird';
self.speed = 13;
self.moveType = 'fly';
return self;
});
// Bee: can float over acid, moves in short bursts
var Bee = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'bee';
self.speed = 10;
self.moveType = 'float';
return self;
});
// Axolotl: can swim in acid, normal speed
var Axolotl = Animal.expand(function () {
var self = Animal.call(this);
self.assetId = 'axolotl';
self.speed = 11;
self.moveType = 'swim';
return self;
});
// Obstacle: food chunk (movable)
var FoodChunk = Container.expand(function () {
var self = Container.call(this);
var chunk = self.attachAsset('foodChunk', {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {};
return self;
});
// Obstacle: stomach wall (static)
var StomachWall = Container.expand(function () {
var self = Container.call(this);
var wall = self.attachAsset('stomachWall', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
// Touch button for animal switching
var SwitchButton = Container.expand(function () {
var self = Container.call(this);
var btn = self.attachAsset('switchBtn', {
anchorX: 0.5,
anchorY: 0.5
});
self.icon = null; // Will be set to animal icon
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2d1b0c // Deep brown, snake belly
});
/****
* Game Code
****/
// Touch button shapes
// Obstacle shapes
// Animal shapes (unique color for each animal)
// --- Game constants ---
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var PLAY_AREA_TOP = 200;
var PLAY_AREA_BOTTOM = GAME_HEIGHT - 200;
var PLAY_AREA_LEFT = 100;
var PLAY_AREA_RIGHT = GAME_WIDTH - 100;
// --- Animal roster and order ---
var animalClasses = [Pig, Cat, Bee, Frog, PolarBear, Elephant, Bird, Snail, Axolotl];
var animalNames = ['Pig', 'Cat', 'Bee', 'Frog', 'Polar Bear', 'Elephant', 'Bird', 'Snail', 'Axolotl'];
var animalIcons = ['pig', 'cat', 'bee', 'frog', 'polarBear', 'elephant', 'bird', 'snail', 'axolotl'];
var animals = [];
var currentAnimalIdx = 0;
var currentAnimal = null;
// --- Obstacles and hazards ---
var obstacles = [];
var acids = [];
var foodChunks = [];
// --- UI ---
var switchButtons = [];
var switchBtnY = GAME_HEIGHT - 180;
var switchBtnSpacing = 200;
var infoText = null;
// --- Dragging ---
var dragNode = null;
var dragOffsetX = 0;
var dragOffsetY = 0;
// --- Game state ---
var isMovingLeft = false;
var isMovingRight = false;
var isMovingUp = false;
var isMovingDown = false;
var isJumping = false;
var isSwitching = false;
var gameStarted = false;
var gameOver = false;
var youWin = false;
// --- Level layout (simple for MVP) ---
function setupLevel() {
// Clear previous
for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy();
for (var i = 0; i < acids.length; ++i) acids[i].destroy();
for (var i = 0; i < foodChunks.length; ++i) foodChunks[i].destroy();
obstacles = [];
acids = [];
foodChunks = [];
// Top and bottom stomach walls
var wallTop = new StomachWall();
wallTop.x = GAME_WIDTH / 2;
wallTop.y = PLAY_AREA_TOP - 40;
obstacles.push(wallTop);
game.addChild(wallTop);
var wallBottom = new StomachWall();
wallBottom.x = GAME_WIDTH / 2;
wallBottom.y = PLAY_AREA_BOTTOM + 40;
obstacles.push(wallBottom);
game.addChild(wallBottom);
// Acid pools (hazards)
var acid1 = new Acid();
acid1.x = GAME_WIDTH / 2;
acid1.y = PLAY_AREA_TOP + 400;
acid1.speed = 6;
acids.push(acid1);
game.addChild(acid1);
var acid2 = new Acid();
acid2.x = GAME_WIDTH / 2 + 400;
acid2.y = PLAY_AREA_TOP + 900;
acid2.speed = 0;
acids.push(acid2);
game.addChild(acid2);
// Food chunks (movable obstacles)
var chunk1 = new FoodChunk();
chunk1.x = GAME_WIDTH / 2 - 300;
chunk1.y = PLAY_AREA_TOP + 700;
foodChunks.push(chunk1);
game.addChild(chunk1);
var chunk2 = new FoodChunk();
chunk2.x = GAME_WIDTH / 2 + 300;
chunk2.y = PLAY_AREA_TOP + 1200;
foodChunks.push(chunk2);
game.addChild(chunk2);
// More obstacles can be added for future levels
}
// --- Animal setup ---
function setupAnimals() {
// Remove previous
for (var i = 0; i < animals.length; ++i) animals[i].destroy();
animals = [];
// Place all animals at start, stacked
var startX = GAME_WIDTH / 2;
var startY = PLAY_AREA_BOTTOM - 200;
for (var i = 0; i < animalClasses.length; ++i) {
var animal = new animalClasses[i]();
animal.x = startX + (i - 4) * 40;
animal.y = startY - i * 40;
animal.zIndex = i;
animal.visible = false;
animals.push(animal);
game.addChild(animal);
}
// Set first animal active
currentAnimalIdx = 0;
currentAnimal = animals[currentAnimalIdx];
currentAnimal.visible = true;
currentAnimal.onSwitchIn();
}
// --- UI setup ---
function setupUI() {
// Remove previous
for (var i = 0; i < switchButtons.length; ++i) switchButtons[i].destroy();
switchButtons = [];
// Create switch buttons for each animal
var btnStartX = GAME_WIDTH / 2 - (animalClasses.length - 1) / 2 * switchBtnSpacing;
for (var i = 0; i < animalClasses.length; ++i) {
var btn = new SwitchButton();
btn.x = btnStartX + i * switchBtnSpacing;
btn.y = switchBtnY;
btn.animalIdx = i;
// Add animal icon
var icon = btn.attachAsset(animalIcons[i], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
btn.icon = icon;
// Highlight current
if (i === currentAnimalIdx) {
icon.scaleX = icon.scaleY = 0.7;
}
// Touch event
btn.down = function (x, y, obj) {
if (isSwitching) return;
var idx = this.animalIdx;
if (idx !== currentAnimalIdx) {
switchAnimal(idx);
}
};
LK.gui.bottom.addChild(btn);
switchButtons.push(btn);
}
// Info text
if (infoText) infoText.destroy();
infoText = new Text2('Help the animals escape!\nTap an animal to switch.\nDrag to move. Avoid acid!', {
size: 70,
fill: "#fff",
align: "center"
});
infoText.anchor.set(0.5, 0);
LK.gui.top.addChild(infoText);
}
// --- Animal switching ---
function switchAnimal(idx) {
if (idx < 0 || idx >= animals.length) return;
if (idx === currentAnimalIdx) return;
isSwitching = true;
// Animate out old
currentAnimal.onSwitchOut();
currentAnimal.visible = false;
// Animate in new
currentAnimalIdx = idx;
currentAnimal = animals[currentAnimalIdx];
currentAnimal.visible = true;
currentAnimal.onSwitchIn();
// Highlight button
for (var i = 0; i < switchButtons.length; ++i) {
var icon = switchButtons[i].icon;
if (i === currentAnimalIdx) {
tween(icon, {
scaleX: 0.7,
scaleY: 0.7
}, {
duration: 120
});
} else {
tween(icon, {
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 120
});
}
}
// Small delay to prevent rapid switching
LK.setTimeout(function () {
isSwitching = false;
}, 200);
}
// --- Movement controls (touch drag) ---
function handleMove(x, y, obj) {
if (gameOver || youWin) return;
// Only move current animal
if (!currentAnimal) return;
// Clamp to play area
var nx = Math.max(PLAY_AREA_LEFT, Math.min(PLAY_AREA_RIGHT, x));
var ny = Math.max(PLAY_AREA_TOP, Math.min(PLAY_AREA_BOTTOM, y));
// For animals with gravity, only allow horizontal drag
if (currentAnimal.gravity > 0) {
nx = Math.max(PLAY_AREA_LEFT, Math.min(PLAY_AREA_RIGHT, x));
// y is controlled by gravity/jump
} else {
currentAnimal.y = ny;
}
currentAnimal.x = nx;
}
// --- Touch events ---
game.down = function (x, y, obj) {
if (gameOver || youWin) return;
// Start drag
dragNode = currentAnimal;
dragOffsetX = x - currentAnimal.x;
dragOffsetY = y - currentAnimal.y;
handleMove(x, y, obj);
};
game.move = function (x, y, obj) {
if (gameOver || youWin) return;
if (dragNode) {
handleMove(x - dragOffsetX, y - dragOffsetY, obj);
}
};
game.up = function (x, y, obj) {
dragNode = null;
};
// --- Collision helpers ---
function intersectsAny(obj, arr) {
for (var i = 0; i < arr.length; ++i) {
if (obj.intersects(arr[i])) return true;
}
return false;
}
function getIntersecting(obj, arr) {
for (var i = 0; i < arr.length; ++i) {
if (obj.intersects(arr[i])) return arr[i];
}
return null;
}
// --- Game update loop ---
game.update = function () {
if (gameOver || youWin) return;
// Update obstacles
for (var i = 0; i < acids.length; ++i) {
if (acids[i].update) acids[i].update();
}
for (var i = 0; i < foodChunks.length; ++i) {
if (foodChunks[i].update) foodChunks[i].update();
}
// Update current animal movement (gravity/jump)
if (currentAnimal) {
// Gravity/jump for Cat, Frog
if (currentAnimal.gravity > 0) {
// If not being dragged, apply gravity
if (!dragNode) {
currentAnimal.vy = (currentAnimal.vy || 0) + currentAnimal.gravity;
currentAnimal.y += currentAnimal.vy;
// Floor collision
if (currentAnimal.y > PLAY_AREA_BOTTOM - 60) {
currentAnimal.y = PLAY_AREA_BOTTOM - 60;
currentAnimal.vy = 0;
currentAnimal.isJumping = false;
}
// Ceiling collision
if (currentAnimal.y < PLAY_AREA_TOP + 60) {
currentAnimal.y = PLAY_AREA_TOP + 60;
currentAnimal.vy = 0;
}
}
}
// TODO: Add jump on double tap or button (future)
}
// Check for acid collision (hazard)
if (currentAnimal) {
var acid = getIntersecting(currentAnimal, acids);
if (acid) {
// Some animals are immune
if (currentAnimal.assetId === 'polarBear' || currentAnimal.assetId === 'axolotl' || currentAnimal.assetId === 'bee' || currentAnimal.assetId === 'bird') {
// No effect
} else {
// Game over
LK.effects.flashScreen(0x00ffff, 800);
LK.showGameOver();
gameOver = true;
return;
}
}
}
// Check for wall collision (keep inside)
if (currentAnimal) {
if (intersectsAny(currentAnimal, obstacles)) {
// Push back inside
if (currentAnimal.y < GAME_HEIGHT / 2) {
currentAnimal.y += 20;
} else {
currentAnimal.y -= 20;
}
}
}
// Check for food chunk collision (Pig/Elephant can push)
if (currentAnimal) {
var chunk = getIntersecting(currentAnimal, foodChunks);
if (chunk) {
if (currentAnimal.assetId === 'pig' || currentAnimal.assetId === 'elephant') {
// Push chunk in direction of movement
var dx = chunk.x - currentAnimal.x;
var dy = chunk.y - currentAnimal.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 0) {
chunk.x += dx / dist * 8;
chunk.y += dy / dist * 8;
// Clamp chunk inside play area
chunk.x = Math.max(PLAY_AREA_LEFT + 60, Math.min(PLAY_AREA_RIGHT - 60, chunk.x));
chunk.y = Math.max(PLAY_AREA_TOP + 60, Math.min(PLAY_AREA_BOTTOM - 60, chunk.y));
}
} else {
// Block movement
if (dragNode) {
// Undo last move
currentAnimal.x -= (currentAnimal.x - chunk.x) * 0.2;
currentAnimal.y -= (currentAnimal.y - chunk.y) * 0.2;
}
}
}
}
// Win condition: reach top of play area
if (currentAnimal && currentAnimal.y < PLAY_AREA_TOP + 80) {
// You win!
LK.effects.flashScreen(0x00ff00, 1000);
LK.showYouWin();
youWin = true;
return;
}
};
// --- Game start ---
function startGame() {
setupLevel();
setupAnimals();
setupUI();
gameOver = false;
youWin = false;
}
startGame(); ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,528 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+
+/****
+* Classes
+****/
+// Obstacle: acid pool (hazard)
+var Acid = Container.expand(function () {
+ var self = Container.call(this);
+ var acid = self.attachAsset('acid', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Acid can move left/right for challenge
+ self.speed = 0;
+ self.direction = 1;
+ self.update = function () {
+ if (self.speed !== 0) {
+ self.x += self.speed * self.direction;
+ if (self.x < 200 || self.x > 2048 - 200) {
+ self.direction *= -1;
+ }
+ }
+ };
+ return self;
+});
+// Animal base class
+var Animal = Container.expand(function () {
+ var self = Container.call(this);
+ // These will be set by subclasses
+ self.assetId = '';
+ self.moveType = 'normal'; // 'normal', 'hop', 'slide', 'float', etc.
+ self.speed = 12; // Default speed
+ self.jumpPower = 0; // For animals that can jump
+ self.gravity = 0; // For animals affected by gravity
+ self.vy = 0; // Vertical velocity
+ // Attach animal asset
+ var animalSprite = self.attachAsset(self.assetId, {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Used for per-animal movement logic
+ self.update = function () {
+ // Movement logic handled in main game loop
+ };
+ // Called when switching to this animal
+ self.onSwitchIn = function () {
+ // Flash or animate to show selection
+ tween(animalSprite, {
+ scaleX: 1.2,
+ scaleY: 1.2
+ }, {
+ duration: 120,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(animalSprite, {
+ scaleX: 1,
+ scaleY: 1
+ }, {
+ duration: 120,
+ easing: tween.easeIn
+ });
+ }
+ });
+ };
+ // Called when switching away from this animal
+ self.onSwitchOut = function () {
+ // No-op for now
+ };
+ return self;
+});
+// Snail: very slow, can stick to walls
+var Snail = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'snail';
+ self.speed = 4;
+ return self;
+});
+// Polar Bear: slow, immune to acid
+var PolarBear = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'polarBear';
+ self.speed = 7;
+ return self;
+});
+// Pig: slow, can push food chunks
+var Pig = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'pig';
+ self.speed = 8;
+ return self;
+});
+// Frog: can hop
+var Frog = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'frog';
+ self.speed = 10;
+ self.jumpPower = 48;
+ self.gravity = 3.5;
+ self.isJumping = false;
+ return self;
+});
+// Elephant: can push obstacles, slowest
+var Elephant = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'elephant';
+ self.speed = 6;
+ return self;
+});
+// Cat: fast, can jump
+var Cat = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'cat';
+ self.speed = 16;
+ self.jumpPower = 38;
+ self.gravity = 3.2;
+ self.isJumping = false;
+ return self;
+});
+// Bird: can fly (ignores gravity)
+var Bird = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'bird';
+ self.speed = 13;
+ self.moveType = 'fly';
+ return self;
+});
+// Bee: can float over acid, moves in short bursts
+var Bee = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'bee';
+ self.speed = 10;
+ self.moveType = 'float';
+ return self;
+});
+// Axolotl: can swim in acid, normal speed
+var Axolotl = Animal.expand(function () {
+ var self = Animal.call(this);
+ self.assetId = 'axolotl';
+ self.speed = 11;
+ self.moveType = 'swim';
+ return self;
+});
+// Obstacle: food chunk (movable)
+var FoodChunk = Container.expand(function () {
+ var self = Container.call(this);
+ var chunk = self.attachAsset('foodChunk', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.update = function () {};
+ return self;
+});
+// Obstacle: stomach wall (static)
+var StomachWall = Container.expand(function () {
+ var self = Container.call(this);
+ var wall = self.attachAsset('stomachWall', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+// Touch button for animal switching
+var SwitchButton = Container.expand(function () {
+ var self = Container.call(this);
+ var btn = self.attachAsset('switchBtn', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.icon = null; // Will be set to animal icon
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x2d1b0c // Deep brown, snake belly
+});
+
+/****
+* Game Code
+****/
+// Touch button shapes
+// Obstacle shapes
+// Animal shapes (unique color for each animal)
+// --- Game constants ---
+var GAME_WIDTH = 2048;
+var GAME_HEIGHT = 2732;
+var PLAY_AREA_TOP = 200;
+var PLAY_AREA_BOTTOM = GAME_HEIGHT - 200;
+var PLAY_AREA_LEFT = 100;
+var PLAY_AREA_RIGHT = GAME_WIDTH - 100;
+// --- Animal roster and order ---
+var animalClasses = [Pig, Cat, Bee, Frog, PolarBear, Elephant, Bird, Snail, Axolotl];
+var animalNames = ['Pig', 'Cat', 'Bee', 'Frog', 'Polar Bear', 'Elephant', 'Bird', 'Snail', 'Axolotl'];
+var animalIcons = ['pig', 'cat', 'bee', 'frog', 'polarBear', 'elephant', 'bird', 'snail', 'axolotl'];
+var animals = [];
+var currentAnimalIdx = 0;
+var currentAnimal = null;
+// --- Obstacles and hazards ---
+var obstacles = [];
+var acids = [];
+var foodChunks = [];
+// --- UI ---
+var switchButtons = [];
+var switchBtnY = GAME_HEIGHT - 180;
+var switchBtnSpacing = 200;
+var infoText = null;
+// --- Dragging ---
+var dragNode = null;
+var dragOffsetX = 0;
+var dragOffsetY = 0;
+// --- Game state ---
+var isMovingLeft = false;
+var isMovingRight = false;
+var isMovingUp = false;
+var isMovingDown = false;
+var isJumping = false;
+var isSwitching = false;
+var gameStarted = false;
+var gameOver = false;
+var youWin = false;
+// --- Level layout (simple for MVP) ---
+function setupLevel() {
+ // Clear previous
+ for (var i = 0; i < obstacles.length; ++i) obstacles[i].destroy();
+ for (var i = 0; i < acids.length; ++i) acids[i].destroy();
+ for (var i = 0; i < foodChunks.length; ++i) foodChunks[i].destroy();
+ obstacles = [];
+ acids = [];
+ foodChunks = [];
+ // Top and bottom stomach walls
+ var wallTop = new StomachWall();
+ wallTop.x = GAME_WIDTH / 2;
+ wallTop.y = PLAY_AREA_TOP - 40;
+ obstacles.push(wallTop);
+ game.addChild(wallTop);
+ var wallBottom = new StomachWall();
+ wallBottom.x = GAME_WIDTH / 2;
+ wallBottom.y = PLAY_AREA_BOTTOM + 40;
+ obstacles.push(wallBottom);
+ game.addChild(wallBottom);
+ // Acid pools (hazards)
+ var acid1 = new Acid();
+ acid1.x = GAME_WIDTH / 2;
+ acid1.y = PLAY_AREA_TOP + 400;
+ acid1.speed = 6;
+ acids.push(acid1);
+ game.addChild(acid1);
+ var acid2 = new Acid();
+ acid2.x = GAME_WIDTH / 2 + 400;
+ acid2.y = PLAY_AREA_TOP + 900;
+ acid2.speed = 0;
+ acids.push(acid2);
+ game.addChild(acid2);
+ // Food chunks (movable obstacles)
+ var chunk1 = new FoodChunk();
+ chunk1.x = GAME_WIDTH / 2 - 300;
+ chunk1.y = PLAY_AREA_TOP + 700;
+ foodChunks.push(chunk1);
+ game.addChild(chunk1);
+ var chunk2 = new FoodChunk();
+ chunk2.x = GAME_WIDTH / 2 + 300;
+ chunk2.y = PLAY_AREA_TOP + 1200;
+ foodChunks.push(chunk2);
+ game.addChild(chunk2);
+ // More obstacles can be added for future levels
+}
+// --- Animal setup ---
+function setupAnimals() {
+ // Remove previous
+ for (var i = 0; i < animals.length; ++i) animals[i].destroy();
+ animals = [];
+ // Place all animals at start, stacked
+ var startX = GAME_WIDTH / 2;
+ var startY = PLAY_AREA_BOTTOM - 200;
+ for (var i = 0; i < animalClasses.length; ++i) {
+ var animal = new animalClasses[i]();
+ animal.x = startX + (i - 4) * 40;
+ animal.y = startY - i * 40;
+ animal.zIndex = i;
+ animal.visible = false;
+ animals.push(animal);
+ game.addChild(animal);
+ }
+ // Set first animal active
+ currentAnimalIdx = 0;
+ currentAnimal = animals[currentAnimalIdx];
+ currentAnimal.visible = true;
+ currentAnimal.onSwitchIn();
+}
+// --- UI setup ---
+function setupUI() {
+ // Remove previous
+ for (var i = 0; i < switchButtons.length; ++i) switchButtons[i].destroy();
+ switchButtons = [];
+ // Create switch buttons for each animal
+ var btnStartX = GAME_WIDTH / 2 - (animalClasses.length - 1) / 2 * switchBtnSpacing;
+ for (var i = 0; i < animalClasses.length; ++i) {
+ var btn = new SwitchButton();
+ btn.x = btnStartX + i * switchBtnSpacing;
+ btn.y = switchBtnY;
+ btn.animalIdx = i;
+ // Add animal icon
+ var icon = btn.attachAsset(animalIcons[i], {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.5,
+ scaleY: 0.5
+ });
+ btn.icon = icon;
+ // Highlight current
+ if (i === currentAnimalIdx) {
+ icon.scaleX = icon.scaleY = 0.7;
+ }
+ // Touch event
+ btn.down = function (x, y, obj) {
+ if (isSwitching) return;
+ var idx = this.animalIdx;
+ if (idx !== currentAnimalIdx) {
+ switchAnimal(idx);
+ }
+ };
+ LK.gui.bottom.addChild(btn);
+ switchButtons.push(btn);
+ }
+ // Info text
+ if (infoText) infoText.destroy();
+ infoText = new Text2('Help the animals escape!\nTap an animal to switch.\nDrag to move. Avoid acid!', {
+ size: 70,
+ fill: "#fff",
+ align: "center"
+ });
+ infoText.anchor.set(0.5, 0);
+ LK.gui.top.addChild(infoText);
+}
+// --- Animal switching ---
+function switchAnimal(idx) {
+ if (idx < 0 || idx >= animals.length) return;
+ if (idx === currentAnimalIdx) return;
+ isSwitching = true;
+ // Animate out old
+ currentAnimal.onSwitchOut();
+ currentAnimal.visible = false;
+ // Animate in new
+ currentAnimalIdx = idx;
+ currentAnimal = animals[currentAnimalIdx];
+ currentAnimal.visible = true;
+ currentAnimal.onSwitchIn();
+ // Highlight button
+ for (var i = 0; i < switchButtons.length; ++i) {
+ var icon = switchButtons[i].icon;
+ if (i === currentAnimalIdx) {
+ tween(icon, {
+ scaleX: 0.7,
+ scaleY: 0.7
+ }, {
+ duration: 120
+ });
+ } else {
+ tween(icon, {
+ scaleX: 0.5,
+ scaleY: 0.5
+ }, {
+ duration: 120
+ });
+ }
+ }
+ // Small delay to prevent rapid switching
+ LK.setTimeout(function () {
+ isSwitching = false;
+ }, 200);
+}
+// --- Movement controls (touch drag) ---
+function handleMove(x, y, obj) {
+ if (gameOver || youWin) return;
+ // Only move current animal
+ if (!currentAnimal) return;
+ // Clamp to play area
+ var nx = Math.max(PLAY_AREA_LEFT, Math.min(PLAY_AREA_RIGHT, x));
+ var ny = Math.max(PLAY_AREA_TOP, Math.min(PLAY_AREA_BOTTOM, y));
+ // For animals with gravity, only allow horizontal drag
+ if (currentAnimal.gravity > 0) {
+ nx = Math.max(PLAY_AREA_LEFT, Math.min(PLAY_AREA_RIGHT, x));
+ // y is controlled by gravity/jump
+ } else {
+ currentAnimal.y = ny;
+ }
+ currentAnimal.x = nx;
+}
+// --- Touch events ---
+game.down = function (x, y, obj) {
+ if (gameOver || youWin) return;
+ // Start drag
+ dragNode = currentAnimal;
+ dragOffsetX = x - currentAnimal.x;
+ dragOffsetY = y - currentAnimal.y;
+ handleMove(x, y, obj);
+};
+game.move = function (x, y, obj) {
+ if (gameOver || youWin) return;
+ if (dragNode) {
+ handleMove(x - dragOffsetX, y - dragOffsetY, obj);
+ }
+};
+game.up = function (x, y, obj) {
+ dragNode = null;
+};
+// --- Collision helpers ---
+function intersectsAny(obj, arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ if (obj.intersects(arr[i])) return true;
+ }
+ return false;
+}
+function getIntersecting(obj, arr) {
+ for (var i = 0; i < arr.length; ++i) {
+ if (obj.intersects(arr[i])) return arr[i];
+ }
+ return null;
+}
+// --- Game update loop ---
+game.update = function () {
+ if (gameOver || youWin) return;
+ // Update obstacles
+ for (var i = 0; i < acids.length; ++i) {
+ if (acids[i].update) acids[i].update();
+ }
+ for (var i = 0; i < foodChunks.length; ++i) {
+ if (foodChunks[i].update) foodChunks[i].update();
+ }
+ // Update current animal movement (gravity/jump)
+ if (currentAnimal) {
+ // Gravity/jump for Cat, Frog
+ if (currentAnimal.gravity > 0) {
+ // If not being dragged, apply gravity
+ if (!dragNode) {
+ currentAnimal.vy = (currentAnimal.vy || 0) + currentAnimal.gravity;
+ currentAnimal.y += currentAnimal.vy;
+ // Floor collision
+ if (currentAnimal.y > PLAY_AREA_BOTTOM - 60) {
+ currentAnimal.y = PLAY_AREA_BOTTOM - 60;
+ currentAnimal.vy = 0;
+ currentAnimal.isJumping = false;
+ }
+ // Ceiling collision
+ if (currentAnimal.y < PLAY_AREA_TOP + 60) {
+ currentAnimal.y = PLAY_AREA_TOP + 60;
+ currentAnimal.vy = 0;
+ }
+ }
+ }
+ // TODO: Add jump on double tap or button (future)
+ }
+ // Check for acid collision (hazard)
+ if (currentAnimal) {
+ var acid = getIntersecting(currentAnimal, acids);
+ if (acid) {
+ // Some animals are immune
+ if (currentAnimal.assetId === 'polarBear' || currentAnimal.assetId === 'axolotl' || currentAnimal.assetId === 'bee' || currentAnimal.assetId === 'bird') {
+ // No effect
+ } else {
+ // Game over
+ LK.effects.flashScreen(0x00ffff, 800);
+ LK.showGameOver();
+ gameOver = true;
+ return;
+ }
+ }
+ }
+ // Check for wall collision (keep inside)
+ if (currentAnimal) {
+ if (intersectsAny(currentAnimal, obstacles)) {
+ // Push back inside
+ if (currentAnimal.y < GAME_HEIGHT / 2) {
+ currentAnimal.y += 20;
+ } else {
+ currentAnimal.y -= 20;
+ }
+ }
+ }
+ // Check for food chunk collision (Pig/Elephant can push)
+ if (currentAnimal) {
+ var chunk = getIntersecting(currentAnimal, foodChunks);
+ if (chunk) {
+ if (currentAnimal.assetId === 'pig' || currentAnimal.assetId === 'elephant') {
+ // Push chunk in direction of movement
+ var dx = chunk.x - currentAnimal.x;
+ var dy = chunk.y - currentAnimal.y;
+ var dist = Math.sqrt(dx * dx + dy * dy);
+ if (dist > 0) {
+ chunk.x += dx / dist * 8;
+ chunk.y += dy / dist * 8;
+ // Clamp chunk inside play area
+ chunk.x = Math.max(PLAY_AREA_LEFT + 60, Math.min(PLAY_AREA_RIGHT - 60, chunk.x));
+ chunk.y = Math.max(PLAY_AREA_TOP + 60, Math.min(PLAY_AREA_BOTTOM - 60, chunk.y));
+ }
+ } else {
+ // Block movement
+ if (dragNode) {
+ // Undo last move
+ currentAnimal.x -= (currentAnimal.x - chunk.x) * 0.2;
+ currentAnimal.y -= (currentAnimal.y - chunk.y) * 0.2;
+ }
+ }
+ }
+ }
+ // Win condition: reach top of play area
+ if (currentAnimal && currentAnimal.y < PLAY_AREA_TOP + 80) {
+ // You win!
+ LK.effects.flashScreen(0x00ff00, 1000);
+ LK.showYouWin();
+ youWin = true;
+ return;
+ }
+};
+// --- Game start ---
+function startGame() {
+ setupLevel();
+ setupAnimals();
+ setupUI();
+ gameOver = false;
+ youWin = false;
+}
+startGame();
\ No newline at end of file