/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Cube class var Cube = Container.expand(function () { var self = Container.call(this); // Cube base var cubeGfx = self.attachAsset('cube', { anchorX: 0.5, anchorY: 0.5 }); // Arrow overlay self.arrowGfx = null; // Grid position self.gridX = 0; self.gridY = 0; // Direction index (0:up, 1:down, 2:left, 3:right) self.dir = 0; // Is this cube currently animating? self.isSliding = false; // Set direction and update arrow self.setDirection = function (dirIdx) { self.dir = dirIdx; if (self.arrowGfx) { self.removeChild(self.arrowGfx); } // Set cube color based on direction var dirColors = [0x3b82f6, // up - blue 0xf59e42, // down - orange 0x22c55e, // left - green 0xf43f5e // right - red ]; if (cubeGfx && dirIdx >= 0 && dirIdx < dirColors.length) { cubeGfx.tint = dirColors[dirIdx]; } else if (cubeGfx) { cubeGfx.tint = 0x707070; } // Defensive: Only set arrow if dirIdx is valid if (dirIdx >= 0 && dirIdx < DIRS.length) { var dir = DIRS[dirIdx]; self.arrowGfx = self.attachAsset(dir.arrow, { anchorX: 0.5, anchorY: 0.5 }); } else { // Fallback: show no arrow if direction is invalid self.arrowGfx = null; } }; // Called when tapped self.down = function (x, y, obj) { if (self.isSliding) { return; } if (game.isAnimating) { return; } // Hide 'Tap to Play' text after first click if (typeof tapToPlayTxt !== "undefined" && tapToPlayTxt.parent) { tapToPlayTxt.visible = false; } // Play click sound LK.getSound('click').play(); game.trySlideCube(self); }; // Always attach event listeners when Cube is created self.interactive = true; self.on('down', self.down); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222831 }); /**** * Game Code ****/ // Add a full-screen background image behind everything var backgroundImageRef = LK.getAsset('background_image', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732, alpha: 1 }); game.addChild(backgroundImageRef); var backgroundImage = LK.getAsset('grid_image', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732, alpha: 0.25 // subtle, so grid/cubes are visible }); game.addChild(backgroundImage); // Cube directions // Tween for sliding animation // Arrow assets: 120x60, colored arrows for each direction // Cube asset: 200x200, white box // Grid config var DIRS = [{ name: 'up', dx: 0, dy: -1, arrow: 'arrow_up', rot: 0 }, { name: 'down', dx: 0, dy: 1, arrow: 'arrow_down', rot: 0 }, { name: 'left', dx: -1, dy: 0, arrow: 'arrow_left', rot: 0 }, { name: 'right', dx: 1, dy: 0, arrow: 'arrow_right', rot: 0 }]; var GRID_SIZE = 4; var CELL_SIZE = 260; // 200px cube + 60px gap var GRID_ORIGIN_X = Math.floor((2048 - GRID_SIZE * CELL_SIZE) / 2) + CELL_SIZE / 2; var GRID_ORIGIN_Y = Math.floor((2732 - GRID_SIZE * CELL_SIZE) / 2) + CELL_SIZE / 2; // Game state var cubes = []; // 2D array [y][x] of Cube or null var cubeList = []; // Flat list of all Cube objects var isAnimating = false; // Score text var scoreTxt = new Text2('0', { size: 120, fill: 0xFFFFFF, font: "Lilita One" }); scoreTxt.anchor.set(0.5, -2); LK.gui.top.addChild(scoreTxt); // "Tap to Play" text centered on the screen var tapToPlayTxt = new Text2('Tap to Play', { size: 140, fill: 0xffffff, font: "Lilita One" }); tapToPlayTxt.anchor.set(0.5, 0.5); tapToPlayTxt.x = 2048 / 2; tapToPlayTxt.y = 2732 / 2 + 700; game.addChild(tapToPlayTxt); // Helper: get grid cell center position function gridToPos(gx, gy) { return { x: GRID_ORIGIN_X + gx * CELL_SIZE, y: GRID_ORIGIN_Y + gy * CELL_SIZE }; } // Helper: check if (gx,gy) is inside grid function inGrid(gx, gy) { return gx >= 0 && gx < GRID_SIZE && gy >= 0 && gy < GRID_SIZE; } // Helper: update score display function updateScore() { var left = 0; for (var y = 0; y < GRID_SIZE; ++y) { for (var x = 0; x < GRID_SIZE; ++x) { if (cubes[y][x]) { left++; } } } scoreTxt.setText(left + ""); } // Try to slide a cube in its direction game.trySlideCube = function (cube) { // Only allow one animation at a time if (game.isAnimating) { return; } if (cube.isSliding) { return; } var dir = DIRS[cube.dir]; var gx = cube.gridX; var gy = cube.gridY; var dx = dir.dx; var dy = dir.dy; // Prevent border cubes facing outwards from moving if (gx === 0 && dx === -1 || // left edge, facing left gx === GRID_SIZE - 1 && dx === 1 || // right edge, facing right gy === 0 && dy === -1 || // top edge, facing up gy === GRID_SIZE - 1 && dy === 1 // bottom edge, facing down ) { // Cube is on the border and facing outwards, do not move return; } // Find farthest empty cell in direction var nx = gx; var ny = gy; while (true) { var tx = nx + dx; var ty = ny + dy; if (!inGrid(tx, ty)) { // Out of grid, can slide out break; } if (cubes[ty][tx]) { // Blocked by another cube // Can't move return; } nx = tx; ny = ty; } // If not moving, do nothing if (nx === gx && ny === gy) { return; } // Mark animating cube.isSliding = true; game.isAnimating = true; // Remove from grid cubes[gy][gx] = null; // Animate to out-of-grid position var endPos; if (inGrid(nx, ny)) { // Should not happen, but fallback endPos = gridToPos(nx, ny); } else { // Compute position just outside grid var outX = nx; var outY = ny; // If moving right, outX is GRID_SIZE, left: -1 // If moving down, outY is GRID_SIZE, up: -1 endPos = { x: GRID_ORIGIN_X + nx * CELL_SIZE, y: GRID_ORIGIN_Y + ny * CELL_SIZE }; } // Animate slide // Calculate cell distance for duration var cellDist = Math.abs(nx - gx) + Math.abs(ny - gy); var duration = Math.max(120, cellDist * 180); // Minimum 120ms, 180ms per cell tween(cube, { x: endPos.x, y: endPos.y }, { duration: duration, onFinish: function onFinish() { // Remove cube from scene and list var idx = cubeList.indexOf(cube); if (idx !== -1) { cubeList.splice(idx, 1); } cube.isSliding = false; game.isAnimating = false; updateScore(); // Check win var left = 0; for (var y = 0; y < GRID_SIZE; ++y) { for (var x = 0; x < GRID_SIZE; ++x) { if (cubes[y][x]) { left++; } } } if (left === 0) { // Show confetti particle effect for level complete storage.slidecubes_save = { currentLevel: currentLevel + 1 }; if (currentLevel < LEVELS.length - 1) { // Show win popup, then load next level after play again buildLevel(currentLevel + 1); } else { LK.showYouWin(); } } cube.destroy(); } }); }; // --- Level definitions --- var LEVELS = [ // Level 1: Simple, 2 cubes, easy [{ x: 0, y: 0, dir: 1 }, // down { x: 3, y: 3, dir: 0 } // up ], // Level 2: 3 cubes, all corners, different directions [{ x: 0, y: 0, dir: 3 }, // right { x: 3, y: 0, dir: 1 }, // down { x: 3, y: 3, dir: 2 } // left ], // Level 3: 4 cubes, one per edge, all different [{ x: 0, y: 1, dir: 3 }, // right { x: 1, y: 0, dir: 1 }, // down { x: 3, y: 2, dir: 2 }, // left { x: 2, y: 3, dir: 0 } // up ], // Level 4: 5 cubes, more central, some block each other [{ x: 0, y: 2, dir: 3 }, // right { x: 1, y: 1, dir: 1 }, // down { x: 2, y: 0, dir: 2 }, // left { x: 3, y: 1, dir: 0 }, // up { x: 2, y: 2, dir: 1 } // down ], // Level 5: 6 cubes, more complex, some in line [{ x: 0, y: 0, dir: 1 }, // down { x: 1, y: 2, dir: 2 }, // left { x: 2, y: 1, dir: 3 }, // right { x: 3, y: 3, dir: 0 }, // up { x: 1, y: 3, dir: 2 }, // left { x: 2, y: 3, dir: 0 } // up ], // Level 6: 7 cubes, some block each other, more challenge [{ x: 0, y: 1, dir: 3 }, // right { x: 1, y: 0, dir: 1 }, // down { x: 2, y: 2, dir: 2 }, // left { x: 3, y: 1, dir: 1 }, // up { x: 1, y: 3, dir: 3 }, // left { x: 2, y: 3, dir: 0 }, // up { x: 3, y: 0, dir: 1 } // down ], // Level 7: 8 cubes, more central, some in line, higher difficulty [{ x: 0, y: 0, dir: 1 }, // down { x: 1, y: 1, dir: 3 }, // right { x: 2, y: 2, dir: 2 }, // up { x: 0, y: 3, dir: 3 }, // right { x: 3, y: 0, dir: 1 }, // down { x: 1, y: 2, dir: 2 }, // left { x: 2, y: 1, dir: 0 } // up ], // Level 8: 9 cubes, nearly full, complex [{ x: 0, y: 0, dir: 1 }, // down { x: 1, y: 0, dir: 1 }, // down { x: 2, y: 0, dir: 1 }, // down { x: 3, y: 0, dir: 2 }, // left { x: 0, y: 1, dir: 3 }, // right { x: 3, y: 1, dir: 1 }, // left { x: 0, y: 2, dir: 3 }, // right { x: 3, y: 2, dir: 1 }, // left { x: 1, y: 3, dir: 2 } // up ], // Level 9: 10 cubes, very challenging [{ x: 0, y: 0, dir: 1 }, // down { x: 1, y: 0, dir: 2 }, // down { x: 2, y: 0, dir: 1 }, // down { x: 3, y: 0, dir: 2 }, // left { x: 0, y: 1, dir: 1 }, // right { x: 3, y: 1, dir: 2 }, // right { x: 3, y: 2, dir: 2 }, // left { x: 1, y: 3, dir: 0 }, // up { x: 2, y: 3, dir: 3 } // up ]]; var currentLevel = 0; // Level indicator text var levelTxt = new Text2('Level 1', { size: 90, fill: 0xFFD700, font: "Lilita One" }); levelTxt.anchor.set(0.5, -1); LK.gui.top.addChild(levelTxt); // Build a level by index function buildLevel(idx) { // Clamp level index if (idx < 0) { idx = 0; } if (idx >= LEVELS.length) { idx = LEVELS.length - 1; } currentLevel = idx; // Save current level to storage storage.slidecubes_save = { currentLevel: currentLevel }; // Reset animation state game.isAnimating = false; // Clear previous for (var i = 0; i < cubeList.length; ++i) { if (cubeList[i]) { cubeList[i].isSliding = false; // Reset sliding state in case any cube is still flagged cubeList[i].destroy(); } } cubeList = []; cubes = []; for (var y = 0; y < GRID_SIZE; ++y) { var row = []; for (var x = 0; x < GRID_SIZE; ++x) { row.push(null); } cubes.push(row); } // Draw grid image reference behind the grid (per cell) if (game.gridImageRefs) { for (var i = 0; i < game.gridImageRefs.length; ++i) { if (game.gridImageRefs[i]) { game.gridImageRefs[i].destroy(); } } } game.gridImageRefs = []; for (var gy = 0; gy < GRID_SIZE; ++gy) { for (var gx = 0; gx < GRID_SIZE; ++gx) { var pos = gridToPos(gx, gy); var gridImg = LK.getAsset('grid_image', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, alpha: 0.18, width: CELL_SIZE * .9, height: CELL_SIZE * .9 }); game.addChild(gridImg); game.gridImageRefs.push(gridImg); } } // Draw grid background squares (faint, behind cubes) if (game.gridSquares) { for (var i = 0; i < game.gridSquares.length; ++i) { if (game.gridSquares[i]) { game.gridSquares[i].destroy(); } } } game.gridSquares = []; for (var gy = 0; gy < GRID_SIZE; ++gy) { for (var gx = 0; gx < GRID_SIZE; ++gx) { var pos = gridToPos(gx, gy); var gridSquare = LK.getAsset('cube', { anchorX: 0.5, anchorY: 0.5, x: pos.x, y: pos.y, tint: 0xcccccc, alpha: 0.18, width: 200, height: 200 }); game.addChild(gridSquare); game.gridSquares.push(gridSquare); } } // Place cubes for this level var levelCubes = LEVELS[idx]; for (var i = 0; i < levelCubes.length; ++i) { var c = levelCubes[i]; var cube = new Cube(); cube.gridX = c.x; cube.gridY = c.y; cube.setDirection(c.dir); var pos = gridToPos(c.x, c.y); cube.x = pos.x; cube.y = pos.y; cubes[c.y][c.x] = cube; cubeList.push(cube); game.addChild(cube); // Re-attach event listeners for interaction cube.interactive = true; cube.on('down', cube.down); } updateScore(); levelTxt.setText("Level " + (currentLevel + 1)); game.isAnimating = false; } // Prevent accidental drag game.move = function (x, y, obj) {}; // No drag game.down = function (x, y, obj) {}; game.up = function (x, y, obj) {}; // No per-tick logic needed game.update = function () {}; // Check for saved game state on load and restore if present // Clear save history var saved = storage.slidecubes_save; if (saved && typeof saved.currentLevel === "number" && saved.currentLevel >= 0 && saved.currentLevel < LEVELS.length) { buildLevel(saved.currentLevel); } else { buildLevel(0); // Level 1 is index 0 }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Cube class
var Cube = Container.expand(function () {
var self = Container.call(this);
// Cube base
var cubeGfx = self.attachAsset('cube', {
anchorX: 0.5,
anchorY: 0.5
});
// Arrow overlay
self.arrowGfx = null;
// Grid position
self.gridX = 0;
self.gridY = 0;
// Direction index (0:up, 1:down, 2:left, 3:right)
self.dir = 0;
// Is this cube currently animating?
self.isSliding = false;
// Set direction and update arrow
self.setDirection = function (dirIdx) {
self.dir = dirIdx;
if (self.arrowGfx) {
self.removeChild(self.arrowGfx);
}
// Set cube color based on direction
var dirColors = [0x3b82f6,
// up - blue
0xf59e42,
// down - orange
0x22c55e,
// left - green
0xf43f5e // right - red
];
if (cubeGfx && dirIdx >= 0 && dirIdx < dirColors.length) {
cubeGfx.tint = dirColors[dirIdx];
} else if (cubeGfx) {
cubeGfx.tint = 0x707070;
}
// Defensive: Only set arrow if dirIdx is valid
if (dirIdx >= 0 && dirIdx < DIRS.length) {
var dir = DIRS[dirIdx];
self.arrowGfx = self.attachAsset(dir.arrow, {
anchorX: 0.5,
anchorY: 0.5
});
} else {
// Fallback: show no arrow if direction is invalid
self.arrowGfx = null;
}
};
// Called when tapped
self.down = function (x, y, obj) {
if (self.isSliding) {
return;
}
if (game.isAnimating) {
return;
}
// Hide 'Tap to Play' text after first click
if (typeof tapToPlayTxt !== "undefined" && tapToPlayTxt.parent) {
tapToPlayTxt.visible = false;
}
// Play click sound
LK.getSound('click').play();
game.trySlideCube(self);
};
// Always attach event listeners when Cube is created
self.interactive = true;
self.on('down', self.down);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x222831
});
/****
* Game Code
****/
// Add a full-screen background image behind everything
var backgroundImageRef = LK.getAsset('background_image', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732,
alpha: 1
});
game.addChild(backgroundImageRef);
var backgroundImage = LK.getAsset('grid_image', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732,
alpha: 0.25 // subtle, so grid/cubes are visible
});
game.addChild(backgroundImage);
// Cube directions
// Tween for sliding animation
// Arrow assets: 120x60, colored arrows for each direction
// Cube asset: 200x200, white box
// Grid config
var DIRS = [{
name: 'up',
dx: 0,
dy: -1,
arrow: 'arrow_up',
rot: 0
}, {
name: 'down',
dx: 0,
dy: 1,
arrow: 'arrow_down',
rot: 0
}, {
name: 'left',
dx: -1,
dy: 0,
arrow: 'arrow_left',
rot: 0
}, {
name: 'right',
dx: 1,
dy: 0,
arrow: 'arrow_right',
rot: 0
}];
var GRID_SIZE = 4;
var CELL_SIZE = 260; // 200px cube + 60px gap
var GRID_ORIGIN_X = Math.floor((2048 - GRID_SIZE * CELL_SIZE) / 2) + CELL_SIZE / 2;
var GRID_ORIGIN_Y = Math.floor((2732 - GRID_SIZE * CELL_SIZE) / 2) + CELL_SIZE / 2;
// Game state
var cubes = []; // 2D array [y][x] of Cube or null
var cubeList = []; // Flat list of all Cube objects
var isAnimating = false;
// Score text
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF,
font: "Lilita One"
});
scoreTxt.anchor.set(0.5, -2);
LK.gui.top.addChild(scoreTxt);
// "Tap to Play" text centered on the screen
var tapToPlayTxt = new Text2('Tap to Play', {
size: 140,
fill: 0xffffff,
font: "Lilita One"
});
tapToPlayTxt.anchor.set(0.5, 0.5);
tapToPlayTxt.x = 2048 / 2;
tapToPlayTxt.y = 2732 / 2 + 700;
game.addChild(tapToPlayTxt);
// Helper: get grid cell center position
function gridToPos(gx, gy) {
return {
x: GRID_ORIGIN_X + gx * CELL_SIZE,
y: GRID_ORIGIN_Y + gy * CELL_SIZE
};
}
// Helper: check if (gx,gy) is inside grid
function inGrid(gx, gy) {
return gx >= 0 && gx < GRID_SIZE && gy >= 0 && gy < GRID_SIZE;
}
// Helper: update score display
function updateScore() {
var left = 0;
for (var y = 0; y < GRID_SIZE; ++y) {
for (var x = 0; x < GRID_SIZE; ++x) {
if (cubes[y][x]) {
left++;
}
}
}
scoreTxt.setText(left + "");
}
// Try to slide a cube in its direction
game.trySlideCube = function (cube) {
// Only allow one animation at a time
if (game.isAnimating) {
return;
}
if (cube.isSliding) {
return;
}
var dir = DIRS[cube.dir];
var gx = cube.gridX;
var gy = cube.gridY;
var dx = dir.dx;
var dy = dir.dy;
// Prevent border cubes facing outwards from moving
if (gx === 0 && dx === -1 ||
// left edge, facing left
gx === GRID_SIZE - 1 && dx === 1 ||
// right edge, facing right
gy === 0 && dy === -1 ||
// top edge, facing up
gy === GRID_SIZE - 1 && dy === 1 // bottom edge, facing down
) {
// Cube is on the border and facing outwards, do not move
return;
}
// Find farthest empty cell in direction
var nx = gx;
var ny = gy;
while (true) {
var tx = nx + dx;
var ty = ny + dy;
if (!inGrid(tx, ty)) {
// Out of grid, can slide out
break;
}
if (cubes[ty][tx]) {
// Blocked by another cube
// Can't move
return;
}
nx = tx;
ny = ty;
}
// If not moving, do nothing
if (nx === gx && ny === gy) {
return;
}
// Mark animating
cube.isSliding = true;
game.isAnimating = true;
// Remove from grid
cubes[gy][gx] = null;
// Animate to out-of-grid position
var endPos;
if (inGrid(nx, ny)) {
// Should not happen, but fallback
endPos = gridToPos(nx, ny);
} else {
// Compute position just outside grid
var outX = nx;
var outY = ny;
// If moving right, outX is GRID_SIZE, left: -1
// If moving down, outY is GRID_SIZE, up: -1
endPos = {
x: GRID_ORIGIN_X + nx * CELL_SIZE,
y: GRID_ORIGIN_Y + ny * CELL_SIZE
};
}
// Animate slide
// Calculate cell distance for duration
var cellDist = Math.abs(nx - gx) + Math.abs(ny - gy);
var duration = Math.max(120, cellDist * 180); // Minimum 120ms, 180ms per cell
tween(cube, {
x: endPos.x,
y: endPos.y
}, {
duration: duration,
onFinish: function onFinish() {
// Remove cube from scene and list
var idx = cubeList.indexOf(cube);
if (idx !== -1) {
cubeList.splice(idx, 1);
}
cube.isSliding = false;
game.isAnimating = false;
updateScore();
// Check win
var left = 0;
for (var y = 0; y < GRID_SIZE; ++y) {
for (var x = 0; x < GRID_SIZE; ++x) {
if (cubes[y][x]) {
left++;
}
}
}
if (left === 0) {
// Show confetti particle effect for level complete
storage.slidecubes_save = {
currentLevel: currentLevel + 1
};
if (currentLevel < LEVELS.length - 1) {
// Show win popup, then load next level after play again
buildLevel(currentLevel + 1);
} else {
LK.showYouWin();
}
}
cube.destroy();
}
});
};
// --- Level definitions ---
var LEVELS = [
// Level 1: Simple, 2 cubes, easy
[{
x: 0,
y: 0,
dir: 1
},
// down
{
x: 3,
y: 3,
dir: 0
} // up
],
// Level 2: 3 cubes, all corners, different directions
[{
x: 0,
y: 0,
dir: 3
},
// right
{
x: 3,
y: 0,
dir: 1
},
// down
{
x: 3,
y: 3,
dir: 2
} // left
],
// Level 3: 4 cubes, one per edge, all different
[{
x: 0,
y: 1,
dir: 3
},
// right
{
x: 1,
y: 0,
dir: 1
},
// down
{
x: 3,
y: 2,
dir: 2
},
// left
{
x: 2,
y: 3,
dir: 0
} // up
],
// Level 4: 5 cubes, more central, some block each other
[{
x: 0,
y: 2,
dir: 3
},
// right
{
x: 1,
y: 1,
dir: 1
},
// down
{
x: 2,
y: 0,
dir: 2
},
// left
{
x: 3,
y: 1,
dir: 0
},
// up
{
x: 2,
y: 2,
dir: 1
} // down
],
// Level 5: 6 cubes, more complex, some in line
[{
x: 0,
y: 0,
dir: 1
},
// down
{
x: 1,
y: 2,
dir: 2
},
// left
{
x: 2,
y: 1,
dir: 3
},
// right
{
x: 3,
y: 3,
dir: 0
},
// up
{
x: 1,
y: 3,
dir: 2
},
// left
{
x: 2,
y: 3,
dir: 0
} // up
],
// Level 6: 7 cubes, some block each other, more challenge
[{
x: 0,
y: 1,
dir: 3
},
// right
{
x: 1,
y: 0,
dir: 1
},
// down
{
x: 2,
y: 2,
dir: 2
},
// left
{
x: 3,
y: 1,
dir: 1
},
// up
{
x: 1,
y: 3,
dir: 3
},
// left
{
x: 2,
y: 3,
dir: 0
},
// up
{
x: 3,
y: 0,
dir: 1
} // down
],
// Level 7: 8 cubes, more central, some in line, higher difficulty
[{
x: 0,
y: 0,
dir: 1
},
// down
{
x: 1,
y: 1,
dir: 3
},
// right
{
x: 2,
y: 2,
dir: 2
},
// up
{
x: 0,
y: 3,
dir: 3
},
// right
{
x: 3,
y: 0,
dir: 1
},
// down
{
x: 1,
y: 2,
dir: 2
},
// left
{
x: 2,
y: 1,
dir: 0
} // up
],
// Level 8: 9 cubes, nearly full, complex
[{
x: 0,
y: 0,
dir: 1
},
// down
{
x: 1,
y: 0,
dir: 1
},
// down
{
x: 2,
y: 0,
dir: 1
},
// down
{
x: 3,
y: 0,
dir: 2
},
// left
{
x: 0,
y: 1,
dir: 3
},
// right
{
x: 3,
y: 1,
dir: 1
},
// left
{
x: 0,
y: 2,
dir: 3
},
// right
{
x: 3,
y: 2,
dir: 1
},
// left
{
x: 1,
y: 3,
dir: 2
} // up
],
// Level 9: 10 cubes, very challenging
[{
x: 0,
y: 0,
dir: 1
},
// down
{
x: 1,
y: 0,
dir: 2
},
// down
{
x: 2,
y: 0,
dir: 1
},
// down
{
x: 3,
y: 0,
dir: 2
},
// left
{
x: 0,
y: 1,
dir: 1
},
// right
{
x: 3,
y: 1,
dir: 2
},
// right
{
x: 3,
y: 2,
dir: 2
},
// left
{
x: 1,
y: 3,
dir: 0
},
// up
{
x: 2,
y: 3,
dir: 3
} // up
]];
var currentLevel = 0;
// Level indicator text
var levelTxt = new Text2('Level 1', {
size: 90,
fill: 0xFFD700,
font: "Lilita One"
});
levelTxt.anchor.set(0.5, -1);
LK.gui.top.addChild(levelTxt);
// Build a level by index
function buildLevel(idx) {
// Clamp level index
if (idx < 0) {
idx = 0;
}
if (idx >= LEVELS.length) {
idx = LEVELS.length - 1;
}
currentLevel = idx;
// Save current level to storage
storage.slidecubes_save = {
currentLevel: currentLevel
};
// Reset animation state
game.isAnimating = false;
// Clear previous
for (var i = 0; i < cubeList.length; ++i) {
if (cubeList[i]) {
cubeList[i].isSliding = false; // Reset sliding state in case any cube is still flagged
cubeList[i].destroy();
}
}
cubeList = [];
cubes = [];
for (var y = 0; y < GRID_SIZE; ++y) {
var row = [];
for (var x = 0; x < GRID_SIZE; ++x) {
row.push(null);
}
cubes.push(row);
}
// Draw grid image reference behind the grid (per cell)
if (game.gridImageRefs) {
for (var i = 0; i < game.gridImageRefs.length; ++i) {
if (game.gridImageRefs[i]) {
game.gridImageRefs[i].destroy();
}
}
}
game.gridImageRefs = [];
for (var gy = 0; gy < GRID_SIZE; ++gy) {
for (var gx = 0; gx < GRID_SIZE; ++gx) {
var pos = gridToPos(gx, gy);
var gridImg = LK.getAsset('grid_image', {
anchorX: 0.5,
anchorY: 0.5,
x: pos.x,
y: pos.y,
alpha: 0.18,
width: CELL_SIZE * .9,
height: CELL_SIZE * .9
});
game.addChild(gridImg);
game.gridImageRefs.push(gridImg);
}
}
// Draw grid background squares (faint, behind cubes)
if (game.gridSquares) {
for (var i = 0; i < game.gridSquares.length; ++i) {
if (game.gridSquares[i]) {
game.gridSquares[i].destroy();
}
}
}
game.gridSquares = [];
for (var gy = 0; gy < GRID_SIZE; ++gy) {
for (var gx = 0; gx < GRID_SIZE; ++gx) {
var pos = gridToPos(gx, gy);
var gridSquare = LK.getAsset('cube', {
anchorX: 0.5,
anchorY: 0.5,
x: pos.x,
y: pos.y,
tint: 0xcccccc,
alpha: 0.18,
width: 200,
height: 200
});
game.addChild(gridSquare);
game.gridSquares.push(gridSquare);
}
}
// Place cubes for this level
var levelCubes = LEVELS[idx];
for (var i = 0; i < levelCubes.length; ++i) {
var c = levelCubes[i];
var cube = new Cube();
cube.gridX = c.x;
cube.gridY = c.y;
cube.setDirection(c.dir);
var pos = gridToPos(c.x, c.y);
cube.x = pos.x;
cube.y = pos.y;
cubes[c.y][c.x] = cube;
cubeList.push(cube);
game.addChild(cube);
// Re-attach event listeners for interaction
cube.interactive = true;
cube.on('down', cube.down);
}
updateScore();
levelTxt.setText("Level " + (currentLevel + 1));
game.isAnimating = false;
}
// Prevent accidental drag
game.move = function (x, y, obj) {};
// No drag
game.down = function (x, y, obj) {};
game.up = function (x, y, obj) {};
// No per-tick logic needed
game.update = function () {};
// Check for saved game state on load and restore if present
// Clear save history
var saved = storage.slidecubes_save;
if (saved && typeof saved.currentLevel === "number" && saved.currentLevel >= 0 && saved.currentLevel < LEVELS.length) {
buildLevel(saved.currentLevel);
} else {
buildLevel(0); // Level 1 is index 0
}