User prompt
show lives as heart
User prompt
show life on bottom left
User prompt
one contact takes one life
User prompt
give additional life on floor 10
User prompt
doors and keys dont spawn under floor list
User prompt
add door to floor 20
User prompt
use background
User prompt
you win if you reach floor 20
User prompt
move floors list to top right
User prompt
move floors list to top
User prompt
add 14 more floors
User prompt
do not write floor number on the top
User prompt
ghosts dont spawn close to you
User prompt
Please fix the bug: 'TypeError: tween.to is not a function' in or related to this line: 'tween.to(keyObj, {' Line Number: 882 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
fade out key if collected
User prompt
key always visible
User prompt
spawn key and door randomly
User prompt
spawn wall
User prompt
spawn one more ghost
User prompt
Please fix the bug: 'puzzleObj is not defined' in or related to this line: 'if (puzzleObj) {' Line Number: 662
User prompt
Please fix the bug: 'Puzzle is not defined' in or related to this line: 'var puzzle = new Puzzle();' Line Number: 452
User prompt
rename puzzle to key
User prompt
remove the floor on page top
User prompt
only show the floors in the list
User prompt
do not show top floor number
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Door class var Door = Container.expand(function () { var self = Container.call(this); self.locked = true; self.doorAsset = self.attachAsset('door_locked', { anchorX: 0.5, anchorY: 0.5 }); self.unlock = function () { self.locked = false; self.doorAsset.destroy(); self.doorAsset = self.attachAsset('door_unlocked', { anchorX: 0.5, anchorY: 0.5 }); }; return self; }); // Enemy (ghost) class var Ghost = Container.expand(function () { var self = Container.call(this); self.attachAsset('ghost', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4.4; self.dirX = 0; self.dirY = 0; self.changeDirCooldown = 0; // Helper to pick a new random direction (including diagonals, but not standing still) function pickRandomDirection() { var dirs = [{ x: 1, y: 0 }, // right { x: -1, y: 0 }, // left { x: 0, y: 1 }, // down { x: 0, y: -1 }, // up { x: 1, y: 1 }, // down-right { x: -1, y: 1 }, // down-left { x: 1, y: -1 }, // up-right { x: -1, y: -1 } // up-left ]; var idx = Math.floor(Math.random() * dirs.length); self.dirX = dirs[idx].x; self.dirY = dirs[idx].y; } pickRandomDirection(); self.changeDirCooldown = 60 + Math.floor(Math.random() * 60); // 1-2 seconds self.update = function () { // Save last position for possible collision logic if (typeof self.lastX === "undefined") self.lastX = self.x; if (typeof self.lastY === "undefined") self.lastY = self.y; // If player exists, chase the player if (typeof player !== "undefined" && player) { var dx = player.x - self.x; var dy = player.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { // Normalize direction var nx = dx / dist; var ny = dy / dist; // Move towards player self.x += self.speed * nx; self.y += self.speed * ny; } } else { // Fallback: random movement if no player self.x += self.speed * self.dirX; self.y += self.speed * self.dirY; } // Stay inside game area (bounce if hit edge) var bounced = false; if (self.x < 120) { self.x = 120; bounced = true; } if (self.x > 2048 - 120) { self.x = 2048 - 120; bounced = true; } if (self.y < 120) { self.y = 120; bounced = true; } if (self.y > 2732 - 120) { self.y = 2732 - 120; bounced = true; } // (No random direction change needed for chase mode) self.lastX = self.x; self.lastY = self.y; }; return self; }); // Key class (was Puzzle) var Key = Container.expand(function () { var self = Container.call(this); self.solved = false; self.attachAsset('puzzle', { anchorX: 0.5, anchorY: 0.5 }); return self; }); // Player class var Player = Container.expand(function () { var self = Container.call(this); self.asset = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.canMove = true; self.moveTo = function (x, y) { if (!self.canMove) return; // Clamp to game area var px = Math.max(60, Math.min(2048 - 60, x)); var py = Math.max(60, Math.min(2732 - 60, y)); self.x = px; self.y = py; }; return self; }); // Wall class var Wall = Container.expand(function () { var self = Container.call(this); var wallAsset = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); self.isSolid = true; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181818 }); /**** * Game Code ****/ // Add background image to the game area // Enemy (ghost) // Puzzle object // Key // Door (unlocked) // Door (locked) // Wall // Player // --- Game State --- var backgroundImg = LK.getAsset('background', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(backgroundImg); var currentFloor = 0; // 0: bottom, 1: 2nd, 2: 3rd, 3: 4th, 4: 5th, 5: top var floors = []; var player; var dragPlayer = false; var lastPlayerPos = { x: 0, y: 0 }; var keyObj = null; var doorObj = null; var ghostObj = null; var messageTxt = null; var floorTxt = null; var keySolved = false; var gameOver = false; // --- Room/Floor Layouts --- // Floor 0: Bottom floor (simple room, 1 puzzle, 1 ghost) function createFloor0() { var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // Rectangle room // Door (random position, not under floor list area) var door = new Door(); do { door.x = 200 + Math.random() * (2048 - 400); door.y = 200 + Math.random() * (2732 - 400); } while (door.x > 1700 && door.y < 1000); // avoid top right area under floor list floor.doors.push(door); // Key (random position, not under floor list area) var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // Ghost (bottom right, but not close to player) var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // Second ghost (top left, but not close to player) var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); return floor; } // Floor 1: 2nd floor (L-shaped room, 1 puzzle, 1 ghost) // Floor 5: Four rooms, each with different shape and size, combined together var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // --- Room 1: Large Rectangle (Top Left) --- // Top wall var wallR1Top = new Wall(); wallR1Top.x = 350; wallR1Top.y = 200; wallR1Top.width = 600; wallR1Top.height = 60; floor.walls.push(wallR1Top); // Left wall var wallR1Left = new Wall(); wallR1Left.x = 70; wallR1Left.y = 500; wallR1Left.width = 60; wallR1Left.height = 600; floor.walls.push(wallR1Left); // Bottom wall var wallR1Bottom = new Wall(); wallR1Bottom.x = 350; wallR1Bottom.y = 800; wallR1Bottom.width = 600; wallR1Bottom.height = 60; floor.walls.push(wallR1Bottom); // Right wall (shared with Room 2, has a door) // Shorten wall segments to leave a gap for the door at y=470 var wallR1RightA = new Wall(); wallR1RightA.x = 650; wallR1RightA.y = 370; // move up wallR1RightA.width = 60; wallR1RightA.height = 120; // shorter, ends above the door floor.walls.push(wallR1RightA); var wallR1RightB = new Wall(); wallR1RightB.x = 650; wallR1RightB.y = 730; wallR1RightB.width = 60; wallR1RightB.height = 200; floor.walls.push(wallR1RightB); // --- Room 2: Tall Rectangle (Top Right) --- // Top wall var wallR2Top = new Wall(); wallR2Top.x = 1200; wallR2Top.y = 200; wallR2Top.width = 600; wallR2Top.height = 60; floor.walls.push(wallR2Top); // Right wall var wallR2Right = new Wall(); wallR2Right.x = 1550; wallR2Right.y = 600; wallR2Right.width = 60; wallR2Right.height = 800; floor.walls.push(wallR2Right); // Bottom wall (shared with Room 3, has a door) // Shorten wall segments to leave a gap for the door at x=1200, y=1100 var wallR2BottomA = new Wall(); wallR2BottomA.x = 1075; wallR2BottomA.y = 1000; wallR2BottomA.width = 150; wallR2BottomA.height = 60; floor.walls.push(wallR2BottomA); var wallR2BottomB = new Wall(); wallR2BottomB.x = 1575; wallR2BottomB.y = 1000; wallR2BottomB.width = 150; wallR2BottomB.height = 60; floor.walls.push(wallR2BottomB); // Left wall (shared with Room 1, has a door) var wallR2LeftA = new Wall(); wallR2LeftA.x = 850; wallR2LeftA.y = 470; wallR2LeftA.width = 60; wallR2LeftA.height = 200; floor.walls.push(wallR2LeftA); var wallR2LeftB = new Wall(); wallR2LeftB.x = 850; wallR2LeftB.y = 730; wallR2LeftB.width = 60; wallR2LeftB.height = 200; floor.walls.push(wallR2LeftB); // --- Room 3: Square (Bottom Right) --- // Top wall (shared with Room 2, has a door) var wallR3TopA = new Wall(); wallR3TopA.x = 1200; wallR3TopA.y = 1200; wallR3TopA.width = 250; wallR3TopA.height = 60; floor.walls.push(wallR3TopA); var wallR3TopB = new Wall(); wallR3TopB.x = 1450; wallR3TopB.y = 1200; wallR3TopB.width = 250; wallR3TopB.height = 60; floor.walls.push(wallR3TopB); // Right wall var wallR3Right = new Wall(); wallR3Right.x = 1550; wallR3Right.y = 1500; wallR3Right.width = 60; wallR3Right.height = 600; floor.walls.push(wallR3Right); // Bottom wall var wallR3Bottom = new Wall(); wallR3Bottom.x = 1200; wallR3Bottom.y = 1800; wallR3Bottom.width = 600; wallR3Bottom.height = 60; floor.walls.push(wallR3Bottom); // Left wall (shared with Room 4, has a door) // Shorten wall segments to leave a gap for the door at y=1700 var wallR3LeftA = new Wall(); wallR3LeftA.x = 850; wallR3LeftA.y = 1300; wallR3LeftA.width = 60; wallR3LeftA.height = 120; floor.walls.push(wallR3LeftA); var wallR3LeftB = new Wall(); wallR3LeftB.x = 850; wallR3LeftB.y = 1820; wallR3LeftB.width = 60; wallR3LeftB.height = 120; floor.walls.push(wallR3LeftB); // --- Room 4: L-Shape (Bottom Left) --- // Top wall var wallR4Top = new Wall(); wallR4Top.x = 350; wallR4Top.y = 1200; wallR4Top.width = 600; wallR4Top.height = 60; floor.walls.push(wallR4Top); // Left wall var wallR4Left = new Wall(); wallR4Left.x = 70; wallR4Left.y = 1500; wallR4Left.width = 60; wallR4Left.height = 600; floor.walls.push(wallR4Left); // Bottom wall var wallR4Bottom = new Wall(); wallR4Bottom.x = 350; wallR4Bottom.y = 1800; wallR4Bottom.width = 600; wallR4Bottom.height = 60; floor.walls.push(wallR4Bottom); // Right wall (shared with Room 3, has a door) // Shorten wall segments to leave a gap for the door at y=1700 var wallR4RightA = new Wall(); wallR4RightA.x = 650; wallR4RightA.y = 1300; wallR4RightA.width = 60; wallR4RightA.height = 120; floor.walls.push(wallR4RightA); var wallR4RightB = new Wall(); wallR4RightB.x = 650; wallR4RightB.y = 1820; wallR4RightB.width = 60; wallR4RightB.height = 120; floor.walls.push(wallR4RightB); // --- Doors between rooms --- // Door between Room 1 and Room 2 (top horizontal) var door1 = new Door(); door1.x = 750; door1.y = 470; floor.doors.push(door1); // Door between Room 2 and Room 3 (vertical) var door2 = new Door(); door2.x = 1200; door2.y = 1100; floor.doors.push(door2); // Door between Room 3 and Room 4 (bottom horizontal) var door3 = new Door(); door3.x = 750; door3.y = 1700; floor.doors.push(door3); // Door between Room 4 and Room 1 (vertical) var door4 = new Door(); // Move door out of the wall: shift x to be just right of the wall (wall at x=70, wall thickness=60, room width=600, so wall edge at x=100, room starts at x=100, door at x=350 is center of wall, move to x=350+90=440) door4.x = 350 + 90; // move further right of wall, so door is fully reachable door4.y = 1000; floor.doors.push(door4); // Shorten bottom wall of Room 1 to leave a gap for the door at x=350, y=1000 // (wallR1Bottom is at y=800, so we need to adjust left wall of Room 4) var wallR4LeftA = new Wall(); wallR4LeftA.x = 70; wallR4LeftA.y = 1200; wallR4LeftA.width = 60; wallR4LeftA.height = 200; floor.walls.push(wallR4LeftA); var wallR4LeftB = new Wall(); wallR4LeftB.x = 70; wallR4LeftB.y = 1500; wallR4LeftB.width = 60; wallR4LeftB.height = 600; floor.walls.push(wallR4LeftB); // --- Key in Room 3 (bottom right) --- var key = new Key(); key.x = 1400; key.y = 1600; floor.puzzles.push(key); // --- Ghost in Room 2 (top right) --- var ghost = new Ghost(); ghost.x = 1300; ghost.y = 600; floor.enemies.push(ghost); function createFloor1() { var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // L-shape: Top wall // Door (random position, not under floor list area) var door = new Door(); do { door.x = 200 + Math.random() * (2048 - 400); door.y = 200 + Math.random() * (2732 - 400); } while (door.x > 1700 && door.y < 1000); // avoid top right area under floor list floor.doors.push(door); // Key (random position, not under floor list area) var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // Ghost (random, not close to player) var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // Second ghost (random, not close to player) var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); return floor; } // Floor 2: 3rd floor (T-shaped, 1 puzzle, 1 ghost) function createFloor2() { var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // T-shape: Top wall // Door (random position, not under floor list area) var door = new Door(); do { door.x = 200 + Math.random() * (2048 - 400); door.y = 200 + Math.random() * (2732 - 400); } while (door.x > 1700 && door.y < 1000); // avoid top right area under floor list floor.doors.push(door); // Key (random position, not under floor list area) var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // Ghost (random, not close to player) var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // Second ghost (random, not close to player) var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); return floor; } // Floor 3: 4th floor (U-shaped, 1 puzzle, 1 ghost) function createFloor3() { var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // U-shape: Top wall // Door (random position, not under floor list area) var door = new Door(); do { door.x = 200 + Math.random() * (2048 - 400); door.y = 200 + Math.random() * (2732 - 400); } while (door.x > 1700 && door.y < 1000); // avoid top right area under floor list floor.doors.push(door); // Key (random position, not under floor list area) var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // Ghost (random, not close to player) var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // Second ghost (random, not close to player) var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); return floor; } // Floor 4: 5th floor (original floor 0, four rooms) function createFloor4() { // Floor 5: Four rooms, each with different shape and size, combined together var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // --- Room 1: Large Rectangle (Top Left) --- // --- Doors between rooms --- // Only keep one main door for this floor var door = new Door(); do { door.x = 200 + Math.random() * (2048 - 400); door.y = 200 + Math.random() * (2732 - 400); } while (door.x > 1700 && door.y < 1000); // avoid top right area under floor list floor.doors.push(door); // Shorten bottom wall of Room 1 to leave a gap for the door at x=350, y=1000 // (wallR1Bottom is at y=800, so we need to adjust left wall of Room 4) // --- Key in Room 3 (random position) --- var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // --- Ghost 1 (random, not close to player) --- var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // --- Ghost 2 (random, not close to player) --- var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); return floor; } // Floor 5: Top floor (original floor 1, exit) function createFloor5() { var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // Walls (rectangle room) // Exit Door (top center, unlocked if puzzle solved) var door = new Door(); door.x = 2048 / 2; door.y = 400; door.locked = false; door.doorAsset.destroy(); door.doorAsset = door.attachAsset('door_unlocked', { anchorX: 0.5, anchorY: 0.5 }); floor.doors.push(door); // Key in a random position var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // Ghost (random, not close to player) var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // Second ghost (random, not close to player) var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); // Upstairs: 1 room, exit door (unlocked if puzzle solved), 1 ghost var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // Walls (rectangle room) // Exit Door (top center, unlocked if puzzle solved) var door = new Door(); door.x = 2048 / 2; door.y = 400; door.locked = false; door.doorAsset.destroy(); door.doorAsset = door.attachAsset('door_unlocked', { anchorX: 0.5, anchorY: 0.5 }); floor.doors.push(door); // Key in the center of the room var key = new Key(); key.x = 2048 / 2; key.y = 2732 / 2; floor.puzzles.push(key); // Ghost (patrols horizontally) var ghost = new Ghost(); ghost.x = 2048 / 2; ghost.y = 1200; floor.enemies.push(ghost); return floor; } // --- Helper Functions --- function clearFloor() { // Remove all objects from game if (floors[currentFloor]) { var f = floors[currentFloor]; for (var i = 0; i < f.walls.length; ++i) f.walls[i].destroy(); for (var i = 0; i < f.doors.length; ++i) f.doors[i].destroy(); for (var i = 0; i < f.keys.length; ++i) f.keys[i].destroy(); for (var i = 0; i < f.puzzles.length; ++i) f.puzzles[i].destroy(); for (var i = 0; i < f.enemies.length; ++i) f.enemies[i].destroy(); } if (doorObj) { if (typeof doorObj.destroy === "function") { doorObj.destroy(); } doorObj = null; } if (keyObj) { if (typeof keyObj.destroy === "function") { keyObj.destroy(); } keyObj = null; } if (ghostObj) { ghostObj.destroy(); ghostObj = null; } } function setupFloor(floorNum) { clearFloor(); var f = floors[floorNum]; // Add walls for (var i = 0; i < f.walls.length; ++i) game.addChild(f.walls[i]); // Add doors for (var i = 0; i < f.doors.length; ++i) game.addChild(f.doors[i]); // Add puzzles for (var i = 0; i < f.puzzles.length; ++i) game.addChild(f.puzzles[i]); // Add enemies for (var i = 0; i < f.enemies.length; ++i) game.addChild(f.enemies[i]); // For easy reference // Set doorObj to the first locked door, or the first door if none are locked doorObj = null; for (var i = 0; i < f.doors.length; ++i) { if (f.doors[i].locked) { doorObj = f.doors[i]; break; } } if (!doorObj && f.doors.length) doorObj = f.doors[0]; keyObj = null; // Set keyObj to the first unsolved key, or null if all solved keyObj = null; for (var i = 0; i < f.puzzles.length; ++i) { if (!f.puzzles[i].solved) { keyObj = f.puzzles[i]; break; } } ghostObj = f.enemies.length ? f.enemies[0] : null; } // --- GUI --- messageTxt = new Text2('', { size: 90, fill: 0xFFCCCC }); messageTxt.anchor.set(0.5, 0); LK.gui.top.addChild(messageTxt); floorTxt = new Text2('Floor 1', { size: 70, fill: 0xCCCCFF }); floorTxt.anchor.set(0.5, 0); LK.gui.top.addChild(floorTxt); // --- Game Setup --- floors[0] = createFloor0(); floors[1] = createFloor1(); floors[2] = createFloor2(); floors[3] = createFloor3(); floors[4] = createFloor4(); floors[5] = createFloor5(); // Add 14 more floors (floors 6 to 19) for (var i = 6; i < 20; ++i) { // Each new floor is a random room with 1 door, 1 key, 2 ghosts floors[i] = function () { var floor = { walls: [], doors: [], keys: [], puzzles: [], enemies: [] }; // Door (random position, not under floor list area) var door = new Door(); do { door.x = 200 + Math.random() * (2048 - 400); door.y = 200 + Math.random() * (2732 - 400); } while (door.x > 1700 && door.y < 1000); // avoid top right area under floor list floor.doors.push(door); // Key (random position, not under floor list area) var key = new Key(); do { key.x = 200 + Math.random() * (2048 - 400); key.y = 200 + Math.random() * (2732 - 400); } while (key.x > 1700 && key.y < 1000); // avoid top right area under floor list floor.puzzles.push(key); // Ghost 1 (random, not close to player start) var ghost = new Ghost(); do { ghost.x = 200 + Math.random() * (2048 - 400); ghost.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost.x - 2048 / 2, 2) + Math.pow(ghost.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost); // Ghost 2 (random, not close to player start) var ghost2 = new Ghost(); do { ghost2.x = 200 + Math.random() * (2048 - 400); ghost2.y = 200 + Math.random() * (2732 - 400); } while (Math.sqrt(Math.pow(ghost2.x - 2048 / 2, 2) + Math.pow(ghost2.y - (2732 - 700), 2)) < 400); floor.enemies.push(ghost2); return floor; }(); } player = new Player(); player.x = 2048 / 2; player.y = 2732 - 700; game.addChild(player); setupFloor(0); updateFloorText(); // --- Life Counter GUI (bottom left) --- // Heart icon asset (using emoji for now, can be replaced with image asset if available) var heartIcons = []; var maxHearts = 6; // reasonable max for layout, can be increased if needed function updateHearts(lives) { // Remove old hearts for (var i = 0; i < heartIcons.length; ++i) { if (heartIcons[i] && typeof heartIcons[i].destroy === "function") { heartIcons[i].destroy(); } } heartIcons = []; // Add new hearts var spacing = 80; var size = 90; for (var i = 0; i < lives; ++i) { var heart = new Text2("❤", { size: size, fill: 0xFF3B3B }); heart.anchor.set(0, 1); // left align, bottom heart.x = i * spacing; heart.y = 0; LK.gui.bottomLeft.addChild(heart); heartIcons.push(heart); } } // Initialize with 1 life updateHearts(1); // --- Floor List GUI (top right) --- var floorListContainer = new Container(); floorListContainer.x = 0; floorListContainer.y = 0; LK.gui.topRight.addChild(floorListContainer); function updateFloorList() { // Remove old children if (floorListContainer && floorListContainer.children) { while (floorListContainer.children.length) { floorListContainer.children[0].destroy(); } } // List from top (highest floor) to bottom (lowest) var y = 40; for (var i = floors.length - 1; i >= 0; --i) { var label = "Floor " + (i + 1); var txt = new Text2(label, { size: 60, fill: i === currentFloor ? "#FFD700" : "#CCCCFF" }); txt.anchor.set(1, 0); // right align txt.x = 0; txt.y = y; if (floorListContainer && typeof floorListContainer.addChild === "function") { floorListContainer.addChild(txt); } y += 90; } } updateFloorList(); function updateFloorText() { floorTxt.setText('Floor ' + (currentFloor + 1)); updateFloorList(); } // --- Movement & Controls --- function canMoveTo(x, y) { // Check collision with walls var f = floors[currentFloor]; for (var i = 0; i < f.walls.length; ++i) { var wall = f.walls[i]; // Simple AABB collision var dx = Math.abs(x - wall.x); var dy = Math.abs(y - wall.y); if (dx < wall.width / 2 + 60 && dy < wall.height / 2 + 60) { return false; } } return true; } function handleMove(x, y, obj) { if (gameOver) return; if (!dragPlayer) return; // Clamp to game area var px = Math.max(60, Math.min(2048 - 60, x)); var py = Math.max(60, Math.min(2732 - 60, y)); // Only move if not colliding with wall if (canMoveTo(px, py)) { player.moveTo(px, py); } } game.down = function (x, y, obj) { if (gameOver) return; // Only start drag if touch/click is on player var dx = x - player.x; var dy = y - player.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 100) { dragPlayer = true; lastPlayerPos.x = player.x; lastPlayerPos.y = player.y; handleMove(x, y, obj); } }; game.move = function (x, y, obj) { handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragPlayer = false; }; // --- Puzzle Interaction --- function tryCollectKey() { if (!keyObj || keyObj.solved) return; // Simple key: tap key to collect keyObj.solved = true; keySolved = true; messageTxt.setText("You found a key!\nThe door unlocked."); // Unlock the corresponding door for the collected key var f = floors[currentFloor]; if (f && f.puzzles && f.doors) { // Find the index of the collected key in the floor's puzzles array var keyIdx = -1; for (var i = 0; i < f.puzzles.length; ++i) { if (f.puzzles[i] === keyObj) { keyIdx = i; break; } } // Unlock the door with the same index (if exists and locked) if (keyIdx >= 0 && f.doors[keyIdx] && f.doors[keyIdx].locked) { f.doors[keyIdx].unlock(); } } // Fade out the key when collected if (keyObj) { tween(keyObj, { alpha: 0 }, { duration: 800 }); } LK.setTimeout(function () { messageTxt.setText(''); }, 1500); } // --- Door Interaction --- function tryOpenDoor() { if (!doorObj) return; if (doorObj.locked) { messageTxt.setText("The door is locked."); LK.setTimeout(function () { messageTxt.setText(''); }, 1200); } else { // Go to next floor or win if (currentFloor < floors.length - 1) { // Go upstairs currentFloor++; setupFloor(currentFloor); player.x = 2048 / 2; player.y = 2732 - 700; updateFloorText(); // If reached floor 20 (index 19), win the game if (currentFloor === 19) { LK.showYouWin(); return; } messageTxt.setText("You ascend to the next floor..."); LK.setTimeout(function () { messageTxt.setText(''); }, 1200); } else { // Win! LK.showYouWin(); } } } // --- Enemy (Ghost) Collision --- function checkGhostCollision() { if (!ghostObj) return; var dx = player.x - ghostObj.x; var dy = player.y - ghostObj.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < 90) { // Only trigger on new contact if (!player.lastGhostContact || !player.lastGhostContact[ghostObj] || !player.lastGhostContact[ghostObj].wasColliding) { if (typeof player.lives === "undefined") player.lives = 1; player.lives -= 1; updateHearts(player.lives); if (player.lives <= 0) { gameOver = true; player.canMove = false; messageTxt.setText("A ghost caught you!"); LK.effects.flashScreen(0x990000, 1200); LK.setTimeout(function () { LK.showGameOver(); }, 1200); } else { messageTxt.setText("A ghost hit you! Lives left: " + player.lives); LK.effects.flashScreen(0x990000, 600); player.canMove = false; // Briefly pause movement after hit LK.setTimeout(function () { player.canMove = true; messageTxt.setText(''); }, 900); } // Track collision state for this ghost if (!player.lastGhostContact) player.lastGhostContact = {}; player.lastGhostContact[ghostObj] = { wasColliding: true }; } } else { // Not colliding, reset collision state for this ghost if (player.lastGhostContact && player.lastGhostContact[ghostObj]) { player.lastGhostContact[ghostObj].wasColliding = false; } } } // --- Main Game Update --- game.update = function () { if (gameOver) return; // Ghost patrol if (ghostObj && ghostObj.update) ghostObj.update(); // Check for key interaction (support multiple keys per floor) var f = floors[currentFloor]; if (f && f.puzzles) { for (var i = 0; i < f.puzzles.length; ++i) { var k = f.puzzles[i]; if (!k.solved) { var dx = player.x - k.x; var dy = player.y - k.y; if (Math.sqrt(dx * dx + dy * dy) < 100 && dragPlayer) { keyObj = k; tryCollectKey(); break; } } } } // Check for door interaction (support multiple doors per floor) if (f && f.doors) { for (var i = 0; i < f.doors.length; ++i) { var dr = f.doors[i]; var dx = player.x - dr.x; var dy = player.y - dr.y; if (Math.abs(dx) < 80 && Math.abs(dy) < 80 && dragPlayer) { doorObj = dr; if (dr.locked) { tryOpenDoor(); } else { // Move player through the door (to the other side of the door) if (currentFloor < floors.length - 1) { // Go upstairs currentFloor++; setupFloor(currentFloor); player.x = 2048 / 2; player.y = 2732 - 700; updateFloorText(); // If reached floor 20 (index 19), win the game if (currentFloor === 19) { LK.showYouWin(); return; } // Give extra life on floor 10 (index 9) if (currentFloor === 9 && typeof player !== "undefined" && player) { if (typeof player.lives === "undefined") player.lives = 1; player.lives += 1; updateHearts(player.lives); messageTxt.setText("You gained an extra life!"); LK.setTimeout(function () { messageTxt.setText(''); }, 1500); } messageTxt.setText("You ascend to the next floor..."); LK.setTimeout(function () { messageTxt.setText(''); }, 1200); } else if (currentFloor > 0) { // Move player to one floor down currentFloor--; setupFloor(currentFloor); player.x = 2048 / 2; player.y = 2732 - 700; updateFloorText(); messageTxt.setText("You descend to the previous floor..."); LK.setTimeout(function () { messageTxt.setText(''); }, 1200); } } break; } } } // Check for ghost collision checkGhostCollision(); };
===================================================================
--- original.js
+++ change.js
@@ -828,14 +828,36 @@
game.addChild(player);
setupFloor(0);
updateFloorText();
// --- Life Counter GUI (bottom left) ---
-var lifeTxt = new Text2('Lives: 1', {
- size: 90,
- fill: 0xFFD700
-});
-lifeTxt.anchor.set(0, 1); // left align, bottom
-LK.gui.bottomLeft.addChild(lifeTxt);
+// Heart icon asset (using emoji for now, can be replaced with image asset if available)
+var heartIcons = [];
+var maxHearts = 6; // reasonable max for layout, can be increased if needed
+function updateHearts(lives) {
+ // Remove old hearts
+ for (var i = 0; i < heartIcons.length; ++i) {
+ if (heartIcons[i] && typeof heartIcons[i].destroy === "function") {
+ heartIcons[i].destroy();
+ }
+ }
+ heartIcons = [];
+ // Add new hearts
+ var spacing = 80;
+ var size = 90;
+ for (var i = 0; i < lives; ++i) {
+ var heart = new Text2("❤", {
+ size: size,
+ fill: 0xFF3B3B
+ });
+ heart.anchor.set(0, 1); // left align, bottom
+ heart.x = i * spacing;
+ heart.y = 0;
+ LK.gui.bottomLeft.addChild(heart);
+ heartIcons.push(heart);
+ }
+}
+// Initialize with 1 life
+updateHearts(1);
// --- Floor List GUI (top right) ---
var floorListContainer = new Container();
floorListContainer.x = 0;
floorListContainer.y = 0;
@@ -991,11 +1013,9 @@
// Only trigger on new contact
if (!player.lastGhostContact || !player.lastGhostContact[ghostObj] || !player.lastGhostContact[ghostObj].wasColliding) {
if (typeof player.lives === "undefined") player.lives = 1;
player.lives -= 1;
- if (typeof lifeTxt !== "undefined" && lifeTxt) {
- lifeTxt.setText("Lives: " + player.lives);
- }
+ updateHearts(player.lives);
if (player.lives <= 0) {
gameOver = true;
player.canMove = false;
messageTxt.setText("A ghost caught you!");
@@ -1074,11 +1094,9 @@
// Give extra life on floor 10 (index 9)
if (currentFloor === 9 && typeof player !== "undefined" && player) {
if (typeof player.lives === "undefined") player.lives = 1;
player.lives += 1;
- if (typeof lifeTxt !== "undefined" && lifeTxt) {
- lifeTxt.setText("Lives: " + player.lives);
- }
+ updateHearts(player.lives);
messageTxt.setText("You gained an extra life!");
LK.setTimeout(function () {
messageTxt.setText('');
}, 1500);