User prompt
change the maze shape for level1
User prompt
Do another shape for maze level1 with few spaces beside each coin there is a way to go to it and collect it
User prompt
change the shape and reduce spaces
User prompt
do many walls of small walls of maze for level1 and check if any coin inside a wall change its position before loading.
User prompt
do many walls of small walls of maze for level1 and check if any coin inside a wall change its position before loading.
User prompt
make it difficult the maze of level1 by adding more walls and spaces between edges for player to pass through it :)
User prompt
change maze level1 let many spaces
User prompt
change the shape of maze of level1 and change coins position to not been inside the walls.
User prompt
change the shape of level1 maze walls
User prompt
Add level text beside pause close to it level1...level10
User prompt
Change the shape of maze of level1 to be more hard and let spaces between the horizontal and vertical edges to be double the size of player so he can pass .
User prompt
let the space road for the player be double of its size.
User prompt
For level1 do more walls and more spaces in each area have coin there must be a space on wall to let player pass to collect it.
User prompt
Add more walls for level1 and let a road spaces for the player to pass through it
User prompt
make the maze hard
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var localPos = game.toLocal(obj.parent.toGlobal(obj.position)); // Get position relative to game stage' Line Number: 438
Code edit (1 edits merged)
Please save this source code
User prompt
Maze Coin Challenge
Initial prompt
Create maze have 10 coins doing rotation 360° continuously when game start, do 10 levels each level have different shape of the maze you can do the 5 other levels like circle mazes have curved lines or walls, the maze have to be inside 4 boundaries of the screen, you can do 4 walls around the maze. do timer on the top left 1:00min if reach 0 before collecting all coins do gameover but if finished them all 10/10 tap screen to go to next level.
/**** * Classes ****/ // Coin class var Coin = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); self.rotationSpeed = 0.05; // Radians per frame self.update = function () { self.rotation += self.rotationSpeed; }; return self; }); // Base size, will be scaled in code // No plugins needed for this version. Tween could be used for rotation, but manual rotation is sufficient. // var tween = LK.import('@upit/tween.v1'); // Player class var Player = Container.expand(function () { var self = Container.call(this); var graphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); // No update needed here as movement is handled in the main game loop return self; }); // Wall class var Wall = Container.expand(function (width, height) { var self = Container.call(this); // We get a base wall asset and scale it to the desired dimensions var graphics = self.attachAsset('wall', { anchorX: 0.0, // Anchor top-left for easier positioning and scaling anchorY: 0.0, width: width, // Set the actual width height: height // Set the actual height }); // Store dimensions for collision checks self.wallWidth = width; self.wallHeight = height; // No update needed for static walls return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x111111 // Dark background }); /**** * Game Code ****/ // Game constants and variables // Define assets used in the game. These will be automatically created and loaded. function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof2(o); } function _defineProperty2(e, r, t) { return (r = _toPropertyKey2(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey2(t) { var i = _toPrimitive2(t, "string"); return "symbol" == _typeof2(i) ? i : i + ""; } function _toPrimitive2(t, r) { if ("object" != _typeof2(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof2(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) { return t; } var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) { return i; } throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } var gameWidth = 2048; var gameHeight = 2732; var levelTimeLimit = 60; // Seconds var totalLevels = 10; // As per description var requiredCoinsPerLevel = 10; // Maze definitions for 10 levels with increasing difficulty. // Each level: walls array [{x, y, width, height}], coins array [{x, y}], startPos {x, y} var mazeLevels = [ // Level 1: Spiral Maze { walls: [ // --- Outer Borders --- { x: 100, y: 200, width: 1848, height: 50 }, // Top { x: 100, y: 2482, width: 1848, height: 50 }, // Bottom { x: 100, y: 250, width: 50, height: 2232 }, // Left { x: 1898, y: 250, width: 50, height: 2232 }, // Right // --- Spiral Arm 1 (Outer) --- { x: 150, y: 450, width: 1600, height: 50 }, // H1: Top segment (Leaves gap right: 1750-1898) { x: 1750, y: 500, width: 50, height: 1800 }, // V1: Right segment (Leaves gap bottom: 2300-2482) { x: 300, y: 2300, width: 1500, height: 50 }, // H2: Bottom segment (Leaves gap left: 150-300) { x: 300, y: 600, width: 50, height: 1700 }, // V2: Left segment (Leaves gap top: 450-600) // --- Spiral Arm 2 (Inner) --- Path width ~150px { x: 450, y: 600, width: 1150, height: 50 }, // H3: Top segment (Leaves gap right: 1600-1750) { x: 1600, y: 650, width: 50, height: 1500 }, // V3: Right segment (Leaves gap bottom: 2150-2300) { x: 450, y: 2150, width: 1200, height: 50 }, // H4: Bottom segment (Leaves gap left: 300-450) { x: 450, y: 750, width: 50, height: 1400 }, // V4: Left segment (Leaves gap top: 600-750) // --- Spiral Arm 3 (Inner) --- Path width ~150px { x: 600, y: 750, width: 850, height: 50 }, // H5: Top segment (Leaves gap right: 1450-1600) { x: 1450, y: 800, width: 50, height: 1200 }, // V5: Right segment (Leaves gap bottom: 2000-2150) { x: 600, y: 2000, width: 900, height: 50 }, // H6: Bottom segment (Leaves gap left: 450-600) { x: 600, y: 900, width: 50, height: 1100 }, // V6: Left segment (Leaves gap top: 750-900) // --- Spiral Arm 4 (Innermost) --- Path width ~150px { x: 750, y: 900, width: 550, height: 50 }, // H7: Top segment (Leaves gap right: 1300-1450) { x: 1300, y: 950, width: 50, height: 900 }, // V7: Right segment (Leaves gap bottom: 1850-2000) { x: 750, y: 1850, width: 600, height: 50 }, // H8: Bottom segment (Leaves gap left: 600-750) { x: 750, y: 1050, width: 50, height: 800 }, // V8: Left segment (Leaves gap top: 900-1050) // --- Center Area Termination --- Blocks the direct path to the center { x: 900, y: 1050, width: 250, height: 50 }, // Central H block { x: 1100, y: 1100, width: 50, height: 600 } // Central V block ], coins: [ // Place coins along the spiral path { x: 1000, y: 350 }, // Path 1 Top { x: 1825, y: 1000 }, // Path 1 Right { x: 1000, y: 2400 }, // Path 1 Bottom { x: 225, y: 1500 }, // Path 1 Left { x: 1000, y: 675 }, // Path 2 Top { x: 1675, y: 1500 }, // Path 2 Right { x: 1000, y: 2075 }, // Path 2 Bottom { x: 525, y: 1500 }, // Path 2 Left { x: 1000, y: 975 }, // Path 3 Top { x: 1024, y: 1400 } // Center area (end of spiral) ], startPos: { x: 200, y: 350 } // Start at the entrance near top-left }, // Level 2: Hypnotic Maze with Doors (Harder) { walls: [ // --- Outer Borders (Solid) --- { x: 100, y: 200, width: 1848, height: 50 }, // Top { x: 100, y: 2482, width: 1848, height: 50 }, // Bottom { x: 100, y: 250, width: 50, height: 2232 }, // Left { x: 1898, y: 250, width: 50, height: 2232 }, // Right // --- Layer 1 (Outer Square - Gap Top) --- approx 200px path { x: 300, y: 400, width: 700, height: 50 }, // Top Left { x: 1150, y: 400, width: 700, height: 50 }, // Top Right (Gap: 1000-1150) { x: 300, y: 2282, width: 1600, height: 50 }, // Bottom Full { x: 300, y: 450, width: 50, height: 1832 }, // Left Full // --- Layer 2 (Gap Left) --- approx 200px path { x: 500, y: 600, width: 1300, height: 50 }, // Top Full { x: 500, y: 2082, width: 1300, height: 50 }, // Bottom Full { x: 500, y: 650, width: 50, height: 650 }, // Left Top (Gap: 1300-1432) { //{4B} // Reused identifier x: 500, y: 1432, width: 50, height: 650 }, // Left Bottom // --- Layer 3 (Gap Bottom) --- approx 200px path { x: 700, y: 800, width: 900, height: 50 }, // Top Full { x: 700, y: 1882, width: 400, height: 50 }, // Bottom Left (Gap: 1100-1250) { //{4G} // Reused identifier x: 1250, y: 1882, width: 350, height: 50 }, // Bottom Right { x: 700, y: 850, width: 50, height: 1032 }, // Left Full { x: 1598, // Adjusted right wall x y: 850, width: 50, height: 1032 }, // Right Full // --- Layer 4 (Gap Right) --- approx 200px path { //{5A} // Reused identifier x: 900, y: 1000, width: 500, height: 50 }, // Top Full { //{5G} // Reused identifier x: 900, y: 1682, width: 500, height: 50 }, // Bottom Full { //{5L} // Reused identifier x: 900, y: 1050, width: 50, height: 632 }, // Left Full { //{5Q} // Reused identifier x: 1398, y: 1050, width: 50, height: 250 // Right Top (Gap: 1300-1432) }, { //{5U} // Reused identifier x: 1398, y: 1432, width: 50, height: 250 // Right Bottom }, // --- Central Area (Solid Block) --- { //{5F} // Reused identifier x: 1100, y: 1200, width: 200, height: 282 // Adjusted to be smaller central block }, // --- Added Dead Ends --- // Removed small horizontal wall in bottom right {}], //{6D} // End walls array coins: [ // Place coins in accessible locations for the harder maze { x: 1800, y: 2400 }, // Near start { x: 400, y: 2182 }, // Path Layer 1 Bottom Left { x: 400, y: 500 }, // Path Layer 2 Top Left { x: 600, y: 1366 // Near Layer 2 Left Gap }, { x: 1700, y: 700 }, // Path Layer 2 Top Right { x: 1700, y: 1982 }, // Path Layer 3 Bottom Right (near dead end) { x: 800, y: 1982 // Near Layer 3 Bottom Gap }, { x: 800, y: 900 }, // Path Layer 3 Top Left { x: 1000, y: 1100 }, // Path Layer 4 Top Left { x: 1300, y: 1366 // Center Area (final coin) }], // End coins startPos: { x: 1800, // Bottom right x y: 2400 // Bottom right y } // Start bottom right corner //{83} //{84} }, // Level 3: S-Shape Path with Doors { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, // Top { x: 100, y: 2482, width: 1848, height: 50 }, // Bottom { x: 100, y: 250, width: 50, height: 2232 }, // Left { x: 1898, y: 250, width: 50, height: 2232 }, // Right // S-shape walls with gaps (doors) // Top H segment (split for door) { x: 100, y: 700, width: 650, // Ends at 750 height: 50 }, { x: 900, // Starts at 900 (gap 750-900) y: 700, width: 650, // Ends at 1550 height: 50 }, // Middle H segment (split for door) { x: 500, y: 1200, width: 650, // Ends at 1150 height: 50 }, { x: 1300, // Starts at 1300 (gap 1150-1300) y: 1200, width: 648, // Ends at 1948 height: 50 }, // Bottom H segment (split for door) { x: 100, y: 1700, width: 650, // Ends at 750 height: 50 }, { x: 900, // Starts at 900 (gap 750-900) y: 1700, width: 650, // Ends at 1550 height: 50 }, // V segment 1 (top right) - Keep solid for now, rely on H gap { x: 1500, y: 250, width: 50, height: 450 }, // V segment 2 (middle left - split for door) { x: 500, y: 750, width: 50, height: 200 // Ends at 950 }, { x: 500, y: 1050, // Starts at 1050 (gap 950-1050) width: 50, height: 150 // Ends at 1200 }, // V segment 3 (middle right - split for door) { x: 1500, y: 1250, width: 50, height: 200 // Ends at 1450 }, { x: 1500, y: 1550, // Starts at 1550 (gap 1450-1550) width: 50, height: 150 // Ends at 1700 }, // V segment 4 (bottom left) - Split to create door (gap y:2050-2200) { // V segment 4 Top part x: 500, y: 1750, width: 50, height: 300 // Ends at y=2050 }, { // V segment 4 Bottom part x: 500, y: 2200, // Starts after gap width: 50, height: 282 // Ends at y=2482 }], coins: [{ x: 300, y: 300 }, { x: 1700, y: 450 }, { x: 300, y: 950 }, { x: 1700, y: 950 }, { x: 300, y: 1450 }, { x: 1700, y: 1450 }, { x: 300, y: 2000 }, { x: 1700, y: 2000 }, { x: 1000, y: 1450 }, { x: 1000, y: 950 }], startPos: { x: 200, y: 300 } }, // Level 4: Asymmetric Cross (Modified Doors) { walls: [ // --- Outer Borders --- { x: 100, y: 200, width: 1848, height: 50 }, // Top { x: 100, y: 2482, width: 1848, height: 50 }, // Bottom { x: 100, y: 250, width: 50, height: 2232 }, // Left { x: 1898, y: 250, width: 50, height: 2232 }, // Right // --- Internal Walls --- // Horizontal dividers // Top H (Gap left: 100-600 -> Wider Door 1) { x: 600, //{9o} // Increased start X y: 800, width: 1348, //{9q} // Adjusted width height: 50 }, // Bottom H (Gap right: 1448-1898 -> Wider Door 2, split for new door) // Part 1 (Ends at x=500) { x: 100, y: 1900, width: 400, //{9w} // Shorter width height: 50 }, // Part 2 (Starts at x=700, ends at 1448 -> Gap x:500-700 = New Door Bottom-Left) { x: 700, y: 1900, width: 748, // Covers remaining section leaving gap height: 50 }, // Vertical dividers // Left V (Gap top: 250-950 -> Wider Door 3) { x: 600, y: 950, //{9C} // Increased start Y width: 50, height: 1532 // Adjusted height }, // Right V (Gap bottom: 1750-2482 -> Wider Door 4, split for new door) // Part 1 (Ends at y=700) { x: 1400, y: 250, width: 50, height: 450 // Shorter height }, // Part 2 (Starts at y=900, ends at 1750 -> Gap y:700-900 = New Door Top-Right) { x: 1400, y: 900, width: 50, height: 850 // Covers remaining section leaving gap }, // Twist/Blocking walls (Unchanged) { x: 150, y: 1000, width: 400, height: 50 }, // Twist block top-left section { x: 1450, y: 1000, width: 400, height: 50 }, // Twist block top-right section { x: 150, y: 1700, width: 400, height: 50 }, // Twist block bottom-left section { x: 1450, y: 1700, width: 400, height: 50 } // Twist block bottom-right section ], coins: [{ x: 300, y: 500 }, // Top Left area (before twist) { x: 300, y: 1300 }, // Top Left area (after twist) { x: 1700, y: 500 }, // Top Right area (before twist) { x: 1700, y: 1300 }, // Top Right area (after twist) { x: 300, y: 2200 }, // Bottom Left area (near corner) { x: 300, y: 1800 }, // Bottom Left area (after twist) { x: 1700, y: 2200 }, // Bottom Right area (near corner) { x: 1700, y: 1800 }, // Bottom Right area (after twist) { x: 1024, y: 1000 }, // Center Top area { x: 1024, y: 1500 } // Center Bottom area ], startPos: { x: 200, y: 300 } // Start Top Left }, // Level 5: Central Hub Branching { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, // Top { x: 100, y: 2482, width: 1848, height: 50 }, // Bottom { x: 100, y: 250, width: 50, height: 2232 }, // Left { x: 1898, y: 250, width: 50, height: 2232 }, // Right // Central Hub Walls (creating a box ~800x800 in center) { x: 624, y: 966, width: 800, height: 50 }, // Hub Top { x: 624, y: 1716, width: 800, height: 50 }, // Hub Bottom { x: 624, y: 1016, width: 50, height: 700 }, // Hub Left { x: 1374, y: 1016, width: 50, height: 700 }, // Hub Right // Branch Walls (connecting hub/borders to create paths) { x: 150, y: 600, width: 1700, height: 50 }, // Top Branch Divider { x: 150, y: 2066, width: 1700, height: 50 }, // Bottom Branch Divider { x: 350, y: 650, width: 50, height: 1416 }, // Left Branch Divider (Inner) { x: 1648, y: 650, width: 50, height: 1416 }, // Right Branch Divider (Inner) // Add some dead ends or twists within branches { x: 150, y: 1341, width: 150, height: 50 }, // Left branch block { x: 1748, y: 1341, width: 150, height: 50 }, // Right branch block { x: 1000, y: 250, width: 50, height: 300 }, // Top branch block { x: 1000, y: 2116, width: 50, height: 300 } // Bottom branch block ], coins: [{ x: 1024, y: 1341 }, // Center Hub { x: 250, y: 400 }, // Top Left Branch { x: 1798, y: 400 }, // Top Right Branch { x: 250, y: 2250 }, // Bottom Left Branch { x: 1798, y: 2250 }, // Bottom Right Branch { x: 250, y: 1341 }, // Mid Left Branch end { x: 1798, y: 1341 }, // Mid Right Branch end { x: 1024, y: 350 }, // Mid Top Branch end { x: 1024, y: 2300 }, // Mid Bottom Branch end { x: 800, y: 1500 } // Inside Hub offset ], startPos: { x: 1024, y: 1341 } // Start in Center Hub }, // Level 6: More complex branching/connections { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, { x: 100, y: 2482, width: 1848, height: 50 }, { x: 100, y: 250, width: 50, height: 2232 }, { x: 1898, y: 250, width: 50, height: 2232 }, // Horizontal dividers { x: 100, y: 800, width: 800, height: 50 }, { x: 1148, y: 800, width: 800, height: 50 }, { x: 100, y: 1300, width: 1848, height: 50 }, { x: 100, y: 1800, width: 800, height: 50 }, { x: 1148, y: 1800, width: 800, height: 50 }, // Vertical dividers { x: 500, y: 250, width: 50, height: 500 }, { x: 500, y: 850, width: 50, height: 400 }, { x: 500, y: 1350, width: 50, height: 400 }, { x: 500, y: 1850, width: 50, height: 632 }, { x: 1500, y: 250, width: 50, height: 500 }, { x: 1500, y: 850, width: 50, height: 400 }, { x: 1500, y: 1350, width: 50, height: 400 }, { x: 1500, y: 1850, width: 50, height: 632 }], coins: [{ x: 300, y: 300 }, { x: 1024, y: 300 }, { x: 1748, y: 300 }, { x: 300, y: 1050 }, { x: 1748, y: 1050 }, { x: 1024, y: 1550 }, // Center area coin { x: 300, y: 2100 }, { x: 1748, y: 2100 }, { x: 800, y: 500 }, { x: 1248, y: 2000 }], startPos: { x: 1024, y: 1550 } // Start near center }, // Level 7: Grid with missing segments { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, { x: 100, y: 2482, width: 1848, height: 50 }, { x: 100, y: 250, width: 50, height: 2232 }, { x: 1898, y: 250, width: 50, height: 2232 }, // Grid lines (approx every 450px) { x: 100, y: 650, width: 1848, height: 50 }, { x: 100, y: 1100, width: 1848, height: 50 }, { x: 100, y: 1550, width: 1848, height: 50 }, { x: 100, y: 2000, width: 1848, height: 50 }, { x: 550, y: 250, width: 50, height: 2232 }, { x: 1000, y: 250, width: 50, height: 2232 }, { x: 1450, y: 250, width: 50, height: 2232 } // Remove segments to create path // (For simplicity, just adding coins in grid cells) ], coins: [ // Place coins in different grid cells { x: 325, y: 425 }, { x: 775, y: 425 }, { x: 1225, y: 425 }, { x: 1675, y: 425 }, { x: 325, y: 875 }, { x: 1675, y: 875 }, // Skip middle cells { x: 325, y: 1325 }, { x: 1675, y: 1325 }, { x: 775, y: 1775 }, { x: 1225, y: 2225 }], startPos: { x: 325, y: 2225 } // Start bottom left }, // Level 8: Spiral (Approximation with Rectangles) { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, { x: 100, y: 2482, width: 1848, height: 50 }, { x: 100, y: 250, width: 50, height: 2232 }, { x: 1898, y: 250, width: 50, height: 2232 }, // Outer spiral path { x: 100, y: 700, width: 1600, height: 50 }, // H1 { x: 1650, y: 250, width: 50, height: 900 }, // V1 { x: 300, y: 1150, width: 1400, height: 50 }, // H2 { x: 250, y: 750, width: 50, height: 850 }, // V2 { x: 250, y: 1600, width: 1200, height: 50 }, // H3 { x: 1450, y: 1150, width: 50, height: 900 }, // V3 { x: 450, y: 2050, width: 1050, height: 50 }, // H4 (inner end) { x: 400, y: 1650, width: 50, height: 400 } // V4 (inner end) ], coins: [ // Place along the spiral path { x: 200, y: 400 }, { x: 1000, y: 400 }, { x: 1800, y: 400 }, // Outer Top { x: 1800, y: 900 }, { x: 1800, y: 1400 }, // Right Down { x: 1000, y: 900 }, // Inner loop 1 { x: 400, y: 900 }, { x: 400, y: 1400 }, // Left Down/Up { x: 400, y: 1800 }, { x: 1000, y: 1800 } // Inner end area ], startPos: { x: 200, y: 300 } // Start near entrance }, // Level 9: Dense Obstacles { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, { x: 100, y: 2482, width: 1848, height: 50 }, { x: 100, y: 250, width: 50, height: 2232 }, { x: 1898, y: 250, width: 50, height: 2232 }, // Many small walls creating tight paths { x: 200, y: 400, width: 200, height: 50 }, { x: 500, y: 400, width: 200, height: 50 }, { x: 800, y: 400, width: 200, height: 50 }, { x: 1100, y: 400, width: 200, height: 50 }, { x: 1400, y: 400, width: 200, height: 50 }, { x: 1700, y: 400, width: 200, height: 50 }, { x: 300, y: 600, width: 50, height: 200 }, { x: 600, y: 600, width: 50, height: 200 }, { x: 900, y: 600, width: 50, height: 200 }, { x: 1200, y: 600, width: 50, height: 200 }, { x: 1500, y: 600, width: 50, height: 200 }, { x: 1800, y: 600, width: 50, height: 200 }, // ... Continue pattern downwards ... { x: 200, y: 900, width: 200, height: 50 }, { x: 500, y: 900, width: 200, height: 50 }, // etc. { x: 300, y: 1100, width: 50, height: 200 }, { x: 600, y: 1100, width: 50, height: 200 }, // etc. { x: 200, y: 1400, width: 200, height: 50 }, { x: 500, y: 1400, width: 200, height: 50 }, // etc. { x: 300, y: 1600, width: 50, height: 200 }, { x: 600, y: 1600, width: 50, height: 200 }, // etc. { x: 200, y: 1900, width: 200, height: 50 }, { x: 500, y: 1900, width: 200, height: 50 }, // etc. { x: 300, y: 2100, width: 50, height: 200 }, { x: 600, y: 2100, width: 50, height: 200 }, // etc. // Mirror pattern on right side { x: 1100, y: 900, width: 200, height: 50 }, { x: 1400, y: 900, width: 200, height: 50 }, { x: 1700, y: 900, width: 200, height: 50 }, { x: 1200, y: 1100, width: 50, height: 200 }, { x: 1500, y: 1100, width: 50, height: 200 }, { x: 1800, y: 1100, width: 50, height: 200 }, { x: 1100, y: 1400, width: 200, height: 50 }, { x: 1400, y: 1400, width: 200, height: 50 }, { x: 1700, y: 1400, width: 200, height: 50 }, { x: 1200, y: 1600, width: 50, height: 200 }, { x: 1500, y: 1600, width: 50, height: 200 }, { x: 1800, y: 1600, width: 50, height: 200 }, { x: 1100, y: 1900, width: 200, height: 50 }, { x: 1400, y: 1900, width: 200, height: 50 }, { x: 1700, y: 1900, width: 200, height: 50 }, { x: 1200, y: 2100, width: 50, height: 200 }, { x: 1500, y: 2100, width: 50, height: 200 }, { x: 1800, y: 2100, width: 50, height: 200 }], coins: [ // Place in tricky spots within the dense grid { x: 250, y: 300 }, { x: 1800, y: 300 }, { x: 400, y: 700 }, { x: 1650, y: 700 }, { x: 750, y: 1000 }, { x: 1300, y: 1000 }, { x: 250, y: 1500 }, { x: 1800, y: 1500 }, { x: 400, y: 2200 }, { x: 1650, y: 2200 }], startPos: { x: 1024, y: 300 } // Start top center }, // Level 10: Final Challenge - Combination { walls: [{ x: 100, y: 200, width: 1848, height: 50 }, { x: 100, y: 2482, width: 1848, height: 50 }, { x: 100, y: 250, width: 50, height: 2232 }, { x: 1898, y: 250, width: 50, height: 2232 }, // Mix of grid, long paths, tight spots // Section 1 (Top Grid) { x: 100, y: 700, width: 1848, height: 50 }, { x: 550, y: 250, width: 50, height: 450 }, { x: 1000, y: 250, width: 50, height: 450 }, { x: 1450, y: 250, width: 50, height: 450 }, // Section 2 (Middle Maze) { x: 100, y: 1200, width: 800, height: 50 }, { x: 1148, y: 1200, width: 800, height: 50 }, { x: 500, y: 750, width: 50, height: 900 }, { x: 1500, y: 750, width: 50, height: 900 }, { x: 100, y: 1650, width: 1848, height: 50 }, // Section 3 (Bottom Spiral-like element) { x: 300, y: 2100, width: 1448, height: 50 }, { x: 1748, y: 1700, width: 50, height: 400 }, { x: 300, y: 1700, width: 50, height: 400 }, { x: 500, y: 1900, width: 1048, height: 50 } // Inner H ], coins: [{ x: 325, y: 400 }, { x: 1675, y: 400 }, // Top Grid { x: 200, y: 900 }, { x: 1800, y: 900 }, // Mid sides { x: 1024, y: 1400 }, // Mid center { x: 400, y: 1800 }, { x: 1600, y: 1800 }, // Lower Mid { x: 200, y: 2300 }, { x: 1800, y: 2300 }, // Bottom Corners { x: 1024, y: 2000 } // Bottom Center (inner) ], startPos: { x: 1024, y: 300 } // Start Top Center } // NOTE: Circular mazes are hard to represent with rectangular walls. // This implementation uses only rectangular walls. ]; // Game state variables var currentLevelIndex = 0; var walls = []; var coins = []; var player = null; var score = 0; var timeLeft = levelTimeLimit; var timerInterval = null; var scoreTxt = null; var timerTxt = null; var levelTxt = null; var levelComplete = false; var isDragging = false; var dragOffset = { x: 0, y: 0 }; // Offset between touch point and player center // --- Helper Functions --- // Clears current level elements function clearLevel() { walls.forEach(function (wall) { wall.destroy(); }); walls = []; coins.forEach(function (coin) { coin.destroy(); }); coins = []; if (player) { player.destroy(); player = null; } levelComplete = false; isDragging = false; } // Loads a level by index function loadLevel(levelIndex) { clearLevel(); if (levelIndex >= mazeLevels.length) { // Handle case where we run out of predefined levels but haven't reached totalLevels console.log("Warning: Ran out of predefined maze data, repeating last level."); levelIndex = mazeLevels.length - 1; // Repeat the last available level // Ideally, generate levels procedurally or add more data. if (levelIndex < 0) { // Should not happen if mazeLevels has data LK.showGameOver(); // No levels defined at all return; } } currentLevelIndex = levelIndex; // Update the global index tracker var levelData = mazeLevels[levelIndex]; // Create walls levelData.walls.forEach(function (wallData) { var wall = new Wall(wallData.width, wallData.height); wall.x = wallData.x; wall.y = wallData.y; game.addChild(wall); walls.push(wall); }); // Create coins levelData.coins.forEach(function (coinData) { var coin = new Coin(); coin.x = coinData.x; coin.y = coinData.y; game.addChild(coin); coins.push(coin); }); // Create player player = new Player(); player.x = levelData.startPos.x; player.y = levelData.startPos.y; game.addChild(player); // Reset score and timer for the new level score = 0; timeLeft = levelTimeLimit; updateScoreDisplay(); updateTimerDisplay(); updateLevelDisplay(); // Update level text startTimer(); } // Checks collision between player (at potential new position) and all walls function checkWallCollision(targetX, targetY) { if (!player) { return true; } // No player, collision is effectively true var playerRadius = player.width / 2; // Assuming player is a circle // Create a hypothetical bounding box for the player at the target position var playerBounds = { left: targetX - playerRadius, right: targetX + playerRadius, top: targetY - playerRadius, bottom: targetY + playerRadius }; for (var i = 0; i < walls.length; i++) { var wall = walls[i]; var wallBounds = { left: wall.x, right: wall.x + wall.wallWidth, // Use stored dimensions top: wall.y, bottom: wall.y + wall.wallHeight // Use stored dimensions }; // Basic AABB collision check if (playerBounds.right > wallBounds.left && playerBounds.left < wallBounds.right && playerBounds.bottom > wallBounds.top && playerBounds.top < wallBounds.bottom) { return true; // Collision detected } } return false; // No collision } // Updates the score display function updateScoreDisplay() { scoreTxt.setText("Coins: " + score + "/" + requiredCoinsPerLevel); } // Updates the timer display function updateTimerDisplay() { timerTxt.setText("Time: " + timeLeft); } // Updates the level display function updateLevelDisplay() { levelTxt.setText("Level: " + (currentLevelIndex + 1)); } // Timer tick function function handleTimerTick() { if (levelComplete) { return; } // Stop timer if level is done timeLeft--; updateTimerDisplay(); if (timeLeft <= 0) { LK.clearInterval(timerInterval); timerInterval = null; LK.showGameOver(); // LK handles the game over state } } // Starts the level timer function startTimer() { if (timerInterval) { LK.clearInterval(timerInterval); } timeLeft = levelTimeLimit; // Reset time updateTimerDisplay(); timerInterval = LK.setInterval(handleTimerTick, 1000); } // Stops the level timer function stopTimer() { if (timerInterval) { LK.clearInterval(timerInterval); timerInterval = null; } } // --- GUI Setup --- // Score display scoreTxt = new Text2('Coins: 0/' + requiredCoinsPerLevel, { size: 60, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); // Anchor middle-top LK.gui.top.addChild(scoreTxt); // Add to top-center GUI area scoreTxt.y = 20; // Add some padding from the top edge // Timer display timerTxt = new Text2('Time: ' + levelTimeLimit, { size: 60, fill: 0xFFFFFF }); timerTxt.anchor.set(1, 0); // Anchor top-right LK.gui.topRight.addChild(timerTxt); // Add to top-right GUI area timerTxt.y = 20; // Match score padding timerTxt.x = -20; // Add some padding from the right edge // --- Event Handlers --- // Level display levelTxt = new Text2('Level: 1', { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0, 0); // Anchor top-left LK.gui.topLeft.addChild(levelTxt); // Add to top-left GUI area (near pause) levelTxt.x = 110; // Offset from the very corner (reserved area) levelTxt.y = 20; // Match other UI padding game.down = function (x, y, obj) { if (levelComplete) { // If level is complete, tap anywhere to proceed currentLevelIndex++; if (currentLevelIndex < totalLevels) { loadLevel(currentLevelIndex); } else { LK.showYouWin(); // Completed all levels } return; // Don't process drag start } // Check if the press is on the player var playerPos = player.position; var dx = x - playerPos.x; var dy = y - playerPos.y; var distSq = dx * dx + dy * dy; var playerRadius = player.width / 2; // Allow starting drag if touching the player // Add a small tolerance for easier touch if (distSq < playerRadius * playerRadius * 1.5 * 1.5) { isDragging = true; // Calculate offset from player center to touch point // The x, y arguments are already in the game's local coordinate system dragOffset.x = player.x - x; dragOffset.y = player.y - y; } else { isDragging = false; } }; game.move = function (x, y, obj) { if (!isDragging || levelComplete || !player) { return; } // The x, y arguments are already in the game's local coordinate system var targetX = x + dragOffset.x; var targetY = y + dragOffset.y; // Check for collisions *before* moving if (!checkWallCollision(targetX, targetY)) { player.x = targetX; player.y = targetY; } else { // Optional: Try moving only horizontally or vertically if diagonal move fails // Check X movement only if (!checkWallCollision(targetX, player.y)) { player.x = targetX; } // Check Y movement only if (!checkWallCollision(player.x, targetY)) { player.y = targetY; } // If both fail, the player stays put } }; game.up = function (x, y, obj) { isDragging = false; }; // --- Game Update Loop --- game.update = function () { if (levelComplete || !player) { return; } // Don't update if level is done or no player // Check for coin collection var playerRadius = player.width / 2; for (var i = coins.length - 1; i >= 0; i--) { var coin = coins[i]; var dx = player.x - coin.x; var dy = player.y - coin.y; var distance = Math.sqrt(dx * dx + dy * dy); var coinRadius = coin.width / 2; if (distance < playerRadius + coinRadius) { // Collision detected - collect coin score++; updateScoreDisplay(); coin.destroy(); coins.splice(i, 1); // Check for level completion if (score >= requiredCoinsPerLevel) { levelComplete = true; stopTimer(); // Optionally show a "Level Clear! Tap to continue" message // For now, just rely on the game.down handler checking levelComplete console.log("Level " + (currentLevelIndex + 1) + " Complete!"); // Note: LK engine might handle transitions, but the prompt asks for tap to continue. if (currentLevelIndex + 1 >= totalLevels) { // If this was the last level according to totalLevels count LK.showYouWin(); } // Otherwise, wait for tap in game.down break; // Exit loop after collecting a coin and potentially completing level } } } }; // --- Start Game --- loadLevel(currentLevelIndex);
/****
* Classes
****/
// Coin class
var Coin = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.rotationSpeed = 0.05; // Radians per frame
self.update = function () {
self.rotation += self.rotationSpeed;
};
return self;
});
// Base size, will be scaled in code
// No plugins needed for this version. Tween could be used for rotation, but manual rotation is sufficient.
// var tween = LK.import('@upit/tween.v1');
// Player class
var Player = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// No update needed here as movement is handled in the main game loop
return self;
});
// Wall class
var Wall = Container.expand(function (width, height) {
var self = Container.call(this);
// We get a base wall asset and scale it to the desired dimensions
var graphics = self.attachAsset('wall', {
anchorX: 0.0,
// Anchor top-left for easier positioning and scaling
anchorY: 0.0,
width: width,
// Set the actual width
height: height // Set the actual height
});
// Store dimensions for collision checks
self.wallWidth = width;
self.wallHeight = height;
// No update needed for static walls
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x111111 // Dark background
});
/****
* Game Code
****/
// Game constants and variables
// Define assets used in the game. These will be automatically created and loaded.
function _typeof2(o) {
"@babel/helpers - typeof";
return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof2(o);
}
function _defineProperty2(e, r, t) {
return (r = _toPropertyKey2(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey2(t) {
var i = _toPrimitive2(t, "string");
return "symbol" == _typeof2(i) ? i : i + "";
}
function _toPrimitive2(t, r) {
if ("object" != _typeof2(t) || !t) {
return t;
}
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof2(i)) {
return i;
}
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function _defineProperty(e, r, t) {
return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
value: t,
enumerable: !0,
configurable: !0,
writable: !0
}) : e[r] = t, e;
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == _typeof(i) ? i : i + "";
}
function _toPrimitive(t, r) {
if ("object" != _typeof(t) || !t) {
return t;
}
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != _typeof(i)) {
return i;
}
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
var gameWidth = 2048;
var gameHeight = 2732;
var levelTimeLimit = 60; // Seconds
var totalLevels = 10; // As per description
var requiredCoinsPerLevel = 10;
// Maze definitions for 10 levels with increasing difficulty.
// Each level: walls array [{x, y, width, height}], coins array [{x, y}], startPos {x, y}
var mazeLevels = [
// Level 1: Spiral Maze
{
walls: [
// --- Outer Borders ---
{
x: 100,
y: 200,
width: 1848,
height: 50
},
// Top
{
x: 100,
y: 2482,
width: 1848,
height: 50
},
// Bottom
{
x: 100,
y: 250,
width: 50,
height: 2232
},
// Left
{
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Right
// --- Spiral Arm 1 (Outer) ---
{
x: 150,
y: 450,
width: 1600,
height: 50
},
// H1: Top segment (Leaves gap right: 1750-1898)
{
x: 1750,
y: 500,
width: 50,
height: 1800
},
// V1: Right segment (Leaves gap bottom: 2300-2482)
{
x: 300,
y: 2300,
width: 1500,
height: 50
},
// H2: Bottom segment (Leaves gap left: 150-300)
{
x: 300,
y: 600,
width: 50,
height: 1700
},
// V2: Left segment (Leaves gap top: 450-600)
// --- Spiral Arm 2 (Inner) --- Path width ~150px
{
x: 450,
y: 600,
width: 1150,
height: 50
},
// H3: Top segment (Leaves gap right: 1600-1750)
{
x: 1600,
y: 650,
width: 50,
height: 1500
},
// V3: Right segment (Leaves gap bottom: 2150-2300)
{
x: 450,
y: 2150,
width: 1200,
height: 50
},
// H4: Bottom segment (Leaves gap left: 300-450)
{
x: 450,
y: 750,
width: 50,
height: 1400
},
// V4: Left segment (Leaves gap top: 600-750)
// --- Spiral Arm 3 (Inner) --- Path width ~150px
{
x: 600,
y: 750,
width: 850,
height: 50
},
// H5: Top segment (Leaves gap right: 1450-1600)
{
x: 1450,
y: 800,
width: 50,
height: 1200
},
// V5: Right segment (Leaves gap bottom: 2000-2150)
{
x: 600,
y: 2000,
width: 900,
height: 50
},
// H6: Bottom segment (Leaves gap left: 450-600)
{
x: 600,
y: 900,
width: 50,
height: 1100
},
// V6: Left segment (Leaves gap top: 750-900)
// --- Spiral Arm 4 (Innermost) --- Path width ~150px
{
x: 750,
y: 900,
width: 550,
height: 50
},
// H7: Top segment (Leaves gap right: 1300-1450)
{
x: 1300,
y: 950,
width: 50,
height: 900
},
// V7: Right segment (Leaves gap bottom: 1850-2000)
{
x: 750,
y: 1850,
width: 600,
height: 50
},
// H8: Bottom segment (Leaves gap left: 600-750)
{
x: 750,
y: 1050,
width: 50,
height: 800
},
// V8: Left segment (Leaves gap top: 900-1050)
// --- Center Area Termination --- Blocks the direct path to the center
{
x: 900,
y: 1050,
width: 250,
height: 50
},
// Central H block
{
x: 1100,
y: 1100,
width: 50,
height: 600
} // Central V block
],
coins: [
// Place coins along the spiral path
{
x: 1000,
y: 350
},
// Path 1 Top
{
x: 1825,
y: 1000
},
// Path 1 Right
{
x: 1000,
y: 2400
},
// Path 1 Bottom
{
x: 225,
y: 1500
},
// Path 1 Left
{
x: 1000,
y: 675
},
// Path 2 Top
{
x: 1675,
y: 1500
},
// Path 2 Right
{
x: 1000,
y: 2075
},
// Path 2 Bottom
{
x: 525,
y: 1500
},
// Path 2 Left
{
x: 1000,
y: 975
},
// Path 3 Top
{
x: 1024,
y: 1400
} // Center area (end of spiral)
],
startPos: {
x: 200,
y: 350
} // Start at the entrance near top-left
},
// Level 2: Hypnotic Maze with Doors (Harder)
{
walls: [
// --- Outer Borders (Solid) ---
{
x: 100,
y: 200,
width: 1848,
height: 50
},
// Top
{
x: 100,
y: 2482,
width: 1848,
height: 50
},
// Bottom
{
x: 100,
y: 250,
width: 50,
height: 2232
},
// Left
{
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Right
// --- Layer 1 (Outer Square - Gap Top) --- approx 200px path
{
x: 300,
y: 400,
width: 700,
height: 50
},
// Top Left
{
x: 1150,
y: 400,
width: 700,
height: 50
},
// Top Right (Gap: 1000-1150)
{
x: 300,
y: 2282,
width: 1600,
height: 50
},
// Bottom Full
{
x: 300,
y: 450,
width: 50,
height: 1832
},
// Left Full
// --- Layer 2 (Gap Left) --- approx 200px path
{
x: 500,
y: 600,
width: 1300,
height: 50
},
// Top Full
{
x: 500,
y: 2082,
width: 1300,
height: 50
},
// Bottom Full
{
x: 500,
y: 650,
width: 50,
height: 650
},
// Left Top (Gap: 1300-1432)
{
//{4B} // Reused identifier
x: 500,
y: 1432,
width: 50,
height: 650
},
// Left Bottom
// --- Layer 3 (Gap Bottom) --- approx 200px path
{
x: 700,
y: 800,
width: 900,
height: 50
},
// Top Full
{
x: 700,
y: 1882,
width: 400,
height: 50
},
// Bottom Left (Gap: 1100-1250)
{
//{4G} // Reused identifier
x: 1250,
y: 1882,
width: 350,
height: 50
},
// Bottom Right
{
x: 700,
y: 850,
width: 50,
height: 1032
},
// Left Full
{
x: 1598,
// Adjusted right wall x
y: 850,
width: 50,
height: 1032
},
// Right Full
// --- Layer 4 (Gap Right) --- approx 200px path
{
//{5A} // Reused identifier
x: 900,
y: 1000,
width: 500,
height: 50
},
// Top Full
{
//{5G} // Reused identifier
x: 900,
y: 1682,
width: 500,
height: 50
},
// Bottom Full
{
//{5L} // Reused identifier
x: 900,
y: 1050,
width: 50,
height: 632
},
// Left Full
{
//{5Q} // Reused identifier
x: 1398,
y: 1050,
width: 50,
height: 250 // Right Top (Gap: 1300-1432)
}, {
//{5U} // Reused identifier
x: 1398,
y: 1432,
width: 50,
height: 250 // Right Bottom
},
// --- Central Area (Solid Block) ---
{
//{5F} // Reused identifier
x: 1100,
y: 1200,
width: 200,
height: 282 // Adjusted to be smaller central block
},
// --- Added Dead Ends ---
// Removed small horizontal wall in bottom right
{}],
//{6D} // End walls array
coins: [
// Place coins in accessible locations for the harder maze
{
x: 1800,
y: 2400
},
// Near start
{
x: 400,
y: 2182
},
// Path Layer 1 Bottom Left
{
x: 400,
y: 500
},
// Path Layer 2 Top Left
{
x: 600,
y: 1366 // Near Layer 2 Left Gap
}, {
x: 1700,
y: 700
},
// Path Layer 2 Top Right
{
x: 1700,
y: 1982
},
// Path Layer 3 Bottom Right (near dead end)
{
x: 800,
y: 1982 // Near Layer 3 Bottom Gap
}, {
x: 800,
y: 900
},
// Path Layer 3 Top Left
{
x: 1000,
y: 1100
},
// Path Layer 4 Top Left
{
x: 1300,
y: 1366 // Center Area (final coin)
}],
// End coins
startPos: {
x: 1800,
// Bottom right x
y: 2400 // Bottom right y
} // Start bottom right corner //{83} //{84}
},
// Level 3: S-Shape Path with Doors
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
},
// Top
{
x: 100,
y: 2482,
width: 1848,
height: 50
},
// Bottom
{
x: 100,
y: 250,
width: 50,
height: 2232
},
// Left
{
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Right
// S-shape walls with gaps (doors)
// Top H segment (split for door)
{
x: 100,
y: 700,
width: 650,
// Ends at 750
height: 50
}, {
x: 900,
// Starts at 900 (gap 750-900)
y: 700,
width: 650,
// Ends at 1550
height: 50
},
// Middle H segment (split for door)
{
x: 500,
y: 1200,
width: 650,
// Ends at 1150
height: 50
}, {
x: 1300,
// Starts at 1300 (gap 1150-1300)
y: 1200,
width: 648,
// Ends at 1948
height: 50
},
// Bottom H segment (split for door)
{
x: 100,
y: 1700,
width: 650,
// Ends at 750
height: 50
}, {
x: 900,
// Starts at 900 (gap 750-900)
y: 1700,
width: 650,
// Ends at 1550
height: 50
},
// V segment 1 (top right) - Keep solid for now, rely on H gap
{
x: 1500,
y: 250,
width: 50,
height: 450
},
// V segment 2 (middle left - split for door)
{
x: 500,
y: 750,
width: 50,
height: 200 // Ends at 950
}, {
x: 500,
y: 1050,
// Starts at 1050 (gap 950-1050)
width: 50,
height: 150 // Ends at 1200
},
// V segment 3 (middle right - split for door)
{
x: 1500,
y: 1250,
width: 50,
height: 200 // Ends at 1450
}, {
x: 1500,
y: 1550,
// Starts at 1550 (gap 1450-1550)
width: 50,
height: 150 // Ends at 1700
},
// V segment 4 (bottom left) - Split to create door (gap y:2050-2200)
{
// V segment 4 Top part
x: 500,
y: 1750,
width: 50,
height: 300 // Ends at y=2050
}, {
// V segment 4 Bottom part
x: 500,
y: 2200,
// Starts after gap
width: 50,
height: 282 // Ends at y=2482
}],
coins: [{
x: 300,
y: 300
}, {
x: 1700,
y: 450
}, {
x: 300,
y: 950
}, {
x: 1700,
y: 950
}, {
x: 300,
y: 1450
}, {
x: 1700,
y: 1450
}, {
x: 300,
y: 2000
}, {
x: 1700,
y: 2000
}, {
x: 1000,
y: 1450
}, {
x: 1000,
y: 950
}],
startPos: {
x: 200,
y: 300
}
},
// Level 4: Asymmetric Cross (Modified Doors)
{
walls: [
// --- Outer Borders ---
{
x: 100,
y: 200,
width: 1848,
height: 50
},
// Top
{
x: 100,
y: 2482,
width: 1848,
height: 50
},
// Bottom
{
x: 100,
y: 250,
width: 50,
height: 2232
},
// Left
{
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Right
// --- Internal Walls ---
// Horizontal dividers
// Top H (Gap left: 100-600 -> Wider Door 1)
{
x: 600,
//{9o} // Increased start X
y: 800,
width: 1348,
//{9q} // Adjusted width
height: 50
},
// Bottom H (Gap right: 1448-1898 -> Wider Door 2, split for new door)
// Part 1 (Ends at x=500)
{
x: 100,
y: 1900,
width: 400,
//{9w} // Shorter width
height: 50
},
// Part 2 (Starts at x=700, ends at 1448 -> Gap x:500-700 = New Door Bottom-Left)
{
x: 700,
y: 1900,
width: 748,
// Covers remaining section leaving gap
height: 50
},
// Vertical dividers
// Left V (Gap top: 250-950 -> Wider Door 3)
{
x: 600,
y: 950,
//{9C} // Increased start Y
width: 50,
height: 1532 // Adjusted height
},
// Right V (Gap bottom: 1750-2482 -> Wider Door 4, split for new door)
// Part 1 (Ends at y=700)
{
x: 1400,
y: 250,
width: 50,
height: 450 // Shorter height
},
// Part 2 (Starts at y=900, ends at 1750 -> Gap y:700-900 = New Door Top-Right)
{
x: 1400,
y: 900,
width: 50,
height: 850 // Covers remaining section leaving gap
},
// Twist/Blocking walls (Unchanged)
{
x: 150,
y: 1000,
width: 400,
height: 50
},
// Twist block top-left section
{
x: 1450,
y: 1000,
width: 400,
height: 50
},
// Twist block top-right section
{
x: 150,
y: 1700,
width: 400,
height: 50
},
// Twist block bottom-left section
{
x: 1450,
y: 1700,
width: 400,
height: 50
} // Twist block bottom-right section
],
coins: [{
x: 300,
y: 500
},
// Top Left area (before twist)
{
x: 300,
y: 1300
},
// Top Left area (after twist)
{
x: 1700,
y: 500
},
// Top Right area (before twist)
{
x: 1700,
y: 1300
},
// Top Right area (after twist)
{
x: 300,
y: 2200
},
// Bottom Left area (near corner)
{
x: 300,
y: 1800
},
// Bottom Left area (after twist)
{
x: 1700,
y: 2200
},
// Bottom Right area (near corner)
{
x: 1700,
y: 1800
},
// Bottom Right area (after twist)
{
x: 1024,
y: 1000
},
// Center Top area
{
x: 1024,
y: 1500
} // Center Bottom area
],
startPos: {
x: 200,
y: 300
} // Start Top Left
},
// Level 5: Central Hub Branching
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
},
// Top
{
x: 100,
y: 2482,
width: 1848,
height: 50
},
// Bottom
{
x: 100,
y: 250,
width: 50,
height: 2232
},
// Left
{
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Right
// Central Hub Walls (creating a box ~800x800 in center)
{
x: 624,
y: 966,
width: 800,
height: 50
},
// Hub Top
{
x: 624,
y: 1716,
width: 800,
height: 50
},
// Hub Bottom
{
x: 624,
y: 1016,
width: 50,
height: 700
},
// Hub Left
{
x: 1374,
y: 1016,
width: 50,
height: 700
},
// Hub Right
// Branch Walls (connecting hub/borders to create paths)
{
x: 150,
y: 600,
width: 1700,
height: 50
},
// Top Branch Divider
{
x: 150,
y: 2066,
width: 1700,
height: 50
},
// Bottom Branch Divider
{
x: 350,
y: 650,
width: 50,
height: 1416
},
// Left Branch Divider (Inner)
{
x: 1648,
y: 650,
width: 50,
height: 1416
},
// Right Branch Divider (Inner)
// Add some dead ends or twists within branches
{
x: 150,
y: 1341,
width: 150,
height: 50
},
// Left branch block
{
x: 1748,
y: 1341,
width: 150,
height: 50
},
// Right branch block
{
x: 1000,
y: 250,
width: 50,
height: 300
},
// Top branch block
{
x: 1000,
y: 2116,
width: 50,
height: 300
} // Bottom branch block
],
coins: [{
x: 1024,
y: 1341
},
// Center Hub
{
x: 250,
y: 400
},
// Top Left Branch
{
x: 1798,
y: 400
},
// Top Right Branch
{
x: 250,
y: 2250
},
// Bottom Left Branch
{
x: 1798,
y: 2250
},
// Bottom Right Branch
{
x: 250,
y: 1341
},
// Mid Left Branch end
{
x: 1798,
y: 1341
},
// Mid Right Branch end
{
x: 1024,
y: 350
},
// Mid Top Branch end
{
x: 1024,
y: 2300
},
// Mid Bottom Branch end
{
x: 800,
y: 1500
} // Inside Hub offset
],
startPos: {
x: 1024,
y: 1341
} // Start in Center Hub
},
// Level 6: More complex branching/connections
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
}, {
x: 100,
y: 2482,
width: 1848,
height: 50
}, {
x: 100,
y: 250,
width: 50,
height: 2232
}, {
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Horizontal dividers
{
x: 100,
y: 800,
width: 800,
height: 50
}, {
x: 1148,
y: 800,
width: 800,
height: 50
}, {
x: 100,
y: 1300,
width: 1848,
height: 50
}, {
x: 100,
y: 1800,
width: 800,
height: 50
}, {
x: 1148,
y: 1800,
width: 800,
height: 50
},
// Vertical dividers
{
x: 500,
y: 250,
width: 50,
height: 500
}, {
x: 500,
y: 850,
width: 50,
height: 400
}, {
x: 500,
y: 1350,
width: 50,
height: 400
}, {
x: 500,
y: 1850,
width: 50,
height: 632
}, {
x: 1500,
y: 250,
width: 50,
height: 500
}, {
x: 1500,
y: 850,
width: 50,
height: 400
}, {
x: 1500,
y: 1350,
width: 50,
height: 400
}, {
x: 1500,
y: 1850,
width: 50,
height: 632
}],
coins: [{
x: 300,
y: 300
}, {
x: 1024,
y: 300
}, {
x: 1748,
y: 300
}, {
x: 300,
y: 1050
}, {
x: 1748,
y: 1050
}, {
x: 1024,
y: 1550
},
// Center area coin
{
x: 300,
y: 2100
}, {
x: 1748,
y: 2100
}, {
x: 800,
y: 500
}, {
x: 1248,
y: 2000
}],
startPos: {
x: 1024,
y: 1550
} // Start near center
},
// Level 7: Grid with missing segments
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
}, {
x: 100,
y: 2482,
width: 1848,
height: 50
}, {
x: 100,
y: 250,
width: 50,
height: 2232
}, {
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Grid lines (approx every 450px)
{
x: 100,
y: 650,
width: 1848,
height: 50
}, {
x: 100,
y: 1100,
width: 1848,
height: 50
}, {
x: 100,
y: 1550,
width: 1848,
height: 50
}, {
x: 100,
y: 2000,
width: 1848,
height: 50
}, {
x: 550,
y: 250,
width: 50,
height: 2232
}, {
x: 1000,
y: 250,
width: 50,
height: 2232
}, {
x: 1450,
y: 250,
width: 50,
height: 2232
}
// Remove segments to create path
// (For simplicity, just adding coins in grid cells)
],
coins: [
// Place coins in different grid cells
{
x: 325,
y: 425
}, {
x: 775,
y: 425
}, {
x: 1225,
y: 425
}, {
x: 1675,
y: 425
}, {
x: 325,
y: 875
}, {
x: 1675,
y: 875
},
// Skip middle cells
{
x: 325,
y: 1325
}, {
x: 1675,
y: 1325
}, {
x: 775,
y: 1775
}, {
x: 1225,
y: 2225
}],
startPos: {
x: 325,
y: 2225
} // Start bottom left
},
// Level 8: Spiral (Approximation with Rectangles)
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
}, {
x: 100,
y: 2482,
width: 1848,
height: 50
}, {
x: 100,
y: 250,
width: 50,
height: 2232
}, {
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Outer spiral path
{
x: 100,
y: 700,
width: 1600,
height: 50
},
// H1
{
x: 1650,
y: 250,
width: 50,
height: 900
},
// V1
{
x: 300,
y: 1150,
width: 1400,
height: 50
},
// H2
{
x: 250,
y: 750,
width: 50,
height: 850
},
// V2
{
x: 250,
y: 1600,
width: 1200,
height: 50
},
// H3
{
x: 1450,
y: 1150,
width: 50,
height: 900
},
// V3
{
x: 450,
y: 2050,
width: 1050,
height: 50
},
// H4 (inner end)
{
x: 400,
y: 1650,
width: 50,
height: 400
} // V4 (inner end)
],
coins: [
// Place along the spiral path
{
x: 200,
y: 400
}, {
x: 1000,
y: 400
}, {
x: 1800,
y: 400
},
// Outer Top
{
x: 1800,
y: 900
}, {
x: 1800,
y: 1400
},
// Right Down
{
x: 1000,
y: 900
},
// Inner loop 1
{
x: 400,
y: 900
}, {
x: 400,
y: 1400
},
// Left Down/Up
{
x: 400,
y: 1800
}, {
x: 1000,
y: 1800
} // Inner end area
],
startPos: {
x: 200,
y: 300
} // Start near entrance
},
// Level 9: Dense Obstacles
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
}, {
x: 100,
y: 2482,
width: 1848,
height: 50
}, {
x: 100,
y: 250,
width: 50,
height: 2232
}, {
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Many small walls creating tight paths
{
x: 200,
y: 400,
width: 200,
height: 50
}, {
x: 500,
y: 400,
width: 200,
height: 50
}, {
x: 800,
y: 400,
width: 200,
height: 50
}, {
x: 1100,
y: 400,
width: 200,
height: 50
}, {
x: 1400,
y: 400,
width: 200,
height: 50
}, {
x: 1700,
y: 400,
width: 200,
height: 50
}, {
x: 300,
y: 600,
width: 50,
height: 200
}, {
x: 600,
y: 600,
width: 50,
height: 200
}, {
x: 900,
y: 600,
width: 50,
height: 200
}, {
x: 1200,
y: 600,
width: 50,
height: 200
}, {
x: 1500,
y: 600,
width: 50,
height: 200
}, {
x: 1800,
y: 600,
width: 50,
height: 200
},
// ... Continue pattern downwards ...
{
x: 200,
y: 900,
width: 200,
height: 50
}, {
x: 500,
y: 900,
width: 200,
height: 50
},
// etc.
{
x: 300,
y: 1100,
width: 50,
height: 200
}, {
x: 600,
y: 1100,
width: 50,
height: 200
},
// etc.
{
x: 200,
y: 1400,
width: 200,
height: 50
}, {
x: 500,
y: 1400,
width: 200,
height: 50
},
// etc.
{
x: 300,
y: 1600,
width: 50,
height: 200
}, {
x: 600,
y: 1600,
width: 50,
height: 200
},
// etc.
{
x: 200,
y: 1900,
width: 200,
height: 50
}, {
x: 500,
y: 1900,
width: 200,
height: 50
},
// etc.
{
x: 300,
y: 2100,
width: 50,
height: 200
}, {
x: 600,
y: 2100,
width: 50,
height: 200
},
// etc.
// Mirror pattern on right side
{
x: 1100,
y: 900,
width: 200,
height: 50
}, {
x: 1400,
y: 900,
width: 200,
height: 50
}, {
x: 1700,
y: 900,
width: 200,
height: 50
}, {
x: 1200,
y: 1100,
width: 50,
height: 200
}, {
x: 1500,
y: 1100,
width: 50,
height: 200
}, {
x: 1800,
y: 1100,
width: 50,
height: 200
}, {
x: 1100,
y: 1400,
width: 200,
height: 50
}, {
x: 1400,
y: 1400,
width: 200,
height: 50
}, {
x: 1700,
y: 1400,
width: 200,
height: 50
}, {
x: 1200,
y: 1600,
width: 50,
height: 200
}, {
x: 1500,
y: 1600,
width: 50,
height: 200
}, {
x: 1800,
y: 1600,
width: 50,
height: 200
}, {
x: 1100,
y: 1900,
width: 200,
height: 50
}, {
x: 1400,
y: 1900,
width: 200,
height: 50
}, {
x: 1700,
y: 1900,
width: 200,
height: 50
}, {
x: 1200,
y: 2100,
width: 50,
height: 200
}, {
x: 1500,
y: 2100,
width: 50,
height: 200
}, {
x: 1800,
y: 2100,
width: 50,
height: 200
}],
coins: [
// Place in tricky spots within the dense grid
{
x: 250,
y: 300
}, {
x: 1800,
y: 300
}, {
x: 400,
y: 700
}, {
x: 1650,
y: 700
}, {
x: 750,
y: 1000
}, {
x: 1300,
y: 1000
}, {
x: 250,
y: 1500
}, {
x: 1800,
y: 1500
}, {
x: 400,
y: 2200
}, {
x: 1650,
y: 2200
}],
startPos: {
x: 1024,
y: 300
} // Start top center
},
// Level 10: Final Challenge - Combination
{
walls: [{
x: 100,
y: 200,
width: 1848,
height: 50
}, {
x: 100,
y: 2482,
width: 1848,
height: 50
}, {
x: 100,
y: 250,
width: 50,
height: 2232
}, {
x: 1898,
y: 250,
width: 50,
height: 2232
},
// Mix of grid, long paths, tight spots
// Section 1 (Top Grid)
{
x: 100,
y: 700,
width: 1848,
height: 50
}, {
x: 550,
y: 250,
width: 50,
height: 450
}, {
x: 1000,
y: 250,
width: 50,
height: 450
}, {
x: 1450,
y: 250,
width: 50,
height: 450
},
// Section 2 (Middle Maze)
{
x: 100,
y: 1200,
width: 800,
height: 50
}, {
x: 1148,
y: 1200,
width: 800,
height: 50
}, {
x: 500,
y: 750,
width: 50,
height: 900
}, {
x: 1500,
y: 750,
width: 50,
height: 900
}, {
x: 100,
y: 1650,
width: 1848,
height: 50
},
// Section 3 (Bottom Spiral-like element)
{
x: 300,
y: 2100,
width: 1448,
height: 50
}, {
x: 1748,
y: 1700,
width: 50,
height: 400
}, {
x: 300,
y: 1700,
width: 50,
height: 400
}, {
x: 500,
y: 1900,
width: 1048,
height: 50
} // Inner H
],
coins: [{
x: 325,
y: 400
}, {
x: 1675,
y: 400
},
// Top Grid
{
x: 200,
y: 900
}, {
x: 1800,
y: 900
},
// Mid sides
{
x: 1024,
y: 1400
},
// Mid center
{
x: 400,
y: 1800
}, {
x: 1600,
y: 1800
},
// Lower Mid
{
x: 200,
y: 2300
}, {
x: 1800,
y: 2300
},
// Bottom Corners
{
x: 1024,
y: 2000
} // Bottom Center (inner)
],
startPos: {
x: 1024,
y: 300
} // Start Top Center
}
// NOTE: Circular mazes are hard to represent with rectangular walls.
// This implementation uses only rectangular walls.
];
// Game state variables
var currentLevelIndex = 0;
var walls = [];
var coins = [];
var player = null;
var score = 0;
var timeLeft = levelTimeLimit;
var timerInterval = null;
var scoreTxt = null;
var timerTxt = null;
var levelTxt = null;
var levelComplete = false;
var isDragging = false;
var dragOffset = {
x: 0,
y: 0
}; // Offset between touch point and player center
// --- Helper Functions ---
// Clears current level elements
function clearLevel() {
walls.forEach(function (wall) {
wall.destroy();
});
walls = [];
coins.forEach(function (coin) {
coin.destroy();
});
coins = [];
if (player) {
player.destroy();
player = null;
}
levelComplete = false;
isDragging = false;
}
// Loads a level by index
function loadLevel(levelIndex) {
clearLevel();
if (levelIndex >= mazeLevels.length) {
// Handle case where we run out of predefined levels but haven't reached totalLevels
console.log("Warning: Ran out of predefined maze data, repeating last level.");
levelIndex = mazeLevels.length - 1; // Repeat the last available level
// Ideally, generate levels procedurally or add more data.
if (levelIndex < 0) {
// Should not happen if mazeLevels has data
LK.showGameOver(); // No levels defined at all
return;
}
}
currentLevelIndex = levelIndex; // Update the global index tracker
var levelData = mazeLevels[levelIndex];
// Create walls
levelData.walls.forEach(function (wallData) {
var wall = new Wall(wallData.width, wallData.height);
wall.x = wallData.x;
wall.y = wallData.y;
game.addChild(wall);
walls.push(wall);
});
// Create coins
levelData.coins.forEach(function (coinData) {
var coin = new Coin();
coin.x = coinData.x;
coin.y = coinData.y;
game.addChild(coin);
coins.push(coin);
});
// Create player
player = new Player();
player.x = levelData.startPos.x;
player.y = levelData.startPos.y;
game.addChild(player);
// Reset score and timer for the new level
score = 0;
timeLeft = levelTimeLimit;
updateScoreDisplay();
updateTimerDisplay();
updateLevelDisplay(); // Update level text
startTimer();
}
// Checks collision between player (at potential new position) and all walls
function checkWallCollision(targetX, targetY) {
if (!player) {
return true;
} // No player, collision is effectively true
var playerRadius = player.width / 2; // Assuming player is a circle
// Create a hypothetical bounding box for the player at the target position
var playerBounds = {
left: targetX - playerRadius,
right: targetX + playerRadius,
top: targetY - playerRadius,
bottom: targetY + playerRadius
};
for (var i = 0; i < walls.length; i++) {
var wall = walls[i];
var wallBounds = {
left: wall.x,
right: wall.x + wall.wallWidth,
// Use stored dimensions
top: wall.y,
bottom: wall.y + wall.wallHeight // Use stored dimensions
};
// Basic AABB collision check
if (playerBounds.right > wallBounds.left && playerBounds.left < wallBounds.right && playerBounds.bottom > wallBounds.top && playerBounds.top < wallBounds.bottom) {
return true; // Collision detected
}
}
return false; // No collision
}
// Updates the score display
function updateScoreDisplay() {
scoreTxt.setText("Coins: " + score + "/" + requiredCoinsPerLevel);
}
// Updates the timer display
function updateTimerDisplay() {
timerTxt.setText("Time: " + timeLeft);
}
// Updates the level display
function updateLevelDisplay() {
levelTxt.setText("Level: " + (currentLevelIndex + 1));
}
// Timer tick function
function handleTimerTick() {
if (levelComplete) {
return;
} // Stop timer if level is done
timeLeft--;
updateTimerDisplay();
if (timeLeft <= 0) {
LK.clearInterval(timerInterval);
timerInterval = null;
LK.showGameOver(); // LK handles the game over state
}
}
// Starts the level timer
function startTimer() {
if (timerInterval) {
LK.clearInterval(timerInterval);
}
timeLeft = levelTimeLimit; // Reset time
updateTimerDisplay();
timerInterval = LK.setInterval(handleTimerTick, 1000);
}
// Stops the level timer
function stopTimer() {
if (timerInterval) {
LK.clearInterval(timerInterval);
timerInterval = null;
}
}
// --- GUI Setup ---
// Score display
scoreTxt = new Text2('Coins: 0/' + requiredCoinsPerLevel, {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0); // Anchor middle-top
LK.gui.top.addChild(scoreTxt); // Add to top-center GUI area
scoreTxt.y = 20; // Add some padding from the top edge
// Timer display
timerTxt = new Text2('Time: ' + levelTimeLimit, {
size: 60,
fill: 0xFFFFFF
});
timerTxt.anchor.set(1, 0); // Anchor top-right
LK.gui.topRight.addChild(timerTxt); // Add to top-right GUI area
timerTxt.y = 20; // Match score padding
timerTxt.x = -20; // Add some padding from the right edge
// --- Event Handlers ---
// Level display
levelTxt = new Text2('Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0); // Anchor top-left
LK.gui.topLeft.addChild(levelTxt); // Add to top-left GUI area (near pause)
levelTxt.x = 110; // Offset from the very corner (reserved area)
levelTxt.y = 20; // Match other UI padding
game.down = function (x, y, obj) {
if (levelComplete) {
// If level is complete, tap anywhere to proceed
currentLevelIndex++;
if (currentLevelIndex < totalLevels) {
loadLevel(currentLevelIndex);
} else {
LK.showYouWin(); // Completed all levels
}
return; // Don't process drag start
}
// Check if the press is on the player
var playerPos = player.position;
var dx = x - playerPos.x;
var dy = y - playerPos.y;
var distSq = dx * dx + dy * dy;
var playerRadius = player.width / 2;
// Allow starting drag if touching the player
// Add a small tolerance for easier touch
if (distSq < playerRadius * playerRadius * 1.5 * 1.5) {
isDragging = true;
// Calculate offset from player center to touch point
// The x, y arguments are already in the game's local coordinate system
dragOffset.x = player.x - x;
dragOffset.y = player.y - y;
} else {
isDragging = false;
}
};
game.move = function (x, y, obj) {
if (!isDragging || levelComplete || !player) {
return;
}
// The x, y arguments are already in the game's local coordinate system
var targetX = x + dragOffset.x;
var targetY = y + dragOffset.y;
// Check for collisions *before* moving
if (!checkWallCollision(targetX, targetY)) {
player.x = targetX;
player.y = targetY;
} else {
// Optional: Try moving only horizontally or vertically if diagonal move fails
// Check X movement only
if (!checkWallCollision(targetX, player.y)) {
player.x = targetX;
}
// Check Y movement only
if (!checkWallCollision(player.x, targetY)) {
player.y = targetY;
}
// If both fail, the player stays put
}
};
game.up = function (x, y, obj) {
isDragging = false;
};
// --- Game Update Loop ---
game.update = function () {
if (levelComplete || !player) {
return;
} // Don't update if level is done or no player
// Check for coin collection
var playerRadius = player.width / 2;
for (var i = coins.length - 1; i >= 0; i--) {
var coin = coins[i];
var dx = player.x - coin.x;
var dy = player.y - coin.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var coinRadius = coin.width / 2;
if (distance < playerRadius + coinRadius) {
// Collision detected - collect coin
score++;
updateScoreDisplay();
coin.destroy();
coins.splice(i, 1);
// Check for level completion
if (score >= requiredCoinsPerLevel) {
levelComplete = true;
stopTimer();
// Optionally show a "Level Clear! Tap to continue" message
// For now, just rely on the game.down handler checking levelComplete
console.log("Level " + (currentLevelIndex + 1) + " Complete!");
// Note: LK engine might handle transitions, but the prompt asks for tap to continue.
if (currentLevelIndex + 1 >= totalLevels) {
// If this was the last level according to totalLevels count
LK.showYouWin();
}
// Otherwise, wait for tap in game.down
break; // Exit loop after collecting a coin and potentially completing level
}
}
}
};
// --- Start Game ---
loadLevel(currentLevelIndex);