/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Ball = Container.expand(function () { var self = Container.call(this); var ballGraphics = self.attachAsset('ball', { anchorX: 0.5, anchorY: 0.5 }); self.gridX = 0; self.gridY = 0; self.targetX = 0; self.targetY = 0; self.isMoving = false; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_X; self.y = gridY * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_Y; self.targetX = self.x; self.targetY = self.y; }; self.moveToGrid = function (gridX, gridY) { if (self.isMoving) return; self.gridX = gridX; self.gridY = gridY; self.targetX = gridX * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_X; self.targetY = gridY * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_Y; self.isMoving = true; tween(self, { x: self.targetX, y: self.targetY }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { self.isMoving = false; } }); }; return self; }); var MazeCell = Container.expand(function () { var self = Container.call(this); self.cellType = 'wall'; self.gridX = 0; self.gridY = 0; self.cellGraphics = null; self.setCellType = function (type) { if (self.cellGraphics) { self.removeChild(self.cellGraphics); } self.cellType = type; var assetName = type; self.cellGraphics = self.attachAsset(assetName, { anchorX: 0, anchorY: 0 }); }; self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = gridX * CELL_SIZE + MAZE_OFFSET_X; self.y = gridY * CELL_SIZE + MAZE_OFFSET_Y; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1A1A1A }); /**** * Game Code ****/ var MAZE_WIDTH = 13; var MAZE_HEIGHT = 17; var CELL_SIZE = 80; var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2; var MAZE_OFFSET_Y = (2732 - MAZE_HEIGHT * CELL_SIZE) / 2; var currentLevel = 1; var maze = []; var mazeCells = []; var ball = null; var entranceX = 1; var entranceY = 1; var nextLevelExits = []; var prevLevelExits = []; var dragNode = null; var moveCount = 0; var levelTxt = new Text2('Level: ' + currentLevel, { size: 80, fill: 0xFFFFFF }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 100; var moveCountTxt = new Text2('Moves: ' + moveCount, { size: 60, fill: 0xFFFFFF }); moveCountTxt.anchor.set(1, 0); LK.gui.topRight.addChild(moveCountTxt); moveCountTxt.x = -20; moveCountTxt.y = 20; function generateMaze() { maze = []; for (var y = 0; y < MAZE_HEIGHT; y++) { maze[y] = []; for (var x = 0; x < MAZE_WIDTH; x++) { maze[y][x] = 'wall'; } } // Generate 3 exits to next level and 3 exits to previous level var nextLevelExits = []; var prevLevelExits = []; // Generate 3 exits to next level for (var i = 0; i < 3; i++) { var exitX, exitY; do { exitX = 1 + Math.floor(Math.random() * (MAZE_WIDTH - 2)); exitY = 1 + Math.floor(Math.random() * (MAZE_HEIGHT - 2)); } while (exitX === entranceX && exitY === entranceY || isExitPositionTaken(exitX, exitY, nextLevelExits, prevLevelExits)); nextLevelExits.push({ x: exitX, y: exitY }); } // Generate 3 exits to previous level (only if not on level 1) if (currentLevel > 1) { for (var i = 0; i < 3; i++) { var exitX, exitY; do { exitX = 1 + Math.floor(Math.random() * (MAZE_WIDTH - 2)); exitY = 1 + Math.floor(Math.random() * (MAZE_HEIGHT - 2)); } while (exitX === entranceX && exitY === entranceY || isExitPositionTaken(exitX, exitY, nextLevelExits, prevLevelExits)); prevLevelExits.push({ x: exitX, y: exitY }); } } var complexity = Math.min(currentLevel, 10); var pathCount = 3 + complexity; maze[entranceY][entranceX] = 'entrance'; // Place next level exits for (var i = 0; i < nextLevelExits.length; i++) { maze[nextLevelExits[i].y][nextLevelExits[i].x] = 'exit'; } // Place previous level exits for (var i = 0; i < prevLevelExits.length; i++) { maze[prevLevelExits[i].y][prevLevelExits[i].x] = 'prev_exit'; } var paths = [{ x: entranceX, y: entranceY }, { x: exitX, y: exitY }]; for (var i = 0; i < pathCount; i++) { var x = 1 + Math.floor(Math.random() * (MAZE_WIDTH - 2)); var y = 1 + Math.floor(Math.random() * (MAZE_HEIGHT - 2)); if (maze[y][x] === 'wall') { maze[y][x] = 'path'; paths.push({ x: x, y: y }); } } for (var p = 0; p < paths.length - 1; p++) { var start = paths[p]; var end = paths[p + 1]; createPath(start.x, start.y, end.x, end.y); } var extraConnections = Math.floor(complexity / 2); for (var e = 0; e < extraConnections; e++) { var start = paths[Math.floor(Math.random() * paths.length)]; var end = paths[Math.floor(Math.random() * paths.length)]; if (start !== end) { createPath(start.x, start.y, end.x, end.y); } } } function isExitPositionTaken(x, y, nextExits, prevExits) { for (var i = 0; i < nextExits.length; i++) { if (nextExits[i].x === x && nextExits[i].y === y) return true; } for (var i = 0; i < prevExits.length; i++) { if (prevExits[i].x === x && prevExits[i].y === y) return true; } return false; } function createPath(x1, y1, x2, y2) { var currentX = x1; var currentY = y1; while (currentX !== x2 || currentY !== y2) { if (maze[currentY] && maze[currentY][currentX] === 'wall') { maze[currentY][currentX] = 'path'; } if (currentX < x2) currentX++;else if (currentX > x2) currentX--;else if (currentY < y2) currentY++;else if (currentY > y2) currentY--; } if (maze[currentY] && maze[currentY][currentX] === 'wall') { maze[currentY][currentX] = 'path'; } } function createMazeVisuals() { for (var i = mazeCells.length - 1; i >= 0; i--) { mazeCells[i].destroy(); } mazeCells = []; for (var y = 0; y < MAZE_HEIGHT; y++) { for (var x = 0; x < MAZE_WIDTH; x++) { var cell = new MazeCell(); cell.setGridPosition(x, y); cell.setCellType(maze[y][x]); mazeCells.push(cell); game.addChild(cell); } } } function initializeLevel() { generateMaze(); createMazeVisuals(); if (ball) { ball.destroy(); } ball = new Ball(); ball.setGridPosition(entranceX, entranceY); game.addChild(ball); levelTxt.setText('Level: ' + currentLevel); moveCountTxt.setText('Moves: ' + moveCount); } function isValidMove(gridX, gridY) { if (gridX < 0 || gridX >= MAZE_WIDTH || gridY < 0 || gridY >= MAZE_HEIGHT) { return false; } return maze[gridY][gridX] !== 'wall'; } function getGridFromPosition(x, y) { var gridX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE); var gridY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE); return { x: gridX, y: gridY }; } function handleMove(x, y, obj) { if (dragNode && !ball.isMoving) { var grid = getGridFromPosition(x, y); if (isValidMove(grid.x, grid.y)) { moveCount++; moveCountTxt.setText('Moves: ' + moveCount); ball.moveToGrid(grid.x, grid.y); if (maze[grid.y][grid.x] === 'exit') { LK.getSound('exitSound').play(); LK.setTimeout(function () { currentLevel++; storage.currentLevel = currentLevel; LK.getSound('levelComplete').play(); initializeLevel(); LK.playMusic('backgroundMusic'); }, 300); } else if (maze[grid.y][grid.x] === 'prev_exit' && currentLevel > 1) { LK.getSound('prevExitSound').play(); LK.setTimeout(function () { currentLevel--; storage.currentLevel = currentLevel; LK.getSound('levelComplete').play(); initializeLevel(); }, 300); } } } } game.move = handleMove; game.down = function (x, y, obj) { dragNode = ball; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; initializeLevel();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Ball = Container.expand(function () {
var self = Container.call(this);
var ballGraphics = self.attachAsset('ball', {
anchorX: 0.5,
anchorY: 0.5
});
self.gridX = 0;
self.gridY = 0;
self.targetX = 0;
self.targetY = 0;
self.isMoving = false;
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_X;
self.y = gridY * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_Y;
self.targetX = self.x;
self.targetY = self.y;
};
self.moveToGrid = function (gridX, gridY) {
if (self.isMoving) return;
self.gridX = gridX;
self.gridY = gridY;
self.targetX = gridX * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_X;
self.targetY = gridY * CELL_SIZE + CELL_SIZE / 2 + MAZE_OFFSET_Y;
self.isMoving = true;
tween(self, {
x: self.targetX,
y: self.targetY
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isMoving = false;
}
});
};
return self;
});
var MazeCell = Container.expand(function () {
var self = Container.call(this);
self.cellType = 'wall';
self.gridX = 0;
self.gridY = 0;
self.cellGraphics = null;
self.setCellType = function (type) {
if (self.cellGraphics) {
self.removeChild(self.cellGraphics);
}
self.cellType = type;
var assetName = type;
self.cellGraphics = self.attachAsset(assetName, {
anchorX: 0,
anchorY: 0
});
};
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = gridX * CELL_SIZE + MAZE_OFFSET_X;
self.y = gridY * CELL_SIZE + MAZE_OFFSET_Y;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A1A
});
/****
* Game Code
****/
var MAZE_WIDTH = 13;
var MAZE_HEIGHT = 17;
var CELL_SIZE = 80;
var MAZE_OFFSET_X = (2048 - MAZE_WIDTH * CELL_SIZE) / 2;
var MAZE_OFFSET_Y = (2732 - MAZE_HEIGHT * CELL_SIZE) / 2;
var currentLevel = 1;
var maze = [];
var mazeCells = [];
var ball = null;
var entranceX = 1;
var entranceY = 1;
var nextLevelExits = [];
var prevLevelExits = [];
var dragNode = null;
var moveCount = 0;
var levelTxt = new Text2('Level: ' + currentLevel, {
size: 80,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 100;
var moveCountTxt = new Text2('Moves: ' + moveCount, {
size: 60,
fill: 0xFFFFFF
});
moveCountTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(moveCountTxt);
moveCountTxt.x = -20;
moveCountTxt.y = 20;
function generateMaze() {
maze = [];
for (var y = 0; y < MAZE_HEIGHT; y++) {
maze[y] = [];
for (var x = 0; x < MAZE_WIDTH; x++) {
maze[y][x] = 'wall';
}
}
// Generate 3 exits to next level and 3 exits to previous level
var nextLevelExits = [];
var prevLevelExits = [];
// Generate 3 exits to next level
for (var i = 0; i < 3; i++) {
var exitX, exitY;
do {
exitX = 1 + Math.floor(Math.random() * (MAZE_WIDTH - 2));
exitY = 1 + Math.floor(Math.random() * (MAZE_HEIGHT - 2));
} while (exitX === entranceX && exitY === entranceY || isExitPositionTaken(exitX, exitY, nextLevelExits, prevLevelExits));
nextLevelExits.push({
x: exitX,
y: exitY
});
}
// Generate 3 exits to previous level (only if not on level 1)
if (currentLevel > 1) {
for (var i = 0; i < 3; i++) {
var exitX, exitY;
do {
exitX = 1 + Math.floor(Math.random() * (MAZE_WIDTH - 2));
exitY = 1 + Math.floor(Math.random() * (MAZE_HEIGHT - 2));
} while (exitX === entranceX && exitY === entranceY || isExitPositionTaken(exitX, exitY, nextLevelExits, prevLevelExits));
prevLevelExits.push({
x: exitX,
y: exitY
});
}
}
var complexity = Math.min(currentLevel, 10);
var pathCount = 3 + complexity;
maze[entranceY][entranceX] = 'entrance';
// Place next level exits
for (var i = 0; i < nextLevelExits.length; i++) {
maze[nextLevelExits[i].y][nextLevelExits[i].x] = 'exit';
}
// Place previous level exits
for (var i = 0; i < prevLevelExits.length; i++) {
maze[prevLevelExits[i].y][prevLevelExits[i].x] = 'prev_exit';
}
var paths = [{
x: entranceX,
y: entranceY
}, {
x: exitX,
y: exitY
}];
for (var i = 0; i < pathCount; i++) {
var x = 1 + Math.floor(Math.random() * (MAZE_WIDTH - 2));
var y = 1 + Math.floor(Math.random() * (MAZE_HEIGHT - 2));
if (maze[y][x] === 'wall') {
maze[y][x] = 'path';
paths.push({
x: x,
y: y
});
}
}
for (var p = 0; p < paths.length - 1; p++) {
var start = paths[p];
var end = paths[p + 1];
createPath(start.x, start.y, end.x, end.y);
}
var extraConnections = Math.floor(complexity / 2);
for (var e = 0; e < extraConnections; e++) {
var start = paths[Math.floor(Math.random() * paths.length)];
var end = paths[Math.floor(Math.random() * paths.length)];
if (start !== end) {
createPath(start.x, start.y, end.x, end.y);
}
}
}
function isExitPositionTaken(x, y, nextExits, prevExits) {
for (var i = 0; i < nextExits.length; i++) {
if (nextExits[i].x === x && nextExits[i].y === y) return true;
}
for (var i = 0; i < prevExits.length; i++) {
if (prevExits[i].x === x && prevExits[i].y === y) return true;
}
return false;
}
function createPath(x1, y1, x2, y2) {
var currentX = x1;
var currentY = y1;
while (currentX !== x2 || currentY !== y2) {
if (maze[currentY] && maze[currentY][currentX] === 'wall') {
maze[currentY][currentX] = 'path';
}
if (currentX < x2) currentX++;else if (currentX > x2) currentX--;else if (currentY < y2) currentY++;else if (currentY > y2) currentY--;
}
if (maze[currentY] && maze[currentY][currentX] === 'wall') {
maze[currentY][currentX] = 'path';
}
}
function createMazeVisuals() {
for (var i = mazeCells.length - 1; i >= 0; i--) {
mazeCells[i].destroy();
}
mazeCells = [];
for (var y = 0; y < MAZE_HEIGHT; y++) {
for (var x = 0; x < MAZE_WIDTH; x++) {
var cell = new MazeCell();
cell.setGridPosition(x, y);
cell.setCellType(maze[y][x]);
mazeCells.push(cell);
game.addChild(cell);
}
}
}
function initializeLevel() {
generateMaze();
createMazeVisuals();
if (ball) {
ball.destroy();
}
ball = new Ball();
ball.setGridPosition(entranceX, entranceY);
game.addChild(ball);
levelTxt.setText('Level: ' + currentLevel);
moveCountTxt.setText('Moves: ' + moveCount);
}
function isValidMove(gridX, gridY) {
if (gridX < 0 || gridX >= MAZE_WIDTH || gridY < 0 || gridY >= MAZE_HEIGHT) {
return false;
}
return maze[gridY][gridX] !== 'wall';
}
function getGridFromPosition(x, y) {
var gridX = Math.floor((x - MAZE_OFFSET_X) / CELL_SIZE);
var gridY = Math.floor((y - MAZE_OFFSET_Y) / CELL_SIZE);
return {
x: gridX,
y: gridY
};
}
function handleMove(x, y, obj) {
if (dragNode && !ball.isMoving) {
var grid = getGridFromPosition(x, y);
if (isValidMove(grid.x, grid.y)) {
moveCount++;
moveCountTxt.setText('Moves: ' + moveCount);
ball.moveToGrid(grid.x, grid.y);
if (maze[grid.y][grid.x] === 'exit') {
LK.getSound('exitSound').play();
LK.setTimeout(function () {
currentLevel++;
storage.currentLevel = currentLevel;
LK.getSound('levelComplete').play();
initializeLevel();
LK.playMusic('backgroundMusic');
}, 300);
} else if (maze[grid.y][grid.x] === 'prev_exit' && currentLevel > 1) {
LK.getSound('prevExitSound').play();
LK.setTimeout(function () {
currentLevel--;
storage.currentLevel = currentLevel;
LK.getSound('levelComplete').play();
initializeLevel();
}, 300);
}
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = ball;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
};
initializeLevel();