User prompt
erase final score
User prompt
make random goal place
User prompt
make wide and big labyrinth
User prompt
make generate labyrinth normal dificult route
User prompt
erase final score text
User prompt
fix sound asset
User prompt
add sound asset in game
User prompt
add sound asset
Code edit (1 edits merged)
Please save this source code
User prompt
Gyro Labyrinth Escape
Initial prompt
random labyrinth with gyroscope control towards the goal finish
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Ball: The player-controlled ball var Ball = Container.expand(function () { var self = Container.call(this); var ballSize = 0; self.setSize = function (size) { ballSize = size; if (self.ballAsset) { self.removeChild(self.ballAsset); } self.ballAsset = self.attachAsset('ball', { width: ballSize, height: ballSize, color: 0x3a8cff, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); }; self.radius = function () { return ballSize / 2; }; return self; }); // Finish: The goal area var Finish = Container.expand(function () { var self = Container.call(this); var finishSize = 0; self.setSize = function (size) { finishSize = size; if (self.finishAsset) { self.removeChild(self.finishAsset); } self.finishAsset = self.attachAsset('finish', { width: finishSize, height: finishSize, color: 0x44de83, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); }; return self; }); // MazeCell: Represents a single cell in the maze grid var MazeCell = Container.expand(function () { var self = Container.call(this); // Walls: {top, right, bottom, left} self.walls = [true, true, true, true]; self.visited = false; self.xIndex = 0; self.yIndex = 0; self.size = 0; self.wallGraphics = []; // Draws the cell walls self.draw = function () { // Remove old wall graphics for (var i = 0; i < self.wallGraphics.length; i++) { self.removeChild(self.wallGraphics[i]); } self.wallGraphics = []; var s = self.size; var wallColor = 0x222222; var wallThickness = Math.max(8, Math.floor(s * 0.12)); // Top wall if (self.walls[0]) { var topWall = LK.getAsset('wall', { width: s, height: wallThickness, color: wallColor, shape: 'box', anchorX: 0, anchorY: 0 }); topWall.x = 0; topWall.y = 0; self.addChild(topWall); self.wallGraphics.push(topWall); } // Right wall if (self.walls[1]) { var rightWall = LK.getAsset('wall', { width: wallThickness, height: s, color: wallColor, shape: 'box', anchorX: 0, anchorY: 0 }); rightWall.x = s - wallThickness; rightWall.y = 0; self.addChild(rightWall); self.wallGraphics.push(rightWall); } // Bottom wall if (self.walls[2]) { var bottomWall = LK.getAsset('wall', { width: s, height: wallThickness, color: wallColor, shape: 'box', anchorX: 0, anchorY: 0 }); bottomWall.x = 0; bottomWall.y = s - wallThickness; self.addChild(bottomWall); self.wallGraphics.push(bottomWall); } // Left wall if (self.walls[3]) { var leftWall = LK.getAsset('wall', { width: wallThickness, height: s, color: wallColor, shape: 'box', anchorX: 0, anchorY: 0 }); leftWall.x = 0; leftWall.y = 0; self.addChild(leftWall); self.wallGraphics.push(leftWall); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xf7f7f7 }); /**** * Game Code ****/ // Maze parameters var MAZE_COLS = 8; var MAZE_ROWS = 12; var MAZE_MARGIN = 80; // px margin around maze var mazeCellSize = 0; var mazeOriginX = 0; var mazeOriginY = 0; var maze = []; var mazeContainer = new Container(); game.addChild(mazeContainer); // Ball and Finish var ball = null; var finish = null; // Ball physics var ballPos = { x: 0, y: 0 }; var ballVel = { x: 0, y: 0 }; var ballMaxSpeed = 32; var ballAccel = 2.2; var ballFriction = 0.96; // Gyro state var gyro = { x: 0, y: 0 }; // Timer var startTime = 0; var elapsedTime = 0; // Final score text removed as per requirements // Helper: Clamp function clamp(val, min, max) { return Math.max(min, Math.min(max, val)); } // Helper: Shuffle array function shuffle(arr) { for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = arr[i]; arr[i] = arr[j]; arr[j] = t; } return arr; } // Maze generation: Recursive backtracker with bias for normal difficulty route function generateMaze(cols, rows) { var grid = []; for (var y = 0; y < rows; y++) { var row = []; for (var x = 0; x < cols; x++) { var cell = new MazeCell(); cell.xIndex = x; cell.yIndex = y; cell.size = mazeCellSize; cell.visited = false; row.push(cell); } grid.push(row); } function cellAt(x, y) { if (x < 0 || y < 0 || x >= cols || y >= rows) return null; return grid[y][x]; } var stack = []; var current = grid[0][0]; current.visited = true; var visitedCount = 1; var totalCells = cols * rows; // Bias: prefer to move generally toward the finish, but not always var finishX = cols - 1; var finishY = rows - 1; while (visitedCount < totalCells) { // Find unvisited neighbors var neighbors = []; var dirs = [[0, -1, 0], // top [1, 0, 1], // right [0, 1, 2], // bottom [-1, 0, 3] // left ]; for (var d = 0; d < 4; d++) { var nx = current.xIndex + dirs[d][0]; var ny = current.yIndex + dirs[d][1]; var neighbor = cellAt(nx, ny); if (neighbor && !neighbor.visited) { neighbors.push({ cell: neighbor, dir: d }); } } if (neighbors.length > 0) { // Bias: 60% chance to pick neighbor that is closer to finish, else random var pick; if (Math.random() < 0.6) { // Sort neighbors by distance to finish, pick the closest neighbors.sort(function (a, b) { var da = Math.abs(a.cell.xIndex - finishX) + Math.abs(a.cell.yIndex - finishY); var db = Math.abs(b.cell.xIndex - finishX) + Math.abs(b.cell.yIndex - finishY); return da - db; }); // 50% chance to pick the closest, 50% chance to pick second closest (if exists) if (neighbors.length > 1 && Math.random() < 0.5) { pick = neighbors[1]; } else { pick = neighbors[0]; } } else { pick = neighbors[Math.floor(Math.random() * neighbors.length)]; } // Remove wall between current and neighbor current.walls[pick.dir] = false; var opp = (pick.dir + 2) % 4; pick.cell.walls[opp] = false; stack.push(current); current = pick.cell; current.visited = true; visitedCount++; } else if (stack.length > 0) { current = stack.pop(); } } // Draw all cells for (var y = 0; y < rows; y++) { for (var x = 0; x < cols; x++) { grid[y][x].draw(); } } return grid; } // Place maze in center of screen, calculate cell size function layoutMaze() { var availW = 2048 - MAZE_MARGIN * 2; var availH = 2732 - MAZE_MARGIN * 2; mazeCellSize = Math.floor(Math.min(availW / MAZE_COLS, availH / MAZE_ROWS)); var mazeW = mazeCellSize * MAZE_COLS; var mazeH = mazeCellSize * MAZE_ROWS; mazeOriginX = Math.floor((2048 - mazeW) / 2); mazeOriginY = Math.floor((2732 - mazeH) / 2); mazeContainer.x = mazeOriginX; mazeContainer.y = mazeOriginY; } // Remove all children from mazeContainer function clearMaze() { while (mazeContainer.children.length > 0) { mazeContainer.removeChild(mazeContainer.children[0]); } } // Place ball at start function placeBall() { if (ball) { ball.destroy(); } ball = new Ball(); ball.setSize(Math.floor(mazeCellSize * 0.55)); ballPos.x = mazeCellSize / 2; ballPos.y = mazeCellSize / 2; ball.x = ballPos.x; ball.y = ballPos.y; ballVel.x = 0; ballVel.y = 0; mazeContainer.addChild(ball); } // Place finish at bottom-right cell function placeFinish() { if (finish) { finish.destroy(); } finish = new Finish(); finish.setSize(Math.floor(mazeCellSize * 0.55)); var fx = (MAZE_COLS - 1) * mazeCellSize + mazeCellSize / 2; var fy = (MAZE_ROWS - 1) * mazeCellSize + mazeCellSize / 2; finish.x = fx; finish.y = fy; mazeContainer.addChild(finish); } // Check collision between ball and maze walls function resolveBallMazeCollision() { var r = ball.radius(); var cx = Math.floor(ballPos.x / mazeCellSize); var cy = Math.floor(ballPos.y / mazeCellSize); // Clamp to maze bounds cx = clamp(cx, 0, MAZE_COLS - 1); cy = clamp(cy, 0, MAZE_ROWS - 1); var cell = maze[cy][cx]; var px = ballPos.x - cx * mazeCellSize; var py = ballPos.y - cy * mazeCellSize; var s = mazeCellSize; var wallThickness = Math.max(8, Math.floor(s * 0.12)); // Top wall if (cell.walls[0] && py - r < wallThickness) { ballPos.y = cy * mazeCellSize + wallThickness + r; ballVel.y = Math.max(0, ballVel.y); } // Right wall if (cell.walls[1] && px + r > s - wallThickness) { ballPos.x = cx * mazeCellSize + s - wallThickness - r; ballVel.x = Math.min(0, ballVel.x); } // Bottom wall if (cell.walls[2] && py + r > s - wallThickness) { ballPos.y = cy * mazeCellSize + s - wallThickness - r; ballVel.y = Math.min(0, ballVel.y); } // Left wall if (cell.walls[3] && px - r < wallThickness) { ballPos.x = cx * mazeCellSize + wallThickness + r; ballVel.x = Math.max(0, ballVel.x); } // Clamp to maze area ballPos.x = clamp(ballPos.x, r, MAZE_COLS * mazeCellSize - r); ballPos.y = clamp(ballPos.y, r, MAZE_ROWS * mazeCellSize - r); } // Check if ball reached finish function checkBallFinish() { var fx = (MAZE_COLS - 1) * mazeCellSize + mazeCellSize / 2; var fy = (MAZE_ROWS - 1) * mazeCellSize + mazeCellSize / 2; var dx = ballPos.x - fx; var dy = ballPos.y - fy; var dist = Math.sqrt(dx * dx + dy * dy); if (dist < ball.radius() + finish.finishAsset.width / 2 - 6) { return true; } return false; } // Start new game function startGame() { clearMaze(); layoutMaze(); maze = generateMaze(MAZE_COLS, MAZE_ROWS); // Add all cells to container for (var y = 0; y < MAZE_ROWS; y++) { for (var x = 0; x < MAZE_COLS; x++) { var cell = maze[y][x]; cell.x = x * mazeCellSize; cell.y = y * mazeCellSize; mazeContainer.addChild(cell); } } placeFinish(); placeBall(); startTime = Date.now(); elapsedTime = 0; // timerTxt.setText('0.00'); // Removed as per requirements } // Gyroscope/motion support function handleDeviceMotion(event) { // event.accelerationIncludingGravity.{x,y,z} // On iOS, x is left/right, y is up/down, z is toward/away // On Android, axes may be swapped, so we allow both var ax = 0, ay = 0; if (event.accelerationIncludingGravity) { ax = event.accelerationIncludingGravity.x || 0; ay = event.accelerationIncludingGravity.y || 0; } // Heuristic: On portrait, invert y for natural tilt gyro.x = clamp(ax, -6, 6); gyro.y = clamp(-ay, -6, 6); } if (typeof window !== "undefined" && window.addEventListener) { window.addEventListener('devicemotion', handleDeviceMotion, true); } // Fallback: Touch drag to control ball if no gyro var dragging = false; var lastTouch = { x: 0, y: 0 }; game.down = function (x, y, obj) { // Only start drag if inside maze area var gx = x - mazeOriginX; var gy = y - mazeOriginY; if (gx >= 0 && gx < mazeCellSize * MAZE_COLS && gy >= 0 && gy < mazeCellSize * MAZE_ROWS) { dragging = true; lastTouch.x = x; lastTouch.y = y; } }; game.up = function (x, y, obj) { dragging = false; }; game.move = function (x, y, obj) { if (dragging) { var dx = x - lastTouch.x; var dy = y - lastTouch.y; // Simulate tilt by touch drag gyro.x = clamp(dx * 0.2, -6, 6); gyro.y = clamp(dy * 0.2, -6, 6); lastTouch.x = x; lastTouch.y = y; } }; // Main update loop game.update = function () { // Ball physics // Use gyro.x/gyro.y as acceleration ballVel.x += ballAccel * gyro.x * 0.18; ballVel.y += ballAccel * gyro.y * 0.18; // Friction ballVel.x *= ballFriction; ballVel.y *= ballFriction; // Clamp speed ballVel.x = clamp(ballVel.x, -ballMaxSpeed, ballMaxSpeed); ballVel.y = clamp(ballVel.y, -ballMaxSpeed, ballMaxSpeed); // Move ball ballPos.x += ballVel.x; ballPos.y += ballVel.y; resolveBallMazeCollision(); ball.x = ballPos.x; ball.y = ballPos.y; // Timer elapsedTime = (Date.now() - startTime) / 1000; // timerTxt.setText(elapsedTime.toFixed(2)); // Removed as per requirements // Win condition if (checkBallFinish()) { LK.getSound('finish_reached').play(); LK.effects.flashScreen(0x44de83, 800); LK.showYouWin(); } }; // Start game on load startGame(); // Reset game on game over or win LK.on('gameover', function () { startGame(); }); LK.on('youwin', function () { startGame(); });
===================================================================
--- original.js
+++ change.js
@@ -190,9 +190,9 @@
arr[j] = t;
}
return arr;
}
-// Maze generation: Recursive backtracker
+// Maze generation: Recursive backtracker with bias for normal difficulty route
function generateMaze(cols, rows) {
var grid = [];
for (var y = 0; y < rows; y++) {
var row = [];
@@ -214,8 +214,11 @@
var current = grid[0][0];
current.visited = true;
var visitedCount = 1;
var totalCells = cols * rows;
+ // Bias: prefer to move generally toward the finish, but not always
+ var finishX = cols - 1;
+ var finishY = rows - 1;
while (visitedCount < totalCells) {
// Find unvisited neighbors
var neighbors = [];
var dirs = [[0, -1, 0],
@@ -237,9 +240,26 @@
});
}
}
if (neighbors.length > 0) {
- var pick = neighbors[Math.floor(Math.random() * neighbors.length)];
+ // Bias: 60% chance to pick neighbor that is closer to finish, else random
+ var pick;
+ if (Math.random() < 0.6) {
+ // Sort neighbors by distance to finish, pick the closest
+ neighbors.sort(function (a, b) {
+ var da = Math.abs(a.cell.xIndex - finishX) + Math.abs(a.cell.yIndex - finishY);
+ var db = Math.abs(b.cell.xIndex - finishX) + Math.abs(b.cell.yIndex - finishY);
+ return da - db;
+ });
+ // 50% chance to pick the closest, 50% chance to pick second closest (if exists)
+ if (neighbors.length > 1 && Math.random() < 0.5) {
+ pick = neighbors[1];
+ } else {
+ pick = neighbors[0];
+ }
+ } else {
+ pick = neighbors[Math.floor(Math.random() * neighbors.length)];
+ }
// Remove wall between current and neighbor
current.walls[pick.dir] = false;
var opp = (pick.dir + 2) % 4;
pick.cell.walls[opp] = false;