Code edit (1 edits merged)
Please save this source code
User prompt
add a confetti particle to level complete
User prompt
remove last change
User prompt
add a level complete button when ni cube left
Code edit (2 edits merged)
Please save this source code
User prompt
after first click close tap to play
Code edit (7 edits merged)
Please save this source code
User prompt
add a text say tap to play
User prompt
change tween duration to cell distance to end โช๐ก Consider importing and using the following plugins: @upit/tween.v1
User prompt
add a click sound to object click
User prompt
change fonts to lilita one
Code edit (3 edits merged)
Please save this source code
User prompt
add a reference for background image
User prompt
add a background image
Code edit (1 edits merged)
Please save this source code
User prompt
create image for each grid not single
/**** * 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 }
===================================================================
--- original.js
+++ change.js
@@ -285,18 +285,8 @@
}
}
if (left === 0) {
// Show confetti particle effect for level complete
- if (typeof LK.effects !== "undefined" && typeof LK.effects.confetti === "function") {
- LK.effects.confetti({
- x: 2048 / 2,
- y: 2732 / 2,
- count: 80,
- spread: 80,
- duration: 1200
- });
- }
- // Save current level to storage before showing you win
storage.slidecubes_save = {
currentLevel: currentLevel + 1
};
if (currentLevel < LEVELS.length - 1) {