User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'length')' in or related to this line: 'var animalGraphics = self.attachAsset(self.assetId, {' Line Number: 35
Code edit (1 edits merged)
Please save this source code
User prompt
Animal Rescue: Escape the Snake!
Initial prompt
(Pig) (Cat) (Bee) (Frog) (Polar Bear) (Elephant) (Bird) (Snail) (Axolotl) (Pink Fox) (Boy Bat) (Wolf) (Chinchilla) And (Moth) Is Struggle In The Snake Tummy Without Inside Of Snake Tummy With Video
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var facekit = LK.import("@upit/facekit.v1"); /**** * Classes ****/ // Animal class var Animal = Container.expand(function (assetId) { var self = Container.call(this); // Attach animal asset var animalGraphics = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); // Escape state self.escaped = false; // Movement velocity self.vx = 0; self.vy = 0; // Used for mouth open "boost" self.boostTimer = 0; // Update method self.update = function () { if (self.escaped) return; // Apply velocity self.x += self.vx; self.y += self.vy; // Friction self.vx *= 0.92; self.vy *= 0.92; // Clamp inside snake tummy if (self.x < tummy.x - tummy.width / 2 + animalGraphics.width / 2) { self.x = tummy.x - tummy.width / 2 + animalGraphics.width / 2; self.vx *= -0.5; } if (self.x > tummy.x + tummy.width / 2 - animalGraphics.width / 2) { self.x = tummy.x + tummy.width / 2 - animalGraphics.width / 2; self.vx *= -0.5; } if (self.y < tummy.y - tummy.height / 2 + animalGraphics.height / 2) { self.y = tummy.y - tummy.height / 2 + animalGraphics.height / 2; self.vy *= -0.5; } if (self.y > tummy.y + tummy.height / 2 - animalGraphics.height / 2) { self.y = tummy.y + tummy.height / 2 - animalGraphics.height / 2; self.vy *= -0.5; } }; // Escape animation self.escape = function () { self.escaped = true; tween(self, { y: self.y - 600, alpha: 0 }, { duration: 900, easing: tween.easeIn, onFinish: function onFinish() { self.visible = false; } }); }; return self; }); // Obstacle class var Obstacle = Container.expand(function () { var self = Container.call(this); var obsGraphics = self.attachAsset('obstacle', { anchorX: 0.5, anchorY: 0.5 }); // Movement self.vx = 0; self.vy = 0; self.update = function () { self.x += self.vx; self.y += self.vy; // Bounce off tummy walls if (self.x < tummy.x - tummy.width / 2 + obsGraphics.width / 2) { self.x = tummy.x - tummy.width / 2 + obsGraphics.width / 2; self.vx *= -1; } if (self.x > tummy.x + tummy.width / 2 - obsGraphics.width / 2) { self.x = tummy.x + tummy.width / 2 - obsGraphics.width / 2; self.vx *= -1; } if (self.y < tummy.y - tummy.height / 2 + obsGraphics.height / 2) { self.y = tummy.y - tummy.height / 2 + obsGraphics.height / 2; self.vy *= -1; } if (self.y > tummy.y + tummy.height / 2 - obsGraphics.height / 2) { self.y = tummy.y + tummy.height / 2 - obsGraphics.height / 2; self.vy *= -1; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Success flash // Obstacle // Animal shapes (different colors) // Snake tummy (background, semi-transparent) /* We use simple shapes for animals and obstacles for now. Each animal will be a different colored ellipse. The snake's tummy is a large, semi-transparent ellipse in the center. Obstacles are red ellipses. */ // Use facekit: show camera feed as background facekit.enabled = true; // Center of the game var centerX = 2048 / 2; var centerY = 2732 / 2; // Snake tummy (background, not interactive) var tummy = LK.getAsset('snakeTummy', { anchorX: 0.5, anchorY: 0.5, x: centerX, y: centerY, alpha: 0.7 }); game.addChild(tummy); // List of animal types and their asset ids var animalTypes = [{ id: 'animal_pig', name: 'Pig' }, { id: 'animal_cat', name: 'Cat' }, { id: 'animal_bee', name: 'Bee' }, { id: 'animal_frog', name: 'Frog' }, { id: 'animal_polarbear', name: 'Polar Bear' }, { id: 'animal_elephant', name: 'Elephant' }, { id: 'animal_bird', name: 'Bird' }, { id: 'animal_snail', name: 'Snail' }, { id: 'animal_axolotl', name: 'Axolotl' }, { id: 'animal_fox', name: 'Pink Fox' }, { id: 'animal_boybat', name: 'Boy Bat' }, { id: 'animal_wolf', name: 'Wolf' }, { id: 'animal_chinchilla', name: 'Chinchilla' }, { id: 'animal_moth', name: 'Moth' }]; // Shuffle animals for random placement function shuffle(arr) { for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = arr[i]; arr[i] = arr[j]; arr[j] = t; } } shuffle(animalTypes); // Create animals var animals = []; for (var i = 0; i < animalTypes.length; i++) { var a = new Animal(animalTypes[i].id); // Place animals in a circle inside the tummy var angle = i / animalTypes.length * Math.PI * 2; var radius = 500; a.x = centerX + Math.cos(angle) * radius; a.y = centerY + Math.sin(angle) * radius; a.name = animalTypes[i].name; animals.push(a); game.addChild(a); } // Obstacles var obstacles = []; for (var i = 0; i < 4; i++) { var obs = new Obstacle(); // Place randomly inside tummy obs.x = centerX + (Math.random() - 0.5) * 700; obs.y = centerY + (Math.random() - 0.5) * 900; // Random velocity obs.vx = (Math.random() - 0.5) * 7; obs.vy = (Math.random() - 0.5) * 7; obstacles.push(obs); game.addChild(obs); } // Score: animals escaped var animalsEscaped = 0; // Score text var scoreTxt = new Text2('0 / ' + animals.length, { size: 120, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Instructions text var instructions = new Text2('Move your face to guide the animals!\nOpen your mouth to help them escape!', { size: 70, fill: "#fff" }); instructions.anchor.set(0.5, 0); LK.gui.bottom.addChild(instructions); // Main animal to control (the first in the array) var mainAnimal = animals[0]; // Helper: get facekit mouth center, fallback to center function getFaceX() { if (facekit.mouthCenter && typeof facekit.mouthCenter.x === 'number') { return facekit.mouthCenter.x; } return centerX; } function getFaceY() { if (facekit.mouthCenter && typeof facekit.mouthCenter.y === 'number') { return facekit.mouthCenter.y; } return centerY; } // Helper: check if animal is at escape zone (top of tummy) function isAtEscapeZone(animal) { // Escape zone: top 120px of tummy return animal.y < tummy.y - tummy.height / 2 + 120; } // Helper: check collision between two containers (circle approx) function isColliding(a, b) { var dx = a.x - b.x; var dy = a.y - b.y; var dist = Math.sqrt(dx * dx + dy * dy); var r1 = a.width || 90; var r2 = b.width || 60; return dist < r1 / 2 + r2 / 2 - 10; } // Flash effect for escape function flashEscape() { var flash = LK.getAsset('escapeFlash', { anchorX: 0.5, anchorY: 0.5, x: centerX, y: centerY, alpha: 0.7 }); game.addChild(flash); tween(flash, { alpha: 0 }, { duration: 600, onFinish: function onFinish() { flash.destroy(); } }); } // Game update game.update = function () { // Update all animals for (var i = 0; i < animals.length; i++) { animals[i].update(); } // Update obstacles for (var i = 0; i < obstacles.length; i++) { obstacles[i].update(); } // Control main animal with face if (!mainAnimal.escaped) { // Move towards face position var fx = getFaceX(); var fy = getFaceY(); // Clamp to tummy area var tx = Math.max(tummy.x - tummy.width / 2 + 90, Math.min(tummy.x + tummy.width / 2 - 90, fx)); var ty = Math.max(tummy.y - tummy.height / 2 + 90, Math.min(tummy.y + tummy.height / 2 - 90, fy)); // Smooth follow mainAnimal.vx += (tx - mainAnimal.x) * 0.08; mainAnimal.vy += (ty - mainAnimal.y) * 0.08; // If mouth open, give a boost upwards if (facekit.mouthOpen) { mainAnimal.vy -= 2.5; mainAnimal.boostTimer = 8; } else if (mainAnimal.boostTimer > 0) { mainAnimal.vy -= 1.2; mainAnimal.boostTimer--; } // If at escape zone, escape! if (isAtEscapeZone(mainAnimal)) { mainAnimal.escape(); animalsEscaped++; scoreTxt.setText(animalsEscaped + ' / ' + animals.length); flashEscape(); // Next animal becomes main var found = false; for (var i = 0; i < animals.length; i++) { if (!animals[i].escaped) { mainAnimal = animals[i]; found = true; break; } } if (!found) { // All escaped! LK.showYouWin(); } } } // Collisions: main animal with obstacles if (!mainAnimal.escaped) { for (var i = 0; i < obstacles.length; i++) { if (isColliding(mainAnimal, obstacles[i])) { // Flash red, reset animal to center LK.effects.flashScreen(0xff0000, 600); mainAnimal.x = centerX; mainAnimal.y = centerY + 400; mainAnimal.vx = 0; mainAnimal.vy = 0; } } } // Collisions: animals with each other (push apart) for (var i = 0; i < animals.length; i++) { for (var j = i + 1; j < animals.length; j++) { if (animals[i].escaped || animals[j].escaped) continue; var dx = animals[i].x - animals[j].x; var dy = animals[i].y - animals[j].y; var dist = Math.sqrt(dx * dx + dy * dy); var minDist = 90; if (dist < minDist && dist > 0) { var overlap = (minDist - dist) / 2; var ox = dx / dist * overlap; var oy = dy / dist * overlap; animals[i].x += ox; animals[i].y += oy; animals[j].x -= ox; animals[j].y -= oy; } } } }; // No touch controls: all control is via facekit // No music, no sound, no pause, no game over handling (handled by LK)
===================================================================
--- original.js
+++ change.js
@@ -7,12 +7,12 @@
/****
* Classes
****/
// Animal class
-var Animal = Container.expand(function () {
+var Animal = Container.expand(function (assetId) {
var self = Container.call(this);
// Attach animal asset
- var animalGraphics = self.attachAsset(self.assetId, {
+ var animalGraphics = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Escape state
@@ -189,10 +189,9 @@
shuffle(animalTypes);
// Create animals
var animals = [];
for (var i = 0; i < animalTypes.length; i++) {
- var a = new Animal();
- a.assetId = animalTypes[i].id;
+ var a = new Animal(animalTypes[i].id);
// Place animals in a circle inside the tummy
var angle = i / animalTypes.length * Math.PI * 2;
var radius = 500;
a.x = centerX + Math.cos(angle) * radius;