Code edit (1 edits merged)
Please save this source code
User prompt
when i pass first level level 2 is do not interact with my input
User prompt
after changing level game is unplayable
User prompt
level 2 is unpassable
User prompt
level dont change after complete
User prompt
create 5 level
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'to')' in or related to this line: 'tw.to({' Line Number: 207 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'to')' in or related to this line: 'tween(cube).to({' Line Number: 206
User prompt
i want to move the cube which i tap with arrow direction
User prompt
objects dont move
User prompt
objects not move
User prompt
blue wont move
Code edit (1 edits merged)
Please save this source code
User prompt
Arrow Slide Grid
User prompt
i want to create game where cubes placed on grid and each cube has arrow to indicade which way can move if path is empty they can go if not they wont. if path empty cube slide all the way out of the screen. win state is clear all grids
User prompt
cubes move until out of screen and diseapper if all grid empty level complete
Initial prompt
i want to create game where cubes placed on grid and each cube has arrow to indicade which way can move if path is empty they can go if not they wont.
/**** * 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
}