/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { level: 1, collectedKeys: 0, lives: 3 }); /**** * Classes ****/ var Door = Container.expand(function () { var self = Container.call(this); var doorGraphics = self.attachAsset('door', { anchorX: 0.5, anchorY: 0.5 }); self.isLocked = true; self.unlock = function () { self.isLocked = false; tween(doorGraphics, { alpha: 0.3 }, { duration: 500 }); LK.getSound('unlockDoor').play(); }; return self; }); var Explorer = Container.expand(function () { var self = Container.call(this); var explorerGraphics = self.attachAsset('explorer', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 10; self.isMoving = false; self.direction = null; self.targetX = 0; self.targetY = 0; self.hasKey = false; self.moveToward = function (x, y) { self.isMoving = true; self.targetX = x; self.targetY = y; // Calculate direction var dx = self.targetX - self.x; var dy = self.targetY - self.y; // Determine primary direction based on larger delta if (Math.abs(dx) > Math.abs(dy)) { self.direction = dx > 0 ? 'right' : 'left'; } else { self.direction = dy > 0 ? 'down' : 'up'; } }; self.stopMoving = function () { self.isMoving = false; self.direction = null; }; self.update = function () { if (self.isMoving) { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.speed) { self.x = self.targetX; self.y = self.targetY; self.stopMoving(); } else { var ratio = self.speed / distance; self.x += dx * ratio; self.y += dy * ratio; } } }; self.collectKey = function () { self.hasKey = true; tween(explorerGraphics, { tint: 0xFFD700 }, { duration: 300, onFinish: function onFinish() { tween(explorerGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } }); }; self.useKey = function () { self.hasKey = false; storage.collectedKeys++; }; self.takeDamage = function () { LK.effects.flashObject(self, 0xFF0000, 500); storage.lives--; LK.getSound('damage').play(); if (storage.lives <= 0) { LK.showGameOver(); } }; return self; }); var FallingRock = Container.expand(function () { var self = Container.call(this); var rockGraphics = self.attachAsset('rock', { anchorX: 0.5, anchorY: 0.5 }); self.isTriggered = false; self.isFalling = false; self.initialY = 0; self.fallSpeed = 0; self.resetTimer = 0; self.resetDelay = 180; // 3 seconds self.trigger = function () { if (!self.isTriggered && !self.isFalling) { self.isTriggered = true; self.fallSpeed = 2; // Start with slow fall // Shake before falling tween(rockGraphics, { x: 5 }, { duration: 100, onFinish: function onFinish() { tween(rockGraphics, { x: -5 }, { duration: 100, onFinish: function onFinish() { tween(rockGraphics, { x: 0 }, { duration: 100, onFinish: function onFinish() { self.isFalling = true; self.isTriggered = false; } }); } }); } }); } }; self.reset = function () { self.y = self.initialY; self.isFalling = false; self.fallSpeed = 0; self.resetTimer = 0; }; self.update = function () { if (self.isFalling) { self.fallSpeed += 0.2; // Acceleration self.y += self.fallSpeed; // Check if rock has fallen out of view if (self.y > 2832) { self.isFalling = false; self.resetTimer = 0; } } else if (self.y !== self.initialY) { // Reset timer self.resetTimer++; if (self.resetTimer >= self.resetDelay) { self.reset(); } } }; return self; }); var Key = Container.expand(function () { var self = Container.call(this); var keyGraphics = self.attachAsset('key', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Float animation keyGraphics.y = Math.sin(LK.ticks / 20) * 5; // Rotate slowly keyGraphics.rotation += 0.01; }; return self; }); var River = Container.expand(function () { var self = Container.call(this); var riverGraphics = self.attachAsset('river', { anchorX: 0.5, anchorY: 0.5 }); self.hasBridge = false; self.addBridge = function () { if (!self.hasBridge) { var bridge = self.attachAsset('bridge', { anchorX: 0.5, anchorY: 0.5 }); self.hasBridge = true; return bridge; } }; self.update = function () { // Flowing water animation riverGraphics.tint = 0x1E88E5 + Math.floor(Math.sin(LK.ticks / 20) * 20) * 0x000101; }; return self; }); var Spike = Container.expand(function () { var self = Container.call(this); var spikeGraphics = self.attachAsset('spike', { anchorX: 0.5, anchorY: 0.5 }); self.isActive = false; self.timer = 0; self.cycleTime = 120; // 2 seconds at 60fps self.update = function () { self.timer++; if (self.timer >= self.cycleTime) { self.timer = 0; self.isActive = !self.isActive; if (self.isActive) { tween(spikeGraphics, { scaleY: 1 }, { duration: 300 }); } else { tween(spikeGraphics, { scaleY: 0.2 }, { duration: 300 }); } } }; // Initialize in retracted state spikeGraphics.scaleY = 0.2; return self; }); var Treasure = Container.expand(function () { var self = Container.call(this); var treasureGraphics = self.attachAsset('treasure', { anchorX: 0.5, anchorY: 0.5 }); self.isCollected = false; self.collect = function () { if (!self.isCollected) { self.isCollected = true; tween(treasureGraphics, { scaleX: 1.3, scaleY: 1.3 }, { duration: 300, onFinish: function onFinish() { tween(treasureGraphics, { scaleX: 0, scaleY: 0 }, { duration: 300 }); } }); LK.setScore(LK.getScore() + 100); LK.getSound('collectTreasure').play(); // Check if all treasures are collected var allCollected = true; for (var i = 0; i < treasures.length; i++) { if (!treasures[i].isCollected) { allCollected = false; break; } } if (allCollected) { // Level complete storage.level++; LK.showYouWin(); } } }; self.update = function () { if (!self.isCollected) { // Shine animation var glowIntensity = (Math.sin(LK.ticks / 30) + 1) / 2; treasureGraphics.alpha = 0.7 + glowIntensity * 0.3; } }; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wall', { anchorX: 0.5, anchorY: 0.5 }); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x607D8B // Cave-like dark blue-gray }); /**** * Game Code ****/ // Game variables var tileSize = 100; var gridWidth = 20; var gridHeight = 27; var explorer; var walls = []; var keys = []; var doors = []; var treasures = []; var spikes = []; var fallingRocks = []; var rivers = []; var bridges = []; var levelGrid = []; var gameStarted = false; // UI Elements var scoreTxt = new Text2('0', { size: 80, fill: 0xFFFFFF }); var levelTxt = new Text2('Level: ' + storage.level, { size: 60, fill: 0xFFFFFF }); var keysTxt = new Text2('Keys: ' + storage.collectedKeys, { size: 60, fill: 0xFFD700 }); var livesTxt = new Text2('Lives: ' + storage.lives, { size: 60, fill: 0xFF5252 }); // Initialize game function initializeGame() { // Clear previous game elements resetGameElements(); // Generate level based on current level generateLevel(storage.level); // Initialize explorer createExplorer(); // Setup UI setupUI(); // Start game gameStarted = true; // Play background music LK.playMusic('caveMusic', { fade: { start: 0, end: 0.3, duration: 1000 } }); } function resetGameElements() { // Remove all existing game elements for (var i = 0; i < walls.length; i++) { walls[i].destroy(); } walls = []; for (var i = 0; i < keys.length; i++) { keys[i].destroy(); } keys = []; for (var i = 0; i < doors.length; i++) { doors[i].destroy(); } doors = []; for (var i = 0; i < treasures.length; i++) { treasures[i].destroy(); } treasures = []; for (var i = 0; i < spikes.length; i++) { spikes[i].destroy(); } spikes = []; for (var i = 0; i < fallingRocks.length; i++) { fallingRocks[i].destroy(); } fallingRocks = []; for (var i = 0; i < rivers.length; i++) { rivers[i].destroy(); } rivers = []; for (var i = 0; i < bridges.length; i++) { bridges[i].destroy(); } bridges = []; levelGrid = []; if (explorer) { explorer.destroy(); explorer = null; } } function createExplorer() { explorer = new Explorer(); game.addChild(explorer); // Position explorer at start position for (var y = 0; y < gridHeight; y++) { for (var x = 0; x < gridWidth; x++) { if (levelGrid[y][x] === 'S') { explorer.x = x * tileSize + tileSize / 2; explorer.y = y * tileSize + tileSize / 2; break; } } } } function setupUI() { // Setup score text scoreTxt.setText(LK.getScore()); scoreTxt.anchor.set(1, 0); LK.gui.topRight.addChild(scoreTxt); // Setup level text levelTxt.setText('Level: ' + storage.level); levelTxt.anchor.set(0.5, 0); levelTxt.y = 80; LK.gui.top.addChild(levelTxt); // Setup keys text keysTxt.setText('Keys: ' + storage.collectedKeys); keysTxt.anchor.set(0, 0); keysTxt.y = 80; LK.gui.topRight.addChild(keysTxt); // Setup lives text livesTxt.setText('Lives: ' + storage.lives); livesTxt.anchor.set(0, 0); LK.gui.topRight.addChild(livesTxt); } function generateLevel(level) { // Define different level layouts var layouts = []; // Level 1: Simple tutorial level layouts[1] = ["WWWWWWWWWWWWWWWWWWWW", "W W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W W W", "W W W WWWWWWWWWW W W", "W W W W W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W W W", "W WWWWWWWWWWWWWWWW W", "W W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W W W W", "W W W WWWWWWWWW W W W", "W W W W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W TS W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"]; // Level 2: Introducing spikes layouts[2] = ["WWWWWWWWWWWWWWWWWWWW", "W W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W W W", "W W W WWWWWWWWWW W W", "W W W W W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W X W W W", "W WWWWWWWWWWWWWWWW W", "W X X W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W X W W W", "W W W WWWWWWWWW W W W", "W W W X W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W TS W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"]; // Level 3: Introducing falling rocks layouts[3] = ["WWWWWWWWWWWWWWWWWWWW", "W W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W F W W", "W W W WWWWWWWWWW W W", "W W W W F W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W F X W W W", "W WWWWWWWWWWWWWWWW W", "W X F X W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W X F W W W", "W W W WWWWWWWWW W W W", "W W W F X W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W TS W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"]; // Level 4: Introducing rivers layouts[4] = ["WWWWWWWWWWWWWWWWWWWW", "WS W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W F W W", "W W W WWWWWWWWWW W W", "W W W W F W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W F X W W W", "WRRRRRRRRRRRRRRRRR W", "W X F X W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W X F W W W", "W W W WWWWWWWWW W W W", "W W W F X W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W T W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"]; // Get layout for current level or use level 4 for any higher levels var currentLayout = layouts[Math.min(level, 4)]; // Parse level layout for (var y = 0; y < currentLayout.length; y++) { levelGrid[y] = []; for (var x = 0; x < currentLayout[y].length; x++) { var cellType = currentLayout[y][x]; levelGrid[y][x] = cellType; var xPos = x * tileSize + tileSize / 2; var yPos = y * tileSize + tileSize / 2; switch (cellType) { case 'W': // Wall var wall = new Wall(); wall.x = xPos; wall.y = yPos; game.addChild(wall); walls.push(wall); break; case 'K': // Key var key = new Key(); key.x = xPos; key.y = yPos; game.addChild(key); keys.push(key); break; case 'D': // Door var door = new Door(); door.x = xPos; door.y = yPos; game.addChild(door); doors.push(door); break; case 'T': // Treasure var treasure = new Treasure(); treasure.x = xPos; treasure.y = yPos; game.addChild(treasure); treasures.push(treasure); break; case 'X': // Spike trap var spike = new Spike(); spike.x = xPos; spike.y = yPos; game.addChild(spike); spikes.push(spike); break; case 'F': // Falling rock var rock = new FallingRock(); rock.x = xPos; rock.y = yPos; rock.initialY = yPos; game.addChild(rock); fallingRocks.push(rock); break; case 'R': // River var river = new River(); river.x = xPos; river.y = yPos; game.addChild(river); rivers.push(river); break; } } } } function getGridPosition(x, y) { var gridX = Math.floor(x / tileSize); var gridY = Math.floor(y / tileSize); if (gridX >= 0 && gridX < gridWidth && gridY >= 0 && gridY < gridHeight) { return { x: gridX, y: gridY }; } return null; } function isWalkable(gridX, gridY) { if (gridX < 0 || gridX >= gridWidth || gridY < 0 || gridY >= gridHeight) { return false; } var cellType = levelGrid[gridY][gridX]; // Check if cell is walkable if (cellType === 'W') { return false; } // Check if door is locked if (cellType === 'D') { var door = getDoorAt(gridX, gridY); return door && !door.isLocked; } // Check if river has bridge if (cellType === 'R') { var river = getRiverAt(gridX, gridY); return river && river.hasBridge; } return true; } function getDoorAt(gridX, gridY) { for (var i = 0; i < doors.length; i++) { var doorPos = getGridPosition(doors[i].x, doors[i].y); if (doorPos && doorPos.x === gridX && doorPos.y === gridY) { return doors[i]; } } return null; } function getRiverAt(gridX, gridY) { for (var i = 0; i < rivers.length; i++) { var riverPos = getGridPosition(rivers[i].x, rivers[i].y); if (riverPos && riverPos.x === gridX && riverPos.y === gridY) { return rivers[i]; } } return null; } // Update UI function updateUI() { scoreTxt.setText(LK.getScore()); levelTxt.setText('Level: ' + storage.level); keysTxt.setText('Keys: ' + storage.collectedKeys); livesTxt.setText('Lives: ' + storage.lives); } // Check for collisions function checkCollisions() { if (!explorer) { return; } var explorerPos = getGridPosition(explorer.x, explorer.y); if (!explorerPos) { return; } var cellType = levelGrid[explorerPos.y][explorerPos.x]; // Check key collision if (cellType === 'K') { for (var i = 0; i < keys.length; i++) { var keyPos = getGridPosition(keys[i].x, keys[i].y); if (keyPos && keyPos.x === explorerPos.x && keyPos.y === explorerPos.y) { explorer.collectKey(); keys[i].destroy(); keys.splice(i, 1); levelGrid[explorerPos.y][explorerPos.x] = ' '; LK.getSound('collect').play(); break; } } } // Check door collision if (cellType === 'D') { var door = getDoorAt(explorerPos.x, explorerPos.y); if (door && door.isLocked && explorer.hasKey) { door.unlock(); explorer.useKey(); keysTxt.setText('Keys: ' + storage.collectedKeys); } } // Check treasure collision if (cellType === 'T') { for (var i = 0; i < treasures.length; i++) { var treasurePos = getGridPosition(treasures[i].x, treasures[i].y); if (treasurePos && treasurePos.x === explorerPos.x && treasurePos.y === explorerPos.y && !treasures[i].isCollected) { treasures[i].collect(); break; } } } // Check spike collision for (var i = 0; i < spikes.length; i++) { if (spikes[i].isActive && explorer.intersects(spikes[i])) { explorer.takeDamage(); // Move player to a safe position var safeX = explorer.x; var safeY = explorer.y - tileSize; if (isWalkable(Math.floor(safeX / tileSize), Math.floor(safeY / tileSize))) { explorer.x = safeX; explorer.y = safeY; } } } // Check falling rock collision for (var i = 0; i < fallingRocks.length; i++) { var rock = fallingRocks[i]; // Trigger rock if explorer is underneath var rockPos = getGridPosition(rock.x, rock.y); if (rockPos && explorerPos.x === rockPos.x && explorerPos.y > rockPos.y && !rock.isTriggered && !rock.isFalling) { rock.trigger(); } // Check if rock hits explorer if (rock.isFalling && explorer.intersects(rock)) { explorer.takeDamage(); rock.reset(); } } // Check river collision (player falls in if there's no bridge) for (var i = 0; i < rivers.length; i++) { var river = rivers[i]; var riverPos = getGridPosition(river.x, river.y); if (riverPos && explorerPos.x === riverPos.x && explorerPos.y === riverPos.y && !river.hasBridge) { explorer.takeDamage(); // Move player to a safe position var safeX = explorer.x; var safeY = explorer.y - tileSize; if (isWalkable(Math.floor(safeX / tileSize), Math.floor(safeY / tileSize))) { explorer.x = safeX; explorer.y = safeY; } } } } function moveExplorer(targetX, targetY) { if (!explorer || explorer.isMoving) { return; } var currentGridPos = getGridPosition(explorer.x, explorer.y); var targetGridPos = getGridPosition(targetX, targetY); if (!currentGridPos || !targetGridPos) { return; } // Only allow movement to adjacent cells var dx = Math.abs(targetGridPos.x - currentGridPos.x); var dy = Math.abs(targetGridPos.y - currentGridPos.y); if (dx === 1 && dy === 0 || dx === 0 && dy === 1) { if (isWalkable(targetGridPos.x, targetGridPos.y)) { var cellCenterX = targetGridPos.x * tileSize + tileSize / 2; var cellCenterY = targetGridPos.y * tileSize + tileSize / 2; explorer.moveToward(cellCenterX, cellCenterY); } } } // Handle touch/mouse events function handleGameInput(x, y, obj) { if (!gameStarted) { return; } moveExplorer(x, y); } // Start game when page loads initializeGame(); // Handle touch/mouse events game.down = handleGameInput; // Game update loop game.update = function () { if (!gameStarted) { return; } // Update UI updateUI(); // Check collisions checkCollisions(); // Add bridge to first river after collecting all keys (for level 4) if (storage.level >= 4 && storage.collectedKeys >= 1) { for (var i = 0; i < rivers.length; i++) { if (!rivers[i].hasBridge) { rivers[i].addBridge(); break; } } } };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,715 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ level: 1,
+ collectedKeys: 0,
+ lives: 3
+});
+
+/****
+* Classes
+****/
+var Door = Container.expand(function () {
+ var self = Container.call(this);
+ var doorGraphics = self.attachAsset('door', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.isLocked = true;
+ self.unlock = function () {
+ self.isLocked = false;
+ tween(doorGraphics, {
+ alpha: 0.3
+ }, {
+ duration: 500
+ });
+ LK.getSound('unlockDoor').play();
+ };
+ return self;
+});
+var Explorer = Container.expand(function () {
+ var self = Container.call(this);
+ var explorerGraphics = self.attachAsset('explorer', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 10;
+ self.isMoving = false;
+ self.direction = null;
+ self.targetX = 0;
+ self.targetY = 0;
+ self.hasKey = false;
+ self.moveToward = function (x, y) {
+ self.isMoving = true;
+ self.targetX = x;
+ self.targetY = y;
+ // Calculate direction
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ // Determine primary direction based on larger delta
+ if (Math.abs(dx) > Math.abs(dy)) {
+ self.direction = dx > 0 ? 'right' : 'left';
+ } else {
+ self.direction = dy > 0 ? 'down' : 'up';
+ }
+ };
+ self.stopMoving = function () {
+ self.isMoving = false;
+ self.direction = null;
+ };
+ self.update = function () {
+ if (self.isMoving) {
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < self.speed) {
+ self.x = self.targetX;
+ self.y = self.targetY;
+ self.stopMoving();
+ } else {
+ var ratio = self.speed / distance;
+ self.x += dx * ratio;
+ self.y += dy * ratio;
+ }
+ }
+ };
+ self.collectKey = function () {
+ self.hasKey = true;
+ tween(explorerGraphics, {
+ tint: 0xFFD700
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ tween(explorerGraphics, {
+ tint: 0xFFFFFF
+ }, {
+ duration: 300
+ });
+ }
+ });
+ };
+ self.useKey = function () {
+ self.hasKey = false;
+ storage.collectedKeys++;
+ };
+ self.takeDamage = function () {
+ LK.effects.flashObject(self, 0xFF0000, 500);
+ storage.lives--;
+ LK.getSound('damage').play();
+ if (storage.lives <= 0) {
+ LK.showGameOver();
+ }
+ };
+ return self;
+});
+var FallingRock = Container.expand(function () {
+ var self = Container.call(this);
+ var rockGraphics = self.attachAsset('rock', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.isTriggered = false;
+ self.isFalling = false;
+ self.initialY = 0;
+ self.fallSpeed = 0;
+ self.resetTimer = 0;
+ self.resetDelay = 180; // 3 seconds
+ self.trigger = function () {
+ if (!self.isTriggered && !self.isFalling) {
+ self.isTriggered = true;
+ self.fallSpeed = 2; // Start with slow fall
+ // Shake before falling
+ tween(rockGraphics, {
+ x: 5
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ tween(rockGraphics, {
+ x: -5
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ tween(rockGraphics, {
+ x: 0
+ }, {
+ duration: 100,
+ onFinish: function onFinish() {
+ self.isFalling = true;
+ self.isTriggered = false;
+ }
+ });
+ }
+ });
+ }
+ });
+ }
+ };
+ self.reset = function () {
+ self.y = self.initialY;
+ self.isFalling = false;
+ self.fallSpeed = 0;
+ self.resetTimer = 0;
+ };
+ self.update = function () {
+ if (self.isFalling) {
+ self.fallSpeed += 0.2; // Acceleration
+ self.y += self.fallSpeed;
+ // Check if rock has fallen out of view
+ if (self.y > 2832) {
+ self.isFalling = false;
+ self.resetTimer = 0;
+ }
+ } else if (self.y !== self.initialY) {
+ // Reset timer
+ self.resetTimer++;
+ if (self.resetTimer >= self.resetDelay) {
+ self.reset();
+ }
+ }
+ };
+ return self;
+});
+var Key = Container.expand(function () {
+ var self = Container.call(this);
+ var keyGraphics = self.attachAsset('key', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.update = function () {
+ // Float animation
+ keyGraphics.y = Math.sin(LK.ticks / 20) * 5;
+ // Rotate slowly
+ keyGraphics.rotation += 0.01;
+ };
+ return self;
+});
+var River = Container.expand(function () {
+ var self = Container.call(this);
+ var riverGraphics = self.attachAsset('river', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.hasBridge = false;
+ self.addBridge = function () {
+ if (!self.hasBridge) {
+ var bridge = self.attachAsset('bridge', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.hasBridge = true;
+ return bridge;
+ }
+ };
+ self.update = function () {
+ // Flowing water animation
+ riverGraphics.tint = 0x1E88E5 + Math.floor(Math.sin(LK.ticks / 20) * 20) * 0x000101;
+ };
+ return self;
+});
+var Spike = Container.expand(function () {
+ var self = Container.call(this);
+ var spikeGraphics = self.attachAsset('spike', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.isActive = false;
+ self.timer = 0;
+ self.cycleTime = 120; // 2 seconds at 60fps
+ self.update = function () {
+ self.timer++;
+ if (self.timer >= self.cycleTime) {
+ self.timer = 0;
+ self.isActive = !self.isActive;
+ if (self.isActive) {
+ tween(spikeGraphics, {
+ scaleY: 1
+ }, {
+ duration: 300
+ });
+ } else {
+ tween(spikeGraphics, {
+ scaleY: 0.2
+ }, {
+ duration: 300
+ });
+ }
+ }
+ };
+ // Initialize in retracted state
+ spikeGraphics.scaleY = 0.2;
+ return self;
+});
+var Treasure = Container.expand(function () {
+ var self = Container.call(this);
+ var treasureGraphics = self.attachAsset('treasure', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.isCollected = false;
+ self.collect = function () {
+ if (!self.isCollected) {
+ self.isCollected = true;
+ tween(treasureGraphics, {
+ scaleX: 1.3,
+ scaleY: 1.3
+ }, {
+ duration: 300,
+ onFinish: function onFinish() {
+ tween(treasureGraphics, {
+ scaleX: 0,
+ scaleY: 0
+ }, {
+ duration: 300
+ });
+ }
+ });
+ LK.setScore(LK.getScore() + 100);
+ LK.getSound('collectTreasure').play();
+ // Check if all treasures are collected
+ var allCollected = true;
+ for (var i = 0; i < treasures.length; i++) {
+ if (!treasures[i].isCollected) {
+ allCollected = false;
+ break;
+ }
+ }
+ if (allCollected) {
+ // Level complete
+ storage.level++;
+ LK.showYouWin();
+ }
+ }
+ };
+ self.update = function () {
+ if (!self.isCollected) {
+ // Shine animation
+ var glowIntensity = (Math.sin(LK.ticks / 30) + 1) / 2;
+ treasureGraphics.alpha = 0.7 + glowIntensity * 0.3;
+ }
+ };
+ return self;
+});
+var Wall = Container.expand(function () {
+ var self = Container.call(this);
+ var wallGraphics = self.attachAsset('wall', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x607D8B // Cave-like dark blue-gray
+});
+
+/****
+* Game Code
+****/
+// Game variables
+var tileSize = 100;
+var gridWidth = 20;
+var gridHeight = 27;
+var explorer;
+var walls = [];
+var keys = [];
+var doors = [];
+var treasures = [];
+var spikes = [];
+var fallingRocks = [];
+var rivers = [];
+var bridges = [];
+var levelGrid = [];
+var gameStarted = false;
+// UI Elements
+var scoreTxt = new Text2('0', {
+ size: 80,
+ fill: 0xFFFFFF
+});
+var levelTxt = new Text2('Level: ' + storage.level, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+var keysTxt = new Text2('Keys: ' + storage.collectedKeys, {
+ size: 60,
+ fill: 0xFFD700
+});
+var livesTxt = new Text2('Lives: ' + storage.lives, {
+ size: 60,
+ fill: 0xFF5252
+});
+// Initialize game
+function initializeGame() {
+ // Clear previous game elements
+ resetGameElements();
+ // Generate level based on current level
+ generateLevel(storage.level);
+ // Initialize explorer
+ createExplorer();
+ // Setup UI
+ setupUI();
+ // Start game
+ gameStarted = true;
+ // Play background music
+ LK.playMusic('caveMusic', {
+ fade: {
+ start: 0,
+ end: 0.3,
+ duration: 1000
+ }
+ });
+}
+function resetGameElements() {
+ // Remove all existing game elements
+ for (var i = 0; i < walls.length; i++) {
+ walls[i].destroy();
+ }
+ walls = [];
+ for (var i = 0; i < keys.length; i++) {
+ keys[i].destroy();
+ }
+ keys = [];
+ for (var i = 0; i < doors.length; i++) {
+ doors[i].destroy();
+ }
+ doors = [];
+ for (var i = 0; i < treasures.length; i++) {
+ treasures[i].destroy();
+ }
+ treasures = [];
+ for (var i = 0; i < spikes.length; i++) {
+ spikes[i].destroy();
+ }
+ spikes = [];
+ for (var i = 0; i < fallingRocks.length; i++) {
+ fallingRocks[i].destroy();
+ }
+ fallingRocks = [];
+ for (var i = 0; i < rivers.length; i++) {
+ rivers[i].destroy();
+ }
+ rivers = [];
+ for (var i = 0; i < bridges.length; i++) {
+ bridges[i].destroy();
+ }
+ bridges = [];
+ levelGrid = [];
+ if (explorer) {
+ explorer.destroy();
+ explorer = null;
+ }
+}
+function createExplorer() {
+ explorer = new Explorer();
+ game.addChild(explorer);
+ // Position explorer at start position
+ for (var y = 0; y < gridHeight; y++) {
+ for (var x = 0; x < gridWidth; x++) {
+ if (levelGrid[y][x] === 'S') {
+ explorer.x = x * tileSize + tileSize / 2;
+ explorer.y = y * tileSize + tileSize / 2;
+ break;
+ }
+ }
+ }
+}
+function setupUI() {
+ // Setup score text
+ scoreTxt.setText(LK.getScore());
+ scoreTxt.anchor.set(1, 0);
+ LK.gui.topRight.addChild(scoreTxt);
+ // Setup level text
+ levelTxt.setText('Level: ' + storage.level);
+ levelTxt.anchor.set(0.5, 0);
+ levelTxt.y = 80;
+ LK.gui.top.addChild(levelTxt);
+ // Setup keys text
+ keysTxt.setText('Keys: ' + storage.collectedKeys);
+ keysTxt.anchor.set(0, 0);
+ keysTxt.y = 80;
+ LK.gui.topRight.addChild(keysTxt);
+ // Setup lives text
+ livesTxt.setText('Lives: ' + storage.lives);
+ livesTxt.anchor.set(0, 0);
+ LK.gui.topRight.addChild(livesTxt);
+}
+function generateLevel(level) {
+ // Define different level layouts
+ var layouts = [];
+ // Level 1: Simple tutorial level
+ layouts[1] = ["WWWWWWWWWWWWWWWWWWWW", "W W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W W W", "W W W WWWWWWWWWW W W", "W W W W W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W W W", "W WWWWWWWWWWWWWWWW W", "W W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W W W W", "W W W WWWWWWWWW W W W", "W W W W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W TS W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"];
+ // Level 2: Introducing spikes
+ layouts[2] = ["WWWWWWWWWWWWWWWWWWWW", "W W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W W W", "W W W WWWWWWWWWW W W", "W W W W W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W X W W W", "W WWWWWWWWWWWWWWWW W", "W X X W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W X W W W", "W W W WWWWWWWWW W W W", "W W W X W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W TS W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"];
+ // Level 3: Introducing falling rocks
+ layouts[3] = ["WWWWWWWWWWWWWWWWWWWW", "W W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W F W W", "W W W WWWWWWWWWW W W", "W W W W F W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W F X W W W", "W WWWWWWWWWWWWWWWW W", "W X F X W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W X F W W W", "W W W WWWWWWWWW W W W", "W W W F X W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W TS W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"];
+ // Level 4: Introducing rivers
+ layouts[4] = ["WWWWWWWWWWWWWWWWWWWW", "WS W W", "W WWWWWW W WWWWWWW W", "W W K W W", "W W WWWWWWWWWWWW W W", "W W W F W W", "W W W WWWWWWWWWW W W", "W W W W F W W W", "W W W W WWWWWW W W W", "W W W W W W W W W", "W W W W W WW W W W W", "W W W W W W W W", "W WWWWW WWWWWWWW W W", "W F X W W W", "WRRRRRRRRRRRRRRRRR W", "W X F X W", "W WWWWWWWW WWWWWWW W", "W W W W W", "W W WWWW WWWWWWW W W", "W W W X F W W W", "W W W WWWWWWWWW W W W", "W W W F X W W W W", "W W WWWWWWWWW W W W W", "W W DW W W W W", "W WWWWWWWWWWW W W T W", "W W W", "WWWWWWWWWWWWWWWWWWWWW"];
+ // Get layout for current level or use level 4 for any higher levels
+ var currentLayout = layouts[Math.min(level, 4)];
+ // Parse level layout
+ for (var y = 0; y < currentLayout.length; y++) {
+ levelGrid[y] = [];
+ for (var x = 0; x < currentLayout[y].length; x++) {
+ var cellType = currentLayout[y][x];
+ levelGrid[y][x] = cellType;
+ var xPos = x * tileSize + tileSize / 2;
+ var yPos = y * tileSize + tileSize / 2;
+ switch (cellType) {
+ case 'W':
+ // Wall
+ var wall = new Wall();
+ wall.x = xPos;
+ wall.y = yPos;
+ game.addChild(wall);
+ walls.push(wall);
+ break;
+ case 'K':
+ // Key
+ var key = new Key();
+ key.x = xPos;
+ key.y = yPos;
+ game.addChild(key);
+ keys.push(key);
+ break;
+ case 'D':
+ // Door
+ var door = new Door();
+ door.x = xPos;
+ door.y = yPos;
+ game.addChild(door);
+ doors.push(door);
+ break;
+ case 'T':
+ // Treasure
+ var treasure = new Treasure();
+ treasure.x = xPos;
+ treasure.y = yPos;
+ game.addChild(treasure);
+ treasures.push(treasure);
+ break;
+ case 'X':
+ // Spike trap
+ var spike = new Spike();
+ spike.x = xPos;
+ spike.y = yPos;
+ game.addChild(spike);
+ spikes.push(spike);
+ break;
+ case 'F':
+ // Falling rock
+ var rock = new FallingRock();
+ rock.x = xPos;
+ rock.y = yPos;
+ rock.initialY = yPos;
+ game.addChild(rock);
+ fallingRocks.push(rock);
+ break;
+ case 'R':
+ // River
+ var river = new River();
+ river.x = xPos;
+ river.y = yPos;
+ game.addChild(river);
+ rivers.push(river);
+ break;
+ }
+ }
+ }
+}
+function getGridPosition(x, y) {
+ var gridX = Math.floor(x / tileSize);
+ var gridY = Math.floor(y / tileSize);
+ if (gridX >= 0 && gridX < gridWidth && gridY >= 0 && gridY < gridHeight) {
+ return {
+ x: gridX,
+ y: gridY
+ };
+ }
+ return null;
+}
+function isWalkable(gridX, gridY) {
+ if (gridX < 0 || gridX >= gridWidth || gridY < 0 || gridY >= gridHeight) {
+ return false;
+ }
+ var cellType = levelGrid[gridY][gridX];
+ // Check if cell is walkable
+ if (cellType === 'W') {
+ return false;
+ }
+ // Check if door is locked
+ if (cellType === 'D') {
+ var door = getDoorAt(gridX, gridY);
+ return door && !door.isLocked;
+ }
+ // Check if river has bridge
+ if (cellType === 'R') {
+ var river = getRiverAt(gridX, gridY);
+ return river && river.hasBridge;
+ }
+ return true;
+}
+function getDoorAt(gridX, gridY) {
+ for (var i = 0; i < doors.length; i++) {
+ var doorPos = getGridPosition(doors[i].x, doors[i].y);
+ if (doorPos && doorPos.x === gridX && doorPos.y === gridY) {
+ return doors[i];
+ }
+ }
+ return null;
+}
+function getRiverAt(gridX, gridY) {
+ for (var i = 0; i < rivers.length; i++) {
+ var riverPos = getGridPosition(rivers[i].x, rivers[i].y);
+ if (riverPos && riverPos.x === gridX && riverPos.y === gridY) {
+ return rivers[i];
+ }
+ }
+ return null;
+}
+// Update UI
+function updateUI() {
+ scoreTxt.setText(LK.getScore());
+ levelTxt.setText('Level: ' + storage.level);
+ keysTxt.setText('Keys: ' + storage.collectedKeys);
+ livesTxt.setText('Lives: ' + storage.lives);
+}
+// Check for collisions
+function checkCollisions() {
+ if (!explorer) {
+ return;
+ }
+ var explorerPos = getGridPosition(explorer.x, explorer.y);
+ if (!explorerPos) {
+ return;
+ }
+ var cellType = levelGrid[explorerPos.y][explorerPos.x];
+ // Check key collision
+ if (cellType === 'K') {
+ for (var i = 0; i < keys.length; i++) {
+ var keyPos = getGridPosition(keys[i].x, keys[i].y);
+ if (keyPos && keyPos.x === explorerPos.x && keyPos.y === explorerPos.y) {
+ explorer.collectKey();
+ keys[i].destroy();
+ keys.splice(i, 1);
+ levelGrid[explorerPos.y][explorerPos.x] = ' ';
+ LK.getSound('collect').play();
+ break;
+ }
+ }
+ }
+ // Check door collision
+ if (cellType === 'D') {
+ var door = getDoorAt(explorerPos.x, explorerPos.y);
+ if (door && door.isLocked && explorer.hasKey) {
+ door.unlock();
+ explorer.useKey();
+ keysTxt.setText('Keys: ' + storage.collectedKeys);
+ }
+ }
+ // Check treasure collision
+ if (cellType === 'T') {
+ for (var i = 0; i < treasures.length; i++) {
+ var treasurePos = getGridPosition(treasures[i].x, treasures[i].y);
+ if (treasurePos && treasurePos.x === explorerPos.x && treasurePos.y === explorerPos.y && !treasures[i].isCollected) {
+ treasures[i].collect();
+ break;
+ }
+ }
+ }
+ // Check spike collision
+ for (var i = 0; i < spikes.length; i++) {
+ if (spikes[i].isActive && explorer.intersects(spikes[i])) {
+ explorer.takeDamage();
+ // Move player to a safe position
+ var safeX = explorer.x;
+ var safeY = explorer.y - tileSize;
+ if (isWalkable(Math.floor(safeX / tileSize), Math.floor(safeY / tileSize))) {
+ explorer.x = safeX;
+ explorer.y = safeY;
+ }
+ }
+ }
+ // Check falling rock collision
+ for (var i = 0; i < fallingRocks.length; i++) {
+ var rock = fallingRocks[i];
+ // Trigger rock if explorer is underneath
+ var rockPos = getGridPosition(rock.x, rock.y);
+ if (rockPos && explorerPos.x === rockPos.x && explorerPos.y > rockPos.y && !rock.isTriggered && !rock.isFalling) {
+ rock.trigger();
+ }
+ // Check if rock hits explorer
+ if (rock.isFalling && explorer.intersects(rock)) {
+ explorer.takeDamage();
+ rock.reset();
+ }
+ }
+ // Check river collision (player falls in if there's no bridge)
+ for (var i = 0; i < rivers.length; i++) {
+ var river = rivers[i];
+ var riverPos = getGridPosition(river.x, river.y);
+ if (riverPos && explorerPos.x === riverPos.x && explorerPos.y === riverPos.y && !river.hasBridge) {
+ explorer.takeDamage();
+ // Move player to a safe position
+ var safeX = explorer.x;
+ var safeY = explorer.y - tileSize;
+ if (isWalkable(Math.floor(safeX / tileSize), Math.floor(safeY / tileSize))) {
+ explorer.x = safeX;
+ explorer.y = safeY;
+ }
+ }
+ }
+}
+function moveExplorer(targetX, targetY) {
+ if (!explorer || explorer.isMoving) {
+ return;
+ }
+ var currentGridPos = getGridPosition(explorer.x, explorer.y);
+ var targetGridPos = getGridPosition(targetX, targetY);
+ if (!currentGridPos || !targetGridPos) {
+ return;
+ }
+ // Only allow movement to adjacent cells
+ var dx = Math.abs(targetGridPos.x - currentGridPos.x);
+ var dy = Math.abs(targetGridPos.y - currentGridPos.y);
+ if (dx === 1 && dy === 0 || dx === 0 && dy === 1) {
+ if (isWalkable(targetGridPos.x, targetGridPos.y)) {
+ var cellCenterX = targetGridPos.x * tileSize + tileSize / 2;
+ var cellCenterY = targetGridPos.y * tileSize + tileSize / 2;
+ explorer.moveToward(cellCenterX, cellCenterY);
+ }
+ }
+}
+// Handle touch/mouse events
+function handleGameInput(x, y, obj) {
+ if (!gameStarted) {
+ return;
+ }
+ moveExplorer(x, y);
+}
+// Start game when page loads
+initializeGame();
+// Handle touch/mouse events
+game.down = handleGameInput;
+// Game update loop
+game.update = function () {
+ if (!gameStarted) {
+ return;
+ }
+ // Update UI
+ updateUI();
+ // Check collisions
+ checkCollisions();
+ // Add bridge to first river after collecting all keys (for level 4)
+ if (storage.level >= 4 && storage.collectedKeys >= 1) {
+ for (var i = 0; i < rivers.length; i++) {
+ if (!rivers[i].hasBridge) {
+ rivers[i].addBridge();
+ break;
+ }
+ }
+ }
+};
\ No newline at end of file
small rock. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
a magic crackers boom effect. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
create a glod color key. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows