User prompt
make the tile a little more vibrant ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
add rainbow color
User prompt
remove the color yellow and a rainbow
User prompt
make the color more vibrante ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
when you open the menu make it bigger
User prompt
give more color choices
User prompt
the background is not changing
User prompt
make a menu button to change the background
User prompt
remove the bug in the tutorial
User prompt
only solve the first row
User prompt
there is a bug in the tutorial
User prompt
there is a bug
User prompt
there is a bug
User prompt
make the tutorial move the block until it is complete in the first level ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
there is a bug when the tutorial move the block in the first level ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the tutorial move the block step by step ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
make the got it button a little bigger
User prompt
there is a bug the tutorial button does not work
User prompt
make the tutorial button work
User prompt
make the tutorial button smaller
User prompt
put the the welcome to puzzle it button in the middle and make it small
User prompt
make a tutorial in the first level
User prompt
when level compele show new round button
User prompt
move the moves: block to the up left
User prompt
add a remix button t remix the block
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // PuzzleTile: Represents a single tile in the puzzle grid. var PuzzleTile = Container.expand(function () { var self = Container.call(this); // Properties self.gridX = 0; // grid position x self.gridY = 0; // grid position y self.correctX = 0; // correct grid position x self.correctY = 0; // correct grid position y self.tileIndex = 0; // index in the tile array self.isEmpty = false; // is this the empty tile? // The tile's visual var tileAsset = self.attachAsset('tile', { anchorX: 0, anchorY: 0 }); // For MVP, we color each tile differently for visual distinction self.setColor = function (color) { tileAsset.color = color; // Use tween to smoothly animate the tint change for more vibrant effect tween(tileAsset, { tint: color }, { duration: 300, easing: tween.easeOut }); }; // Set the label (number) for the tile self.setLabel = function (label) { if (self.labelText) { self.labelText.setText(label); } else { var txt = new Text2(label + '', { size: 120, fill: 0x222222 }); txt.anchor.set(0.5, 0.5); txt.x = tileAsset.width / 2; txt.y = tileAsset.height / 2; self.addChild(txt); self.labelText = txt; } }; // Hide label for empty tile self.hideLabel = function () { if (self.labelText) { self.labelText.visible = false; } }; // Show label self.showLabel = function () { if (self.labelText) { self.labelText.visible = true; } }; // Animate to a new position self.moveTo = function (x, y, duration) { tween(self, { x: x, y: y }, { duration: duration || 200, easing: tween.cubicOut }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222222 }); /**** * Game Code ****/ // In the future, this can be replaced with a real image or a procedurally generated pattern. // For MVP, we use a colored box as a placeholder for each tile, with a random color per game. // We'll use a single image asset for the puzzle, which will be randomly generated each game. // --- Puzzle Settings --- var gridSize = 4; // 4x4 grid (15-puzzle style) var tileSize = 400; // px, will be scaled to fit screen var tileSpacing = 12; // px gap between tiles var puzzleOffsetX = 0; var puzzleOffsetY = 0; var puzzleWidth = gridSize * tileSize + (gridSize - 1) * tileSpacing; var puzzleHeight = gridSize * tileSize + (gridSize - 1) * tileSpacing; // --- State --- var tiles = []; // 2D array [y][x] of PuzzleTile var tileList = []; // flat array of all PuzzleTile var emptyTile = null; // reference to the empty tile var moveCount = 0; var startTime = 0; var timerInterval = null; var isSolved = false; // --- UI --- var moveText = new Text2('Moves: 0', { size: 90, fill: 0xFFFFFF }); moveText.anchor.set(0, 0); // Anchor to top-left for easier positioning LK.gui.topLeft.addChild(moveText); // Add to topLeft GUI container var timeText = new Text2('Time: 0s', { size: 90, fill: 0xFFFFFF }); timeText.anchor.set(0.5, 0); LK.gui.top.addChild(timeText); // Keep timeText in the top-center // Position UI moveText.x = 20; // Small margin from the left edge moveText.y = 120; // Position below the platform menu icon area timeText.x = LK.gui.top.width / 2; // Center timeText timeText.y = 20; // --- Remix Button --- var remixBtn = new Text2('Remix', { size: 90, fill: 0xFFD700 }); remixBtn.anchor.set(0.5, 0); remixBtn.x = LK.gui.top.width / 2; remixBtn.y = 120; remixBtn.interactive = true; remixBtn.buttonMode = true; remixBtn.down = function (x, y, obj) { if (isSolved) return; shufflePuzzle(); moveCount = 0; startTime = Date.now(); updateUI(); }; LK.gui.top.addChild(remixBtn); // --- New Round Button --- var newRoundBtn = new Text2('New Round', { size: 90, fill: 0x4CAF50 // A nice green color for the new round button }); newRoundBtn.anchor.set(0.5, 0); newRoundBtn.x = LK.gui.top.width / 2; newRoundBtn.y = remixBtn.y + remixBtn.height + 30; // Position below the Remix button with some padding newRoundBtn.interactive = true; newRoundBtn.buttonMode = true; newRoundBtn.visible = false; // Initially hidden newRoundBtn.down = function (x, y, obj) { createPuzzle(); // This will re-initialize the game, hide this button, and reset isSolved }; LK.gui.top.addChild(newRoundBtn); // --- Background Menu Button --- var bgMenuBtn = new Text2('BG', { size: 60, fill: 0xFFFFFF }); bgMenuBtn.anchor.set(1, 0); bgMenuBtn.x = LK.gui.topRight.width - 20; bgMenuBtn.y = 20; bgMenuBtn.interactive = true; bgMenuBtn.buttonMode = true; bgMenuBtn.down = function (x, y, obj) { showBackgroundMenu(); }; LK.gui.topRight.addChild(bgMenuBtn); // --- Background Selection Variables --- var backgroundMenu = null; var backgroundColors = [0x222222, // Dark gray (default) 0x00FF00, // Bright green 0x0080FF, // Bright blue 0xFF00FF, // Bright magenta 0xFF0040, // Bright red 0xFF8000, // Bright orange 0x8000FF, // Bright purple 'rainbow' // Rainbow option ]; var currentBgIndex = 0; // --- Rainbow Background Variables --- var rainbowInterval = null; var rainbowHue = 0; // --- Helper Functions --- // Generate a random color palette for the puzzle function generateColorPalette(n) { var colors = []; var baseHue = Math.floor(Math.random() * 360); for (var i = 0; i < n; i++) { // HSL to RGB conversion with more vibrant saturation and lightness var hue = (baseHue + i * (360 / n)) % 360; var rgb = hslToRgb(hue / 360, 0.9, 0.7); // Increased saturation to 0.9 and lightness to 0.7 var color = rgb[0] << 16 | rgb[1] << 8 | rgb[2]; colors.push(color); } return colors; } // HSL to RGB helper function hslToRgb(h, s, l) { var r, g, b; if (s == 0) { r = g = b = l; } else { var hue2rgb = function hue2rgb(p, q, t) { if (t < 0) t += 1; if (t > 1) t -= 1; if (t < 1 / 6) return p + (q - p) * 6 * t; if (t < 1 / 2) return q; if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; return p; }; var q = l < 0.5 ? l * (1 + s) : l + s - l * s; var p = 2 * l - q; r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1 / 3); } return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; } // Shuffle an array in-place function shuffleArray(arr) { for (var i = arr.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } } // Check if the puzzle is solved function checkSolved() { for (var y = 0; y < gridSize; y++) { for (var x = 0; x < gridSize; x++) { var tile = tiles[y][x]; if (tile.gridX !== tile.correctX || tile.gridY !== tile.correctY) { return false; } } } return true; } // Update move and time UI function updateUI() { moveText.setText('Moves: ' + moveCount); var elapsed = Math.floor((Date.now() - startTime) / 1000); timeText.setText('Time: ' + elapsed + 's'); } // --- Puzzle Generation --- function createPuzzle() { if (typeof newRoundBtn !== 'undefined' && newRoundBtn) { newRoundBtn.visible = false; } if (typeof hideTutorial === 'function') { hideTutorial(); } // Remove old tiles for (var i = 0; i < tileList.length; i++) { tileList[i].destroy(); } tiles = []; tileList = []; emptyTile = null; isSolved = false; moveCount = 0; updateUI(); // Generate color palette var numTiles = gridSize * gridSize; var colors = generateColorPalette(numTiles - 1); // Calculate tile size to fit screen var maxWidth = 2048 - 200; var maxHeight = 2732 - 400; tileSize = Math.floor(Math.min((maxWidth - (gridSize - 1) * tileSpacing) / gridSize, (maxHeight - (gridSize - 1) * tileSpacing) / gridSize)); puzzleWidth = gridSize * tileSize + (gridSize - 1) * tileSpacing; puzzleHeight = gridSize * tileSize + (gridSize - 1) * tileSpacing; puzzleOffsetX = Math.floor((2048 - puzzleWidth) / 2); puzzleOffsetY = Math.floor((2732 - puzzleHeight) / 2) + 80; // Create tiles in solved order var idx = 0; for (var y = 0; y < gridSize; y++) { tiles[y] = []; for (var x = 0; x < gridSize; x++) { var tile = new PuzzleTile(); tile.gridX = x; tile.gridY = y; tile.correctX = x; tile.correctY = y; tile.tileIndex = idx; tile.x = puzzleOffsetX + x * (tileSize + tileSpacing); tile.y = puzzleOffsetY + y * (tileSize + tileSpacing); tile.width = tileSize; tile.height = tileSize; tile.setColor(colors[idx] || 0x222222); tile.setLabel(idx + 1); tile.isEmpty = false; tileList.push(tile); tiles[y][x] = tile; game.addChild(tile); idx++; } } // Make last tile the empty tile var lastTile = tiles[gridSize - 1][gridSize - 1]; lastTile.isEmpty = true; lastTile.setColor(0x222222); lastTile.hideLabel(); emptyTile = lastTile; // Shuffle tiles shufflePuzzle(); // Start timer startTime = Date.now(); if (timerInterval) LK.clearInterval(timerInterval); timerInterval = LK.setInterval(updateUI, 500); } // Shuffle the puzzle by simulating random valid moves function shufflePuzzle() { var moves = [[0, 1], [1, 0], [0, -1], [-1, 0]]; var prevX = emptyTile.gridX, prevY = emptyTile.gridY; var shuffleCount = 200 + Math.floor(Math.random() * 100); for (var i = 0; i < shuffleCount; i++) { var possible = []; for (var d = 0; d < moves.length; d++) { var nx = emptyTile.gridX + moves[d][0]; var ny = emptyTile.gridY + moves[d][1]; if (nx >= 0 && nx < gridSize && ny >= 0 && ny < gridSize) { if (!(nx === prevX && ny === prevY)) { possible.push([nx, ny]); } } } if (possible.length === 0) continue; var pick = possible[Math.floor(Math.random() * possible.length)]; var tile = tiles[pick[1]][pick[0]]; swapWithEmpty(tile, false); prevX = emptyTile.gridX; prevY = emptyTile.gridY; } // After shuffling, update all tile positions visually for (var y = 0; y < gridSize; y++) { for (var x = 0; x < gridSize; x++) { var tile = tiles[y][x]; tile.x = puzzleOffsetX + x * (tileSize + tileSpacing); tile.y = puzzleOffsetY + y * (tileSize + tileSpacing); tile.gridX = x; tile.gridY = y; } } } // Swap a tile with the empty tile (if adjacent) function swapWithEmpty(tile, animate) { if (tile.isEmpty) return false; var dx = Math.abs(tile.gridX - emptyTile.gridX); var dy = Math.abs(tile.gridY - emptyTile.gridY); if (dx === 1 && dy === 0 || dx === 0 && dy === 1) { // Swap in tiles array var tx = tile.gridX, ty = tile.gridY; var ex = emptyTile.gridX, ey = emptyTile.gridY; tiles[ty][tx] = emptyTile; tiles[ey][ex] = tile; // Swap grid positions var tmpX = tile.gridX, tmpY = tile.gridY; tile.gridX = emptyTile.gridX; tile.gridY = emptyTile.gridY; emptyTile.gridX = tmpX; emptyTile.gridY = tmpY; // Animate movement var tileTargetX = puzzleOffsetX + tile.gridX * (tileSize + tileSpacing); var tileTargetY = puzzleOffsetY + tile.gridY * (tileSize + tileSpacing); var emptyTargetX = puzzleOffsetX + emptyTile.gridX * (tileSize + tileSpacing); var emptyTargetY = puzzleOffsetY + emptyTile.gridY * (tileSize + tileSpacing); if (animate !== false) { tile.moveTo(tileTargetX, tileTargetY, 120); emptyTile.moveTo(emptyTargetX, emptyTargetY, 120); } else { tile.x = tileTargetX; tile.y = tileTargetY; emptyTile.x = emptyTargetX; emptyTile.y = emptyTargetY; } return true; } return false; } // --- Input Handling --- // Find which tile was pressed function getTileAtPos(x, y) { for (var i = 0; i < tileList.length; i++) { var tile = tileList[i]; if (tile.isEmpty) continue; var tx = tile.x, ty = tile.y; var tw = tile.width, th = tile.height; if (x >= tx && x <= tx + tw && y >= ty && y <= ty + th) { return tile; } } return null; } // Handle tap/click on the puzzle game.down = function (x, y, obj) { if (isSolved) return; var tile = getTileAtPos(x, y); if (!tile) return; var moved = swapWithEmpty(tile, true); if (moved) { moveCount++; updateUI(); if (checkSolved()) { isSolved = true; updateUI(); LK.effects.flashScreen(0x44ff44, 800); // Instead of showing YouWin screen, show the New Round button if (typeof newRoundBtn !== 'undefined' && newRoundBtn) { newRoundBtn.visible = true; } // LK.setTimeout(function () { // Original YouWin call removed // LK.showYouWin(); // }, 900); } } }; // --- Game Update --- game.update = function () { // No per-frame logic needed for MVP }; // --- Tutorial Overlay --- var tutorialOverlay = null; var tutorialStep = 0; var tutorialActive = false; // Show tutorial overlay for the first level function showTutorial() { tutorialActive = true; tutorialStep = 0; if (tutorialOverlay) { tutorialOverlay.destroy(); tutorialOverlay = null; } tutorialOverlay = new Container(); var bg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 20, x: 2048 / 2, y: 2732 / 2 }); bg.alpha = 0.7; tutorialOverlay.addChild(bg); var tutText = new Text2("Welcome to Puzzle It!\n\nWatch how to move the tiles...", { size: 100, fill: 0xffffff }); tutText.anchor.set(0.5, 0.5); tutText.x = 2048 / 2; tutText.y = 2732 / 2 - 200; tutorialOverlay.addChild(tutText); var tutBtn = new Text2("Got it!", { size: 80, fill: 0x4CAF50 }); tutBtn.anchor.set(0.5, 0.5); tutBtn.x = 2048 / 2; tutBtn.y = 2732 / 2 + 300; tutBtn.interactive = true; tutBtn.buttonMode = true; tutBtn.visible = false; // Hide button initially tutorialOverlay.addChild(tutBtn); // Add the tutorial overlay to the game directly instead of LK.gui.center game.addChild(tutorialOverlay); // Set up the button's click handler after it's added to the display tree tutBtn.down = function (x, y, obj) { hideTutorial(); }; // Start the step-by-step tutorial startTutorialSteps(tutText, tutBtn); } // Start step-by-step tutorial movements function startTutorialSteps(tutText, tutBtn) { var stepDelay = 2000; // 2 seconds between steps var moveDelay = 1000; // 1 second to show movement var steps = [{ text: "Step 1: Move tile 15 up...", tileToMove: function tileToMove() { // Find tile with number 15 for (var i = 0; i < tileList.length; i++) { if (tileList[i].labelText && tileList[i].labelText.text === "15") { return tileList[i]; } } return null; } }, { text: "Step 2: Move tile 14 right...", tileToMove: function tileToMove() { // Find tile with number 14 for (var i = 0; i < tileList.length; i++) { if (tileList[i].labelText && tileList[i].labelText.text === "14") { return tileList[i]; } } return null; } }, { text: "Step 3: Move tile 11 down...", tileToMove: function tileToMove() { // Find tile with number 11 for (var i = 0; i < tileList.length; i++) { if (tileList[i].labelText && tileList[i].labelText.text === "11") { return tileList[i]; } } return null; } }]; var currentStep = 0; function performNextStep() { if (currentStep >= steps.length) { // Tutorial complete tutText.setText("Great! Now you try.\n\nTap a tile next to the empty space to move it.\n\nPut the numbers in order to win."); tutBtn.visible = true; return; } var step = steps[currentStep]; tutText.setText(step.text); // Wait a moment, then perform the move LK.setTimeout(function () { var tile = step.tileToMove(); if (tile && swapWithEmpty(tile, true)) { // Move was successful, wait for animation then continue LK.setTimeout(function () { currentStep++; performNextStep(); }, moveDelay); } else { // Move failed, skip to next step currentStep++; performNextStep(); } }, stepDelay); } // Start the tutorial steps performNextStep(); } // Hide tutorial overlay function hideTutorial() { tutorialActive = false; if (tutorialOverlay) { game.removeChild(tutorialOverlay); tutorialOverlay.destroy(); tutorialOverlay = null; } } // Show background color selection menu function showBackgroundMenu() { if (backgroundMenu) { hideBackgroundMenu(); return; } backgroundMenu = new Container(); // Semi-transparent background var menuBg = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 12, scaleY: 8, x: 2048 / 2, y: 2732 / 2 }); menuBg.alpha = 0.9; menuBg.tint = 0x000000; backgroundMenu.addChild(menuBg); // Title var titleText = new Text2("Choose Background", { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 2732 / 2 - 300; backgroundMenu.addChild(titleText); // Color options var colorsPerRow = 4; var colorSize = 120; var colorSpacing = 40; var startX = 2048 / 2 - (colorsPerRow * colorSize + (colorsPerRow - 1) * colorSpacing) / 2 + colorSize / 2; var startY = 2732 / 2 - 100; for (var i = 0; i < backgroundColors.length; i++) { var row = Math.floor(i / colorsPerRow); var col = i % colorsPerRow; var colorBtn = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: colorSize / 100, scaleY: colorSize / 100, x: startX + col * (colorSize + colorSpacing), y: startY + row * (colorSize + colorSpacing) }); if (backgroundColors[i] === 'rainbow') { // Create a rainbow gradient effect for the rainbow button colorBtn.tint = 0xFF0000; // Start with red, will be animated // Add a visual indicator that this is the rainbow option var rainbowText = new Text2("🌈", { size: 60, fill: 0xFFFFFF }); rainbowText.anchor.set(0.5, 0.5); rainbowText.x = 0; rainbowText.y = 0; colorBtn.addChild(rainbowText); } else { colorBtn.tint = backgroundColors[i]; } colorBtn.interactive = true; colorBtn.buttonMode = true; colorBtn.colorIndex = i; // Add selection indicator for current background if (i === currentBgIndex) { var indicator = LK.getAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: (colorSize + 20) / 100, scaleY: (colorSize + 20) / 100, x: 0, y: 0 }); indicator.tint = 0xFFD700; indicator.alpha = 0.8; colorBtn.addChild(indicator); } (function (colorIndex) { colorBtn.down = function (x, y, obj) { currentBgIndex = colorIndex; if (backgroundColors[colorIndex] === 'rainbow') { startRainbowBackground(); } else { stopRainbowBackground(); game.setBackgroundColor(backgroundColors[colorIndex]); } hideBackgroundMenu(); }; })(i); backgroundMenu.addChild(colorBtn); } // Close button var closeBtn = new Text2("Close", { size: 70, fill: 0xFF4444 }); closeBtn.anchor.set(0.5, 0.5); closeBtn.x = 2048 / 2; closeBtn.y = 2732 / 2 + 250; closeBtn.interactive = true; closeBtn.buttonMode = true; closeBtn.down = function (x, y, obj) { hideBackgroundMenu(); }; backgroundMenu.addChild(closeBtn); game.addChild(backgroundMenu); } // Hide background selection menu function hideBackgroundMenu() { if (backgroundMenu) { game.removeChild(backgroundMenu); backgroundMenu.destroy(); backgroundMenu = null; } } // Start rainbow background animation function startRainbowBackground() { stopRainbowBackground(); // Stop any existing rainbow rainbowInterval = LK.setInterval(function () { rainbowHue = (rainbowHue + 2) % 360; // Increment hue var rgb = hslToRgb(rainbowHue / 360, 0.8, 0.5); // High saturation, medium lightness var color = rgb[0] << 16 | rgb[1] << 8 | rgb[2]; game.setBackgroundColor(color); }, 50); // Update every 50ms for smooth animation } // Stop rainbow background animation function stopRainbowBackground() { if (rainbowInterval) { LK.clearInterval(rainbowInterval); rainbowInterval = null; } } // --- Start Game --- createPuzzle(); ; // Show tutorial only for the first level (first time game is loaded) showTutorial(); // Block input while tutorial is active var origGameDown = game.down; game.down = function (x, y, obj) { if (tutorialActive) return; origGameDown(x, y, obj); };
===================================================================
--- original.js
+++ change.js
@@ -23,9 +23,15 @@
});
// For MVP, we color each tile differently for visual distinction
self.setColor = function (color) {
tileAsset.color = color;
- tileAsset.tint = color;
+ // Use tween to smoothly animate the tint change for more vibrant effect
+ tween(tileAsset, {
+ tint: color
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
};
// Set the label (number) for the tile
self.setLabel = function (label) {
if (self.labelText) {
@@ -188,11 +194,11 @@
function generateColorPalette(n) {
var colors = [];
var baseHue = Math.floor(Math.random() * 360);
for (var i = 0; i < n; i++) {
- // HSL to RGB conversion
+ // HSL to RGB conversion with more vibrant saturation and lightness
var hue = (baseHue + i * (360 / n)) % 360;
- var rgb = hslToRgb(hue / 360, 0.6, 0.6);
+ var rgb = hslToRgb(hue / 360, 0.9, 0.7); // Increased saturation to 0.9 and lightness to 0.7
var color = rgb[0] << 16 | rgb[1] << 8 | rgb[2];
colors.push(color);
}
return colors;