User prompt
make the create account buttton work and when done signing up it saves your data for your account ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
remove the create account text
User prompt
now add the asset for the create account button to the button
User prompt
make an asset for the create account button
User prompt
for some reason when i click on password field it types into the enter name field fix it
User prompt
under the enter your name field make a password one and under that make a button thats says create account
User prompt
if a player cant get a match in 5 seconds then they should see bouncing gems and it should be a hint how u could match do that for me ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
still good job u reduced but its still not working sometimes please fix
User prompt
sometimes when i move somewhere i can match with gems it doesnt work sometimes fix it please
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Gem = Container.expand(function (type) { var self = Container.call(this); self.gemType = type; self.gridX = 0; self.gridY = 0; self.isAnimating = false; self.isScaling = false; var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange', 'gem_cyan', 'gem_pink']; var gemGraphics = self.attachAsset(gemAssets[type], { anchorX: 0.5, anchorY: 0.5, scaleX: CELL_SIZE / 256, scaleY: CELL_SIZE / 256 }); self.setGridPosition = function (gridX, gridY) { self.gridX = gridX; self.gridY = gridY; self.x = boardStartX + gridX * CELL_SIZE + CELL_SIZE / 2; self.y = boardStartY + gridY * CELL_SIZE + CELL_SIZE / 2; }; self.animateToPosition = function (targetX, targetY, duration, onComplete) { if (duration === undefined) duration = 300; self.isAnimating = true; tween(self, { x: targetX, y: targetY }, { duration: duration, easing: tween.easeOut, onFinish: function onFinish() { self.isAnimating = false; if (onComplete) onComplete(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x8B4513 // Brown background }); /**** * Game Code ****/ // Gold yellow // Deep pink // Medium slate blue var GAME_STATE_HOME = 0; var GAME_STATE_PLAYING = 1; var GAME_STATE_PAUSED = 2; var currentGameState = GAME_STATE_HOME; // Pause menu elements var pauseMenuContainer = null; var pauseMenuBg = null; var volumeButton = null; var exitButton = null; var resumeButton = null; var volumeEnabled = storage.volumeEnabled !== undefined ? storage.volumeEnabled : true; var BOARD_SIZE = 8; // Smaller board for kids - easier to see patterns var CELL_SIZE = Math.floor(Math.min(2048, 2732 - 500) / BOARD_SIZE * 0.95); // Bigger gems, leave more space for UI var BOARD_TOTAL_SIZE = BOARD_SIZE * CELL_SIZE; var boardStartX = (2048 - BOARD_TOTAL_SIZE) / 2; var boardStartY = (2732 - BOARD_TOTAL_SIZE) / 2 + 100; // Offset for top UI var board = []; var gems = []; var selectedGem = null; var isProcessingMatches = false; var isDragging = false; var dragStartX = 0; var dragStartY = 0; var score = 0; // Home screen elements var homeContainer = null; var playButton = null; var titleText = null; var textInputField = null; var textInputBorder = null; var textInputText = null; var inputText = ''; var keyboardContainer = null; var keyboardVisible = false; var keyboardKeys = []; var keyboardLayout = [['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'], ['Z', 'X', 'C', 'V', 'B', 'N', 'M']]; function createPauseMenu() { pauseMenuContainer = new Container(); game.addChild(pauseMenuContainer); // Create semi-transparent background pauseMenuBg = pauseMenuContainer.attachAsset('pauseMenuBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); // Pause menu title var pauseTitle = new Text2('GAME PAUSED', { size: 80, fill: 0xFFFFFF }); pauseTitle.anchor.set(0.5, 0.5); pauseTitle.x = 2048 / 2; pauseTitle.y = 2732 / 2 - 200; pauseMenuContainer.addChild(pauseTitle); // Resume button resumeButton = pauseMenuContainer.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 100 }); var resumeText = new Text2('RESUME GAME', { size: 50, fill: 0xFFFFFF }); resumeText.anchor.set(0.5, 0.5); resumeText.x = 2048 / 2; resumeText.y = 2732 / 2 - 100; pauseMenuContainer.addChild(resumeText); // Volume toggle button volumeButton = pauseMenuContainer.attachAsset('volumeToggle', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); var volumeText = new Text2(volumeEnabled ? 'VOLUME: ON' : 'VOLUME: OFF', { size: 40, fill: 0xFFFFFF }); volumeText.anchor.set(0.5, 0.5); volumeText.x = 2048 / 2; volumeText.y = 2732 / 2; pauseMenuContainer.addChild(volumeText); // Exit button exitButton = pauseMenuContainer.attachAsset('menuButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 + 100 }); var exitText = new Text2('EXIT TO MENU', { size: 50, fill: 0xFFFFFF }); exitText.anchor.set(0.5, 0.5); exitText.x = 2048 / 2; exitText.y = 2732 / 2 + 100; pauseMenuContainer.addChild(exitText); // Store reference to volume text for updates pauseMenuContainer.volumeText = volumeText; } function createCustomKeyboard() { if (keyboardContainer) return; // Already exists keyboardContainer = new Container(); game.addChild(keyboardContainer); // Create keyboard background var keyboardBg = keyboardContainer.attachAsset('keyboardBg', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: 2732 }); // Clear previous keys keyboardKeys = []; var startY = 2732 - 750; // Start position for keys var keySpacing = 150; var rowSpacing = 110; // Create letter keys for (var row = 0; row < keyboardLayout.length; row++) { var rowKeys = keyboardLayout[row]; var rowWidth = rowKeys.length * keySpacing; var startX = (2048 - rowWidth) / 2 + keySpacing / 2; for (var col = 0; col < rowKeys.length; col++) { var letter = rowKeys[col]; var keyX = startX + col * keySpacing; var keyY = startY + row * rowSpacing; var key = keyboardContainer.attachAsset('keyboardKey', { anchorX: 0.5, anchorY: 0.5, x: keyX, y: keyY }); var keyText = new Text2(letter, { size: 45, fill: 0xFFFFFF }); keyText.anchor.set(0.5, 0.5); keyText.x = keyX; keyText.y = keyY; keyboardContainer.addChild(keyText); keyboardKeys.push({ key: key, text: keyText, letter: letter, x: keyX, y: keyY, width: 140, height: 100 }); } } // Create space key var spaceKey = keyboardContainer.attachAsset('keyboardSpaceKey', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: startY + 3 * rowSpacing }); var spaceText = new Text2('SPACE', { size: 40, fill: 0xFFFFFF }); spaceText.anchor.set(0.5, 0.5); spaceText.x = 2048 / 2; spaceText.y = startY + 3 * rowSpacing; keyboardContainer.addChild(spaceText); keyboardKeys.push({ key: spaceKey, text: spaceText, letter: ' ', x: 2048 / 2, y: startY + 3 * rowSpacing, width: 400, height: 100 }); // Create backspace key var backspaceKey = keyboardContainer.attachAsset('keyboardBackspaceKey', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 300, y: startY + 3 * rowSpacing }); var backspaceText = new Text2('←', { size: 50, fill: 0xFFFFFF }); backspaceText.anchor.set(0.5, 0.5); backspaceText.x = 2048 / 2 - 300; backspaceText.y = startY + 3 * rowSpacing; keyboardContainer.addChild(backspaceText); keyboardKeys.push({ key: backspaceKey, text: backspaceText, letter: 'BACKSPACE', x: 2048 / 2 - 300, y: startY + 3 * rowSpacing, width: 200, height: 100 }); // Create done key var doneKey = keyboardContainer.attachAsset('keyboardDoneKey', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 300, y: startY + 3 * rowSpacing }); var doneText = new Text2('DONE', { size: 40, fill: 0xFFFFFF }); doneText.anchor.set(0.5, 0.5); doneText.x = 2048 / 2 + 300; doneText.y = startY + 3 * rowSpacing; keyboardContainer.addChild(doneText); keyboardKeys.push({ key: doneKey, text: doneText, letter: 'DONE', x: 2048 / 2 + 300, y: startY + 3 * rowSpacing, width: 200, height: 100 }); // Animate keyboard sliding up keyboardContainer.y = 800; tween(keyboardContainer, { y: 0 }, { duration: 300, easing: tween.easeOut }); keyboardVisible = true; } function hideCustomKeyboard() { if (!keyboardContainer) return; tween(keyboardContainer, { y: 800 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { if (keyboardContainer) { keyboardContainer.destroy(); keyboardContainer = null; keyboardKeys = []; keyboardVisible = false; } } }); } function handleKeyboardInput(letter) { if (letter === 'BACKSPACE') { if (inputText.length > 0) { inputText = inputText.slice(0, -1); } } else if (letter === 'DONE') { hideCustomKeyboard(); return; } else if (letter === ' ') { if (inputText.length < 20) { inputText += ' '; } } else { if (inputText.length < 20) { inputText += letter; } } // Update text display if (textInputText) { if (inputText.length === 0) { textInputText.setText('Enter your name...'); textInputText.fill = 0x888888; } else { textInputText.setText(inputText); textInputText.fill = 0x000000; } } } function createHomeScreen() { homeContainer = new Container(); game.addChild(homeContainer); // Create title using gemMatchTitle asset titleText = homeContainer.attachAsset('gemMatchTitle', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 800 }); // Create play button using playButton asset playButton = homeContainer.attachAsset('playButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1400 }); // Play button text removed per request // Create text input field under play button textInputBorder = homeContainer.attachAsset('textInputBorder', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1600 }); textInputField = homeContainer.attachAsset('textInputField', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1600 }); // Create placeholder text for input field textInputText = new Text2('Enter your name...', { size: 50, fill: 0x888888 }); textInputText.anchor.set(0.5, 0.5); textInputText.x = 2048 / 2; textInputText.y = 1600; homeContainer.addChild(textInputText); // Add bouncy animation to play button tween(playButton, { scaleX: 1.05, scaleY: 1.05 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(playButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { // Restart the bounce animation if (currentGameState === GAME_STATE_HOME && playButton) { tween(playButton, { scaleX: 1.05, scaleY: 1.05 }, { duration: 1000, easing: tween.easeInOut }); } } }); } }); // Add super vibrant rainbow color animation with bounce effect var rainbowColors = [0xFF0080, 0x00FF80, 0x8000FF, 0xFF8000, 0x0080FF, 0xFF4080, 0x80FF00, 0xFF0040]; var colorIndex = 0; function animateTitle() { if (currentGameState === GAME_STATE_HOME && titleText && titleText.fill !== undefined) { // Color transition tween(titleText, { fill: rainbowColors[colorIndex] }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { colorIndex = (colorIndex + 1) % rainbowColors.length; LK.setTimeout(animateTitle, 100); } }); // Add bouncy scale animation if (titleText.scaleX !== undefined && titleText.scaleY !== undefined) { tween(titleText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { if (titleText && titleText.scaleX !== undefined && titleText.scaleY !== undefined) { tween(titleText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 300, easing: tween.easeIn }); } } }); } } } animateTitle(); } function startGame() { currentGameState = GAME_STATE_PLAYING; // Reset moves for new game movesRemaining = maxMoves; // Remove home screen if (homeContainer) { homeContainer.destroy(); homeContainer = null; playButton = null; titleText = null; } // Create game elements createGameElements(); initializeBoard(); } function createGameElements() { // Create board background var boardBackground = game.addChild(LK.getAsset('boardBg', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: boardStartY + BOARD_TOTAL_SIZE / 2, scaleX: BOARD_TOTAL_SIZE / 960, scaleY: BOARD_TOTAL_SIZE / 960 })); // Initialize score display with bright colors scoreTxt = new Text2('Score: 0', { size: 90, fill: 0xFF1493 // Bright pink text }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 80; // Add target score display targetTxt = new Text2('Target: ' + targetScore, { size: 70, fill: 0x32CD32 // Bright green text }); targetTxt.anchor.set(0.5, 0); LK.gui.top.addChild(targetTxt); targetTxt.y = 180; // Add encouraging message display messageTxt = new Text2('Match the colorful gems!', { size: 60, fill: 0xFFD700 // Golden yellow text }); messageTxt.anchor.set(0.5, 0); LK.gui.top.addChild(messageTxt); messageTxt.y = 250; // Add moves display next to target movesTxt = new Text2('Moves: ' + movesRemaining, { size: 70, fill: 0xFF4500 // Orange red text }); movesTxt.anchor.set(0, 0); LK.gui.top.addChild(movesTxt); movesTxt.x = targetTxt.x + targetTxt.width / 2 + 50; movesTxt.y = 180; // Create pause button below the game board pauseButton = game.addChild(LK.getAsset('pauseButton', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: boardStartY + BOARD_TOTAL_SIZE + 150 })); // Pause button text removed per request } // UI elements - declare globally but create in game var scoreTxt = null; var targetTxt = null; var messageTxt = null; var movesTxt = null; var pauseButton = null; var targetScore = 500; // Kid-friendly target var maxMoves = 20; // Limited moves for the game var movesRemaining = maxMoves; function initializeBoard() { // Create 2D array for board for (var y = 0; y < BOARD_SIZE; y++) { board[y] = []; gems[y] = []; for (var x = 0; x < BOARD_SIZE; x++) { var gemType = Math.floor(Math.random() * 8); var gem = new Gem(gemType); gem.setGridPosition(x, y); board[y][x] = gemType; gems[y][x] = gem; game.addChild(gem); } } // Remove initial matches removeInitialMatches(); } function removeInitialMatches() { var foundMatches = true; var iterations = 0; while (foundMatches && iterations < 10) { foundMatches = false; iterations++; for (var y = 0; y < BOARD_SIZE; y++) { for (var x = 0; x < BOARD_SIZE; x++) { if (hasMatchAt(x, y)) { var newType = Math.floor(Math.random() * 8); board[y][x] = newType; gems[y][x].gemType = newType; // Update gem graphics by recreating gems[y][x].destroy(); var newGem = new Gem(newType); newGem.setGridPosition(x, y); gems[y][x] = newGem; game.addChild(newGem); foundMatches = true; } } } } } function hasMatchAt(x, y) { if (board[y][x] === undefined || board[y][x] === -1) return false; var gemType = board[y][x]; // Check horizontal match var horizontalCount = 1; // Check left for (var i = x - 1; i >= 0 && board[y] && board[y][i] === gemType; i--) { horizontalCount++; } // Check right for (var i = x + 1; i < BOARD_SIZE && board[y] && board[y][i] === gemType; i++) { horizontalCount++; } // Check vertical match var verticalCount = 1; // Check up for (var i = y - 1; i >= 0 && board[i] && board[i][x] === gemType; i--) { verticalCount++; } // Check down for (var i = y + 1; i < BOARD_SIZE && board[i] && board[i][x] === gemType; i++) { verticalCount++; } return horizontalCount >= 3 || verticalCount >= 3; } function getGemAt(gameX, gameY) { var gridX = Math.floor((gameX - boardStartX) / CELL_SIZE); var gridY = Math.floor((gameY - boardStartY) / CELL_SIZE); if (gridX >= 0 && gridX < BOARD_SIZE && gridY >= 0 && gridY < BOARD_SIZE) { return gems[gridY][gridX]; } return null; } function isAdjacent(gem1, gem2) { var dx = Math.abs(gem1.gridX - gem2.gridX); var dy = Math.abs(gem1.gridY - gem2.gridY); return dx === 1 && dy === 0 || dx === 0 && dy === 1; } function swapGems(gem1, gem2) { if (!gem1 || !gem2 || gem1.isAnimating || gem2.isAnimating) return; // Store original positions and types var originalGem1X = gem1.gridX; var originalGem1Y = gem1.gridY; var originalGem2X = gem2.gridX; var originalGem2Y = gem2.gridY; var originalGem1Type = gem1.gemType; var originalGem2Type = gem2.gemType; // Calculate original visual positions var originalGem1PosX = boardStartX + originalGem1X * CELL_SIZE + CELL_SIZE / 2; var originalGem1PosY = boardStartY + originalGem1Y * CELL_SIZE + CELL_SIZE / 2; var originalGem2PosX = boardStartX + originalGem2X * CELL_SIZE + CELL_SIZE / 2; var originalGem2PosY = boardStartY + originalGem2Y * CELL_SIZE + CELL_SIZE / 2; // Temporarily update board and gem properties to test for matches board[originalGem1Y][originalGem1X] = originalGem2Type; board[originalGem2Y][originalGem2X] = originalGem1Type; gem1.gemType = originalGem2Type; gem2.gemType = originalGem1Type; // Check if this swap creates any matches var hasMatch = hasMatchAt(originalGem1X, originalGem1Y) || hasMatchAt(originalGem2X, originalGem2Y); if (hasMatch) { // Valid swap - complete the swap gem1.setGridPosition(originalGem2X, originalGem2Y); gem2.setGridPosition(originalGem1X, originalGem1Y); // Update gems array gems[originalGem1Y][originalGem1X] = gem2; gems[originalGem2Y][originalGem2X] = gem1; // Animate to swapped positions gem1.animateToPosition(originalGem2PosX, originalGem2PosY, 200); gem2.animateToPosition(originalGem1PosX, originalGem1PosY, 200, function () { if (volumeEnabled) { var swapSound = LK.getSound('swap'); if (swapSound) swapSound.play(); } // Decrement moves on successful swap movesRemaining--; if (movesTxt) { movesTxt.setText('Moves: ' + movesRemaining); // Color code the moves display if (movesRemaining <= 3) { movesTxt.fill = 0xFF0000; // Red - critical } else if (movesRemaining <= 5) { movesTxt.fill = 0xFF8C00; // Orange - warning } else { movesTxt.fill = 0xFF4500; // Orange red - normal } } checkForMatches(); }); } else { // Invalid swap - revert changes board[originalGem1Y][originalGem1X] = originalGem1Type; board[originalGem2Y][originalGem2X] = originalGem2Type; gem1.gemType = originalGem1Type; gem2.gemType = originalGem2Type; // Animate gems briefly toward each other then back var swapDistance = 30; var gem1SwipePosX = originalGem1PosX + (originalGem2PosX - originalGem1PosX) * 0.3; var gem1SwipePosY = originalGem1PosY + (originalGem2PosY - originalGem1PosY) * 0.3; var gem2SwipePosX = originalGem2PosX + (originalGem1PosX - originalGem2PosX) * 0.3; var gem2SwipePosY = originalGem2PosY + (originalGem1PosY - originalGem2PosY) * 0.3; // First animate toward each other gem1.animateToPosition(gem1SwipePosX, gem1SwipePosY, 150, function () { // Then animate back to original positions gem1.animateToPosition(originalGem1PosX, originalGem1PosY, 150); }); gem2.animateToPosition(gem2SwipePosX, gem2SwipePosY, 150, function () { // Then animate back to original positions gem2.animateToPosition(originalGem2PosX, originalGem2PosY, 150); if (volumeEnabled) { var invalidSound = LK.getSound('invalid_move'); if (invalidSound) invalidSound.play(); } }); } } function checkForMatches() { if (isProcessingMatches) return; var matchesFound = []; // Find all horizontal matches first for (var y = 0; y < BOARD_SIZE; y++) { for (var x = 0; x < BOARD_SIZE; x++) { if (board[y][x] === -1) continue; // Skip empty cells var gemType = board[y][x]; var horizontalCount = 1; var horizontalMatches = [{ x: x, y: y }]; // Check right for (var i = x + 1; i < BOARD_SIZE && board[y][i] === gemType; i++) { horizontalCount++; horizontalMatches.push({ x: i, y: y }); } if (horizontalCount >= 3) { // Add all horizontal matches, avoiding duplicates for (var i = 0; i < horizontalMatches.length; i++) { var match = horizontalMatches[i]; var alreadyFound = false; for (var j = 0; j < matchesFound.length; j++) { if (matchesFound[j].x === match.x && matchesFound[j].y === match.y) { alreadyFound = true; break; } } if (!alreadyFound) { matchesFound.push(match); } } } } } // Find all vertical matches for (var x = 0; x < BOARD_SIZE; x++) { for (var y = 0; y < BOARD_SIZE; y++) { if (board[y][x] === -1) continue; // Skip empty cells var gemType = board[y][x]; var verticalCount = 1; var verticalMatches = [{ x: x, y: y }]; // Check down for (var i = y + 1; i < BOARD_SIZE && board[i][x] === gemType; i++) { verticalCount++; verticalMatches.push({ x: x, y: i }); } if (verticalCount >= 3) { // Add all vertical matches, avoiding duplicates for (var i = 0; i < verticalMatches.length; i++) { var match = verticalMatches[i]; var alreadyFound = false; for (var j = 0; j < matchesFound.length; j++) { if (matchesFound[j].x === match.x && matchesFound[j].y === match.y) { alreadyFound = true; break; } } if (!alreadyFound) { matchesFound.push(match); } } } } } // Check for 2x2 square matches and add rows if found for (var y = 0; y < BOARD_SIZE - 1; y++) { for (var x = 0; x < BOARD_SIZE - 1; x++) { var squareMatches = checkSquareMatch(x, y); if (squareMatches.length === 4) { // Check if any of these squares are already in our matches var hasSquareMatch = false; for (var i = 0; i < squareMatches.length; i++) { for (var j = 0; j < matchesFound.length; j++) { if (squareMatches[i].x === matchesFound[j].x && squareMatches[i].y === matchesFound[j].y) { hasSquareMatch = true; break; } } if (hasSquareMatch) break; } if (hasSquareMatch) { // Add entire rows for square matches for (var rowY = y; rowY <= y + 1; rowY++) { for (var rowX = 0; rowX < BOARD_SIZE; rowX++) { var alreadyFound = false; for (var j = 0; j < matchesFound.length; j++) { if (matchesFound[j].x === rowX && matchesFound[j].y === rowY) { alreadyFound = true; break; } } if (!alreadyFound) { matchesFound.push({ x: rowX, y: rowY }); } } } } } } } if (matchesFound.length > 0) { isProcessingMatches = true; removeMatches(matchesFound); } else { // No matches found, check if moves are depleted if (movesRemaining <= 0) { messageTxt.setText('NO MORE MOVES!'); LK.effects.flashScreen(0xFF0000, 1000); // Red flash for game over LK.setTimeout(function () { LK.showGameOver(); }, 1500); } } } function checkSquareMatch(x, y) { if (x >= BOARD_SIZE - 1 || y >= BOARD_SIZE - 1) return []; var gemType = board[y][x]; // Check if all 4 positions in 2x2 square have same gem type if (board[y][x] === gemType && board[y][x + 1] === gemType && board[y + 1][x] === gemType && board[y + 1][x + 1] === gemType) { return [{ x: x, y: y }, { x: x + 1, y: y }, { x: x, y: y + 1 }, { x: x + 1, y: y + 1 }]; } return []; } function getRowsToRemove(matches) { var rowsToRemove = []; // Check if any 2x2 square matches exist for (var y = 0; y < BOARD_SIZE - 1; y++) { for (var x = 0; x < BOARD_SIZE - 1; x++) { var squareMatches = checkSquareMatch(x, y); if (squareMatches.length === 4) { // Check if this square is part of our current matches var isPartOfMatches = false; for (var i = 0; i < squareMatches.length; i++) { for (var j = 0; j < matches.length; j++) { if (squareMatches[i].x === matches[j].x && squareMatches[i].y === matches[j].y) { isPartOfMatches = true; break; } } if (isPartOfMatches) break; } if (isPartOfMatches) { // Add both rows to removal list if (rowsToRemove.indexOf(y) === -1) rowsToRemove.push(y); if (rowsToRemove.indexOf(y + 1) === -1) rowsToRemove.push(y + 1); } } } } return rowsToRemove; } function getMatchesAt(x, y) { if (board[y][x] === -1) return []; // Empty cell var gemType = board[y][x]; var allMatches = []; // Check horizontal matches var horizontalMatches = [{ x: x, y: y }]; // Check left for (var i = x - 1; i >= 0 && board[y][i] === gemType; i--) { horizontalMatches.push({ x: i, y: y }); } // Check right for (var i = x + 1; i < BOARD_SIZE && board[y][i] === gemType; i++) { horizontalMatches.push({ x: i, y: y }); } if (horizontalMatches.length >= 3) { for (var i = 0; i < horizontalMatches.length; i++) { allMatches.push(horizontalMatches[i]); } } // Check vertical matches var verticalMatches = [{ x: x, y: y }]; // Check up for (var i = y - 1; i >= 0 && board[i][x] === gemType; i--) { verticalMatches.push({ x: x, y: i }); } // Check down for (var i = y + 1; i < BOARD_SIZE && board[i][x] === gemType; i++) { verticalMatches.push({ x: x, y: i }); } if (verticalMatches.length >= 3) { // Add vertical matches, avoiding duplicates from horizontal for (var i = 0; i < verticalMatches.length; i++) { var vMatch = verticalMatches[i]; var alreadyExists = false; for (var j = 0; j < allMatches.length; j++) { if (allMatches[j].x === vMatch.x && allMatches[j].y === vMatch.y) { alreadyExists = true; break; } } if (!alreadyExists) { allMatches.push(vMatch); } } } return allMatches; } function removeMatches(matches) { // Check for 2x2 square matches and get rows to clear var rowsToRemove = getRowsToRemove(matches); var totalGemsToRemove = matches.length; // If we have a square match, add entire rows to removal if (rowsToRemove.length > 0) { var rowMatches = []; for (var i = 0; i < rowsToRemove.length; i++) { var rowY = rowsToRemove[i]; for (var x = 0; x < BOARD_SIZE; x++) { rowMatches.push({ x: x, y: rowY }); } } // Combine with original matches, avoiding duplicates for (var i = 0; i < rowMatches.length; i++) { var rowMatch = rowMatches[i]; var alreadyExists = false; for (var j = 0; j < matches.length; j++) { if (matches[j].x === rowMatch.x && matches[j].y === rowMatch.y) { alreadyExists = true; break; } } if (!alreadyExists) { matches.push(rowMatch); } } totalGemsToRemove = matches.length; } // Add score with celebration for big matches score += matches.length * 10; scoreTxt.setText('Score: ' + score); // Kid-friendly encouraging messages based on match size and square detection var encouragingMessages = ['Great job!', 'Awesome!', 'Fantastic!', 'Amazing!', 'Super cool!', 'You\'re doing great!', 'Keep going!', 'Brilliant!', 'Wonderful!']; if (rowsToRemove.length > 0) { messageTxt.setText('SQUARE POWER! ROW CLEARED!'); LK.effects.flashScreen(0x00FF00, 1000); // Bright green flash for square matches if (volumeEnabled) { var squareSound = LK.getSound('square_match'); if (squareSound) squareSound.play(); } } else if (matches.length >= 6) { messageTxt.setText('WOW! INCREDIBLE!'); LK.effects.flashScreen(0xFFD700, 800); // Extra long gold flash if (volumeEnabled) { var bigSound = LK.getSound('big_match'); if (bigSound) bigSound.play(); } } else if (matches.length >= 5) { messageTxt.setText('SUPER COMBO!'); LK.effects.flashScreen(0xFFD700, 500); // Gold flash for 5+ matches if (volumeEnabled) { var bigSound = LK.getSound('big_match'); if (bigSound) bigSound.play(); } } else if (matches.length >= 4) { messageTxt.setText('GREAT MATCH!'); LK.effects.flashScreen(0xFF69B4, 300); // Pink flash for 4+ matches if (volumeEnabled) { var bigSound = LK.getSound('big_match'); if (bigSound) bigSound.play(); } } else { var randomMessage = encouragingMessages[Math.floor(Math.random() * encouragingMessages.length)]; messageTxt.setText(randomMessage); if (volumeEnabled) { var matchSound = LK.getSound('match'); if (matchSound) matchSound.play(); } } // Update target display with progress var progress = Math.min(score / targetScore, 1.0); var progressPercent = Math.floor(progress * 100); targetTxt.setText('Target: ' + targetScore + ' (' + progressPercent + '%)'); // Encouraging messages based on progress if (progress >= 0.9) { targetTxt.fill = 0xFF6347; // Orange - almost there! } else if (progress >= 0.5) { targetTxt.fill = 0xFFD700; // Gold - halfway there! } else { targetTxt.fill = 0x32CD32; // Green - keep going! } // Check if target is reached if (score >= targetScore) { messageTxt.setText('🎉 YOU DID IT! 🎉'); LK.effects.flashScreen(0x00FF00, 1000); // Bright green celebration LK.showYouWin(); } // Flash and remove matched gems with rainbow colors var rainbowColors = [0xFF69B4, 0x00BFFF, 0x32CD32, 0xFFD700, 0xFF6347, 0x9370DB]; for (var i = 0; i < matches.length; i++) { var match = matches[i]; var gem = gems[match.y][match.x]; if (gem) { var flashColor = rainbowColors[i % rainbowColors.length]; LK.effects.flashObject(gem, flashColor, 300); tween(gem, { alpha: 0, scaleX: 1.5, // Make gems grow bigger before disappearing scaleY: 1.5 }, { duration: 300, easing: tween.easeOut, // Bouncy effect onFinish: function onFinish() { // Properly destroy the gem after animation if (gem && gem.destroy) { gem.destroy(); } } }); } board[match.y][match.x] = -1; // Mark as empty gems[match.y][match.x] = null; // Clear gem reference } // Wait for animation then drop gems LK.setTimeout(function () { dropGems(); }, 350); } function dropGems() { var moved = false; // Drop existing gems for (var x = 0; x < BOARD_SIZE; x++) { var writePos = BOARD_SIZE - 1; for (var y = BOARD_SIZE - 1; y >= 0; y--) { if (board[y][x] !== -1) { if (y !== writePos) { // Move gem down board[writePos][x] = board[y][x]; gems[writePos][x] = gems[y][x]; gems[writePos][x].setGridPosition(x, writePos); gems[writePos][x].animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + writePos * CELL_SIZE + CELL_SIZE / 2, 200); board[y][x] = -1; gems[y][x] = null; moved = true; } writePos--; } } } // Fill empty spaces with new gems - ensure we fill from top to bottom for (var x = 0; x < BOARD_SIZE; x++) { for (var y = 0; y < BOARD_SIZE; y++) { if (board[y][x] === -1) { var newType = Math.floor(Math.random() * 8); var newGem = new Gem(newType); newGem.setGridPosition(x, y); newGem.y = boardStartY - (BOARD_SIZE - y) * CELL_SIZE + CELL_SIZE / 2; // Start above board newGem.animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + y * CELL_SIZE + CELL_SIZE / 2, 400); board[y][x] = newType; gems[y][x] = newGem; game.addChild(newGem); moved = true; } } } // Double check - ensure no empty spaces remain by creating additional gems if needed for (var x = 0; x < BOARD_SIZE; x++) { for (var y = 0; y < BOARD_SIZE; y++) { if (!gems[y][x] || board[y][x] === -1) { var newType = Math.floor(Math.random() * 8); var newGem = new Gem(newType); newGem.setGridPosition(x, y); board[y][x] = newType; gems[y][x] = newGem; game.addChild(newGem); moved = true; } } } if (moved) { LK.setTimeout(function () { isProcessingMatches = false; checkForMatches(); // Check for cascade matches }, 450); } else { isProcessingMatches = false; } } game.down = function (x, y, obj) { if (currentGameState === GAME_STATE_HOME) { // Check if play button was clicked using coordinate bounds if (playButton) { var buttonLeft = playButton.x - playButton.width * playButton.scaleX / 2; var buttonRight = playButton.x + playButton.width * playButton.scaleX / 2; var buttonTop = playButton.y - playButton.height * playButton.scaleY / 2; var buttonBottom = playButton.y + playButton.height * playButton.scaleY / 2; if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { // Add click effect to play button tween(playButton, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(playButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { if (volumeEnabled) LK.getSound('button_click').play(); startGame(); } }); } }); } // Check if text input field was clicked if (textInputField) { var fieldLeft = textInputField.x - textInputField.width / 2; var fieldRight = textInputField.x + textInputField.width / 2; var fieldTop = textInputField.y - textInputField.height / 2; var fieldBottom = textInputField.y + textInputField.height / 2; if (x >= fieldLeft && x <= fieldRight && y >= fieldTop && y <= fieldBottom) { // Show custom keyboard if (volumeEnabled) LK.getSound('button_click').play(); // Add visual feedback tween(textInputField, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(textInputField, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { createCustomKeyboard(); } }); } }); return; } // Handle keyboard clicks if (keyboardVisible && keyboardContainer) { for (var i = 0; i < keyboardKeys.length; i++) { var keyData = keyboardKeys[i]; var keyLeft = keyData.x - keyData.width / 2; var keyRight = keyData.x + keyData.width / 2; var keyTop = keyData.y - keyData.height / 2; var keyBottom = keyData.y + keyData.height / 2; if (x >= keyLeft && x <= keyRight && y >= keyTop && y <= keyBottom) { // Key pressed - add visual feedback if (volumeEnabled) LK.getSound('button_click').play(); var originalKey = keyData.key; tween(originalKey, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(originalKey, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); } }); handleKeyboardInput(keyData.letter); return; } } } } } return; } if (currentGameState === GAME_STATE_PAUSED) { // Handle pause menu clicks if (resumeButton) { var buttonLeft = resumeButton.x - resumeButton.width / 2; var buttonRight = resumeButton.x + resumeButton.width / 2; var buttonTop = resumeButton.y - resumeButton.height / 2; var buttonBottom = resumeButton.y + resumeButton.height / 2; if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { // Resume game if (volumeEnabled) LK.getSound('button_click').play(); currentGameState = GAME_STATE_PLAYING; pauseMenuContainer.destroy(); pauseMenuContainer = null; return; } } if (volumeButton) { var buttonLeft = volumeButton.x - volumeButton.width / 2; var buttonRight = volumeButton.x + volumeButton.width / 2; var buttonTop = volumeButton.y - volumeButton.height / 2; var buttonBottom = volumeButton.y + volumeButton.height / 2; if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { // Toggle volume if (volumeEnabled) LK.getSound('button_click').play(); volumeEnabled = !volumeEnabled; storage.volumeEnabled = volumeEnabled; pauseMenuContainer.volumeText.setText(volumeEnabled ? 'VOLUME: ON' : 'VOLUME: OFF'); return; } } if (exitButton) { var buttonLeft = exitButton.x - exitButton.width / 2; var buttonRight = exitButton.x + exitButton.width / 2; var buttonTop = exitButton.y - exitButton.height / 2; var buttonBottom = exitButton.y + exitButton.height / 2; if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { // Exit to home screen if (volumeEnabled) LK.getSound('button_click').play(); currentGameState = GAME_STATE_HOME; // Clear all game elements game.removeChildren(); // Reset UI elements LK.gui.top.removeChildren(); scoreTxt = null; targetTxt = null; messageTxt = null; movesTxt = null; pauseButton = null; pauseMenuContainer = null; // Reset game variables board = []; gems = []; selectedGem = null; isProcessingMatches = false; isDragging = false; score = 0; // Show home screen createHomeScreen(); return; } } return; } if (currentGameState !== GAME_STATE_PLAYING || isProcessingMatches) return; // Check if pause button was clicked if (pauseButton) { var buttonLeft = pauseButton.x - pauseButton.width / 2; var buttonRight = pauseButton.x + pauseButton.width / 2; var buttonTop = pauseButton.y - pauseButton.height / 2; var buttonBottom = pauseButton.y + pauseButton.height / 2; if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { // Add click effect to pause button tween(pauseButton, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { tween(pauseButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut, onFinish: function onFinish() { // Show pause menu if (volumeEnabled) LK.getSound('button_click').play(); currentGameState = GAME_STATE_PAUSED; createPauseMenu(); } }); } }); return; } } selectedGem = getGemAt(x, y); if (selectedGem) { if (volumeEnabled) { var selectSound = LK.getSound('select'); if (selectSound) selectSound.play(); } isDragging = true; dragStartX = x; dragStartY = y; // Fun rainbow flash and bigger bounce effect for kids var rainbowColors = [0xFF69B4, 0x00BFFF, 0x32CD32, 0xFFD700, 0xFF6347, 0x9370DB]; var randomColor = rainbowColors[Math.floor(Math.random() * rainbowColors.length)]; LK.effects.flashObject(selectedGem, randomColor, 300); // Store reference to selected gem for use in callbacks var gemToAnimate = selectedGem; // Check if gem exists and has valid properties before starting tween, and prevent multiple scale animations if (gemToAnimate && gemToAnimate.scaleX !== undefined && gemToAnimate.scaleY !== undefined && !gemToAnimate.isScaling) { // Stop any existing scale tweens on this gem tween.stop(gemToAnimate, { scaleX: true, scaleY: true }); // Mark gem as scaling to prevent multiple simultaneous animations gemToAnimate.isScaling = true; // Store original scale values var originalScaleX = CELL_SIZE / 256; var originalScaleY = CELL_SIZE / 256; tween(gemToAnimate, { scaleX: originalScaleX * 1.4, // Bigger bounce for kids scaleY: originalScaleY * 1.4 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { // Check if gem still exists and has valid properties before animating back if (gemToAnimate && gemToAnimate.scaleX !== undefined && gemToAnimate.scaleY !== undefined) { tween(gemToAnimate, { scaleX: originalScaleX, scaleY: originalScaleY }, { duration: 150, easing: tween.easeIn, onFinish: function onFinish() { // Reset scaling flag when animation is complete if (gemToAnimate) { gemToAnimate.isScaling = false; } } }); } else { // Reset scaling flag even if gem no longer exists if (gemToAnimate) { gemToAnimate.isScaling = false; } } } }); } } }; game.move = function (x, y, obj) { if (currentGameState !== GAME_STATE_PLAYING || !isDragging || !selectedGem || isProcessingMatches) return; var deltaX = x - dragStartX; var deltaY = y - dragStartY; var threshold = CELL_SIZE / 2; if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) { var targetGem = null; if (Math.abs(deltaX) > Math.abs(deltaY)) { // Horizontal swipe if (deltaX > 0 && selectedGem.gridX < BOARD_SIZE - 1) { targetGem = gems[selectedGem.gridY][selectedGem.gridX + 1]; } else if (deltaX < 0 && selectedGem.gridX > 0) { targetGem = gems[selectedGem.gridY][selectedGem.gridX - 1]; } } else { // Vertical swipe if (deltaY > 0 && selectedGem.gridY < BOARD_SIZE - 1) { targetGem = gems[selectedGem.gridY + 1][selectedGem.gridX]; } else if (deltaY < 0 && selectedGem.gridY > 0) { targetGem = gems[selectedGem.gridY - 1][selectedGem.gridX]; } } if (targetGem) { swapGems(selectedGem, targetGem); } isDragging = false; selectedGem = null; } }; game.up = function (x, y, obj) { if (currentGameState !== GAME_STATE_PLAYING) return; isDragging = false; selectedGem = null; }; // Initialize home screen createHomeScreen();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Gem = Container.expand(function (type) {
var self = Container.call(this);
self.gemType = type;
self.gridX = 0;
self.gridY = 0;
self.isAnimating = false;
self.isScaling = false;
var gemAssets = ['gem_red', 'gem_blue', 'gem_green', 'gem_yellow', 'gem_purple', 'gem_orange', 'gem_cyan', 'gem_pink'];
var gemGraphics = self.attachAsset(gemAssets[type], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: CELL_SIZE / 256,
scaleY: CELL_SIZE / 256
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = boardStartX + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = boardStartY + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
if (duration === undefined) duration = 300;
self.isAnimating = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isAnimating = false;
if (onComplete) onComplete();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x8B4513 // Brown background
});
/****
* Game Code
****/
// Gold yellow
// Deep pink
// Medium slate blue
var GAME_STATE_HOME = 0;
var GAME_STATE_PLAYING = 1;
var GAME_STATE_PAUSED = 2;
var currentGameState = GAME_STATE_HOME;
// Pause menu elements
var pauseMenuContainer = null;
var pauseMenuBg = null;
var volumeButton = null;
var exitButton = null;
var resumeButton = null;
var volumeEnabled = storage.volumeEnabled !== undefined ? storage.volumeEnabled : true;
var BOARD_SIZE = 8; // Smaller board for kids - easier to see patterns
var CELL_SIZE = Math.floor(Math.min(2048, 2732 - 500) / BOARD_SIZE * 0.95); // Bigger gems, leave more space for UI
var BOARD_TOTAL_SIZE = BOARD_SIZE * CELL_SIZE;
var boardStartX = (2048 - BOARD_TOTAL_SIZE) / 2;
var boardStartY = (2732 - BOARD_TOTAL_SIZE) / 2 + 100; // Offset for top UI
var board = [];
var gems = [];
var selectedGem = null;
var isProcessingMatches = false;
var isDragging = false;
var dragStartX = 0;
var dragStartY = 0;
var score = 0;
// Home screen elements
var homeContainer = null;
var playButton = null;
var titleText = null;
var textInputField = null;
var textInputBorder = null;
var textInputText = null;
var inputText = '';
var keyboardContainer = null;
var keyboardVisible = false;
var keyboardKeys = [];
var keyboardLayout = [['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'], ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'], ['Z', 'X', 'C', 'V', 'B', 'N', 'M']];
function createPauseMenu() {
pauseMenuContainer = new Container();
game.addChild(pauseMenuContainer);
// Create semi-transparent background
pauseMenuBg = pauseMenuContainer.attachAsset('pauseMenuBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
// Pause menu title
var pauseTitle = new Text2('GAME PAUSED', {
size: 80,
fill: 0xFFFFFF
});
pauseTitle.anchor.set(0.5, 0.5);
pauseTitle.x = 2048 / 2;
pauseTitle.y = 2732 / 2 - 200;
pauseMenuContainer.addChild(pauseTitle);
// Resume button
resumeButton = pauseMenuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 100
});
var resumeText = new Text2('RESUME GAME', {
size: 50,
fill: 0xFFFFFF
});
resumeText.anchor.set(0.5, 0.5);
resumeText.x = 2048 / 2;
resumeText.y = 2732 / 2 - 100;
pauseMenuContainer.addChild(resumeText);
// Volume toggle button
volumeButton = pauseMenuContainer.attachAsset('volumeToggle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
var volumeText = new Text2(volumeEnabled ? 'VOLUME: ON' : 'VOLUME: OFF', {
size: 40,
fill: 0xFFFFFF
});
volumeText.anchor.set(0.5, 0.5);
volumeText.x = 2048 / 2;
volumeText.y = 2732 / 2;
pauseMenuContainer.addChild(volumeText);
// Exit button
exitButton = pauseMenuContainer.attachAsset('menuButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 + 100
});
var exitText = new Text2('EXIT TO MENU', {
size: 50,
fill: 0xFFFFFF
});
exitText.anchor.set(0.5, 0.5);
exitText.x = 2048 / 2;
exitText.y = 2732 / 2 + 100;
pauseMenuContainer.addChild(exitText);
// Store reference to volume text for updates
pauseMenuContainer.volumeText = volumeText;
}
function createCustomKeyboard() {
if (keyboardContainer) return; // Already exists
keyboardContainer = new Container();
game.addChild(keyboardContainer);
// Create keyboard background
var keyboardBg = keyboardContainer.attachAsset('keyboardBg', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: 2732
});
// Clear previous keys
keyboardKeys = [];
var startY = 2732 - 750; // Start position for keys
var keySpacing = 150;
var rowSpacing = 110;
// Create letter keys
for (var row = 0; row < keyboardLayout.length; row++) {
var rowKeys = keyboardLayout[row];
var rowWidth = rowKeys.length * keySpacing;
var startX = (2048 - rowWidth) / 2 + keySpacing / 2;
for (var col = 0; col < rowKeys.length; col++) {
var letter = rowKeys[col];
var keyX = startX + col * keySpacing;
var keyY = startY + row * rowSpacing;
var key = keyboardContainer.attachAsset('keyboardKey', {
anchorX: 0.5,
anchorY: 0.5,
x: keyX,
y: keyY
});
var keyText = new Text2(letter, {
size: 45,
fill: 0xFFFFFF
});
keyText.anchor.set(0.5, 0.5);
keyText.x = keyX;
keyText.y = keyY;
keyboardContainer.addChild(keyText);
keyboardKeys.push({
key: key,
text: keyText,
letter: letter,
x: keyX,
y: keyY,
width: 140,
height: 100
});
}
}
// Create space key
var spaceKey = keyboardContainer.attachAsset('keyboardSpaceKey', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: startY + 3 * rowSpacing
});
var spaceText = new Text2('SPACE', {
size: 40,
fill: 0xFFFFFF
});
spaceText.anchor.set(0.5, 0.5);
spaceText.x = 2048 / 2;
spaceText.y = startY + 3 * rowSpacing;
keyboardContainer.addChild(spaceText);
keyboardKeys.push({
key: spaceKey,
text: spaceText,
letter: ' ',
x: 2048 / 2,
y: startY + 3 * rowSpacing,
width: 400,
height: 100
});
// Create backspace key
var backspaceKey = keyboardContainer.attachAsset('keyboardBackspaceKey', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 300,
y: startY + 3 * rowSpacing
});
var backspaceText = new Text2('←', {
size: 50,
fill: 0xFFFFFF
});
backspaceText.anchor.set(0.5, 0.5);
backspaceText.x = 2048 / 2 - 300;
backspaceText.y = startY + 3 * rowSpacing;
keyboardContainer.addChild(backspaceText);
keyboardKeys.push({
key: backspaceKey,
text: backspaceText,
letter: 'BACKSPACE',
x: 2048 / 2 - 300,
y: startY + 3 * rowSpacing,
width: 200,
height: 100
});
// Create done key
var doneKey = keyboardContainer.attachAsset('keyboardDoneKey', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 300,
y: startY + 3 * rowSpacing
});
var doneText = new Text2('DONE', {
size: 40,
fill: 0xFFFFFF
});
doneText.anchor.set(0.5, 0.5);
doneText.x = 2048 / 2 + 300;
doneText.y = startY + 3 * rowSpacing;
keyboardContainer.addChild(doneText);
keyboardKeys.push({
key: doneKey,
text: doneText,
letter: 'DONE',
x: 2048 / 2 + 300,
y: startY + 3 * rowSpacing,
width: 200,
height: 100
});
// Animate keyboard sliding up
keyboardContainer.y = 800;
tween(keyboardContainer, {
y: 0
}, {
duration: 300,
easing: tween.easeOut
});
keyboardVisible = true;
}
function hideCustomKeyboard() {
if (!keyboardContainer) return;
tween(keyboardContainer, {
y: 800
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (keyboardContainer) {
keyboardContainer.destroy();
keyboardContainer = null;
keyboardKeys = [];
keyboardVisible = false;
}
}
});
}
function handleKeyboardInput(letter) {
if (letter === 'BACKSPACE') {
if (inputText.length > 0) {
inputText = inputText.slice(0, -1);
}
} else if (letter === 'DONE') {
hideCustomKeyboard();
return;
} else if (letter === ' ') {
if (inputText.length < 20) {
inputText += ' ';
}
} else {
if (inputText.length < 20) {
inputText += letter;
}
}
// Update text display
if (textInputText) {
if (inputText.length === 0) {
textInputText.setText('Enter your name...');
textInputText.fill = 0x888888;
} else {
textInputText.setText(inputText);
textInputText.fill = 0x000000;
}
}
}
function createHomeScreen() {
homeContainer = new Container();
game.addChild(homeContainer);
// Create title using gemMatchTitle asset
titleText = homeContainer.attachAsset('gemMatchTitle', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 800
});
// Create play button using playButton asset
playButton = homeContainer.attachAsset('playButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1400
});
// Play button text removed per request
// Create text input field under play button
textInputBorder = homeContainer.attachAsset('textInputBorder', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1600
});
textInputField = homeContainer.attachAsset('textInputField', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1600
});
// Create placeholder text for input field
textInputText = new Text2('Enter your name...', {
size: 50,
fill: 0x888888
});
textInputText.anchor.set(0.5, 0.5);
textInputText.x = 2048 / 2;
textInputText.y = 1600;
homeContainer.addChild(textInputText);
// Add bouncy animation to play button
tween(playButton, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Restart the bounce animation
if (currentGameState === GAME_STATE_HOME && playButton) {
tween(playButton, {
scaleX: 1.05,
scaleY: 1.05
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
});
// Add super vibrant rainbow color animation with bounce effect
var rainbowColors = [0xFF0080, 0x00FF80, 0x8000FF, 0xFF8000, 0x0080FF, 0xFF4080, 0x80FF00, 0xFF0040];
var colorIndex = 0;
function animateTitle() {
if (currentGameState === GAME_STATE_HOME && titleText && titleText.fill !== undefined) {
// Color transition
tween(titleText, {
fill: rainbowColors[colorIndex]
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
colorIndex = (colorIndex + 1) % rainbowColors.length;
LK.setTimeout(animateTitle, 100);
}
});
// Add bouncy scale animation
if (titleText.scaleX !== undefined && titleText.scaleY !== undefined) {
tween(titleText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (titleText && titleText.scaleX !== undefined && titleText.scaleY !== undefined) {
tween(titleText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 300,
easing: tween.easeIn
});
}
}
});
}
}
}
animateTitle();
}
function startGame() {
currentGameState = GAME_STATE_PLAYING;
// Reset moves for new game
movesRemaining = maxMoves;
// Remove home screen
if (homeContainer) {
homeContainer.destroy();
homeContainer = null;
playButton = null;
titleText = null;
}
// Create game elements
createGameElements();
initializeBoard();
}
function createGameElements() {
// Create board background
var boardBackground = game.addChild(LK.getAsset('boardBg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: boardStartY + BOARD_TOTAL_SIZE / 2,
scaleX: BOARD_TOTAL_SIZE / 960,
scaleY: BOARD_TOTAL_SIZE / 960
}));
// Initialize score display with bright colors
scoreTxt = new Text2('Score: 0', {
size: 90,
fill: 0xFF1493 // Bright pink text
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 80;
// Add target score display
targetTxt = new Text2('Target: ' + targetScore, {
size: 70,
fill: 0x32CD32 // Bright green text
});
targetTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(targetTxt);
targetTxt.y = 180;
// Add encouraging message display
messageTxt = new Text2('Match the colorful gems!', {
size: 60,
fill: 0xFFD700 // Golden yellow text
});
messageTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(messageTxt);
messageTxt.y = 250;
// Add moves display next to target
movesTxt = new Text2('Moves: ' + movesRemaining, {
size: 70,
fill: 0xFF4500 // Orange red text
});
movesTxt.anchor.set(0, 0);
LK.gui.top.addChild(movesTxt);
movesTxt.x = targetTxt.x + targetTxt.width / 2 + 50;
movesTxt.y = 180;
// Create pause button below the game board
pauseButton = game.addChild(LK.getAsset('pauseButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: boardStartY + BOARD_TOTAL_SIZE + 150
}));
// Pause button text removed per request
}
// UI elements - declare globally but create in game
var scoreTxt = null;
var targetTxt = null;
var messageTxt = null;
var movesTxt = null;
var pauseButton = null;
var targetScore = 500; // Kid-friendly target
var maxMoves = 20; // Limited moves for the game
var movesRemaining = maxMoves;
function initializeBoard() {
// Create 2D array for board
for (var y = 0; y < BOARD_SIZE; y++) {
board[y] = [];
gems[y] = [];
for (var x = 0; x < BOARD_SIZE; x++) {
var gemType = Math.floor(Math.random() * 8);
var gem = new Gem(gemType);
gem.setGridPosition(x, y);
board[y][x] = gemType;
gems[y][x] = gem;
game.addChild(gem);
}
}
// Remove initial matches
removeInitialMatches();
}
function removeInitialMatches() {
var foundMatches = true;
var iterations = 0;
while (foundMatches && iterations < 10) {
foundMatches = false;
iterations++;
for (var y = 0; y < BOARD_SIZE; y++) {
for (var x = 0; x < BOARD_SIZE; x++) {
if (hasMatchAt(x, y)) {
var newType = Math.floor(Math.random() * 8);
board[y][x] = newType;
gems[y][x].gemType = newType;
// Update gem graphics by recreating
gems[y][x].destroy();
var newGem = new Gem(newType);
newGem.setGridPosition(x, y);
gems[y][x] = newGem;
game.addChild(newGem);
foundMatches = true;
}
}
}
}
}
function hasMatchAt(x, y) {
if (board[y][x] === undefined || board[y][x] === -1) return false;
var gemType = board[y][x];
// Check horizontal match
var horizontalCount = 1;
// Check left
for (var i = x - 1; i >= 0 && board[y] && board[y][i] === gemType; i--) {
horizontalCount++;
}
// Check right
for (var i = x + 1; i < BOARD_SIZE && board[y] && board[y][i] === gemType; i++) {
horizontalCount++;
}
// Check vertical match
var verticalCount = 1;
// Check up
for (var i = y - 1; i >= 0 && board[i] && board[i][x] === gemType; i--) {
verticalCount++;
}
// Check down
for (var i = y + 1; i < BOARD_SIZE && board[i] && board[i][x] === gemType; i++) {
verticalCount++;
}
return horizontalCount >= 3 || verticalCount >= 3;
}
function getGemAt(gameX, gameY) {
var gridX = Math.floor((gameX - boardStartX) / CELL_SIZE);
var gridY = Math.floor((gameY - boardStartY) / CELL_SIZE);
if (gridX >= 0 && gridX < BOARD_SIZE && gridY >= 0 && gridY < BOARD_SIZE) {
return gems[gridY][gridX];
}
return null;
}
function isAdjacent(gem1, gem2) {
var dx = Math.abs(gem1.gridX - gem2.gridX);
var dy = Math.abs(gem1.gridY - gem2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapGems(gem1, gem2) {
if (!gem1 || !gem2 || gem1.isAnimating || gem2.isAnimating) return;
// Store original positions and types
var originalGem1X = gem1.gridX;
var originalGem1Y = gem1.gridY;
var originalGem2X = gem2.gridX;
var originalGem2Y = gem2.gridY;
var originalGem1Type = gem1.gemType;
var originalGem2Type = gem2.gemType;
// Calculate original visual positions
var originalGem1PosX = boardStartX + originalGem1X * CELL_SIZE + CELL_SIZE / 2;
var originalGem1PosY = boardStartY + originalGem1Y * CELL_SIZE + CELL_SIZE / 2;
var originalGem2PosX = boardStartX + originalGem2X * CELL_SIZE + CELL_SIZE / 2;
var originalGem2PosY = boardStartY + originalGem2Y * CELL_SIZE + CELL_SIZE / 2;
// Temporarily update board and gem properties to test for matches
board[originalGem1Y][originalGem1X] = originalGem2Type;
board[originalGem2Y][originalGem2X] = originalGem1Type;
gem1.gemType = originalGem2Type;
gem2.gemType = originalGem1Type;
// Check if this swap creates any matches
var hasMatch = hasMatchAt(originalGem1X, originalGem1Y) || hasMatchAt(originalGem2X, originalGem2Y);
if (hasMatch) {
// Valid swap - complete the swap
gem1.setGridPosition(originalGem2X, originalGem2Y);
gem2.setGridPosition(originalGem1X, originalGem1Y);
// Update gems array
gems[originalGem1Y][originalGem1X] = gem2;
gems[originalGem2Y][originalGem2X] = gem1;
// Animate to swapped positions
gem1.animateToPosition(originalGem2PosX, originalGem2PosY, 200);
gem2.animateToPosition(originalGem1PosX, originalGem1PosY, 200, function () {
if (volumeEnabled) {
var swapSound = LK.getSound('swap');
if (swapSound) swapSound.play();
}
// Decrement moves on successful swap
movesRemaining--;
if (movesTxt) {
movesTxt.setText('Moves: ' + movesRemaining);
// Color code the moves display
if (movesRemaining <= 3) {
movesTxt.fill = 0xFF0000; // Red - critical
} else if (movesRemaining <= 5) {
movesTxt.fill = 0xFF8C00; // Orange - warning
} else {
movesTxt.fill = 0xFF4500; // Orange red - normal
}
}
checkForMatches();
});
} else {
// Invalid swap - revert changes
board[originalGem1Y][originalGem1X] = originalGem1Type;
board[originalGem2Y][originalGem2X] = originalGem2Type;
gem1.gemType = originalGem1Type;
gem2.gemType = originalGem2Type;
// Animate gems briefly toward each other then back
var swapDistance = 30;
var gem1SwipePosX = originalGem1PosX + (originalGem2PosX - originalGem1PosX) * 0.3;
var gem1SwipePosY = originalGem1PosY + (originalGem2PosY - originalGem1PosY) * 0.3;
var gem2SwipePosX = originalGem2PosX + (originalGem1PosX - originalGem2PosX) * 0.3;
var gem2SwipePosY = originalGem2PosY + (originalGem1PosY - originalGem2PosY) * 0.3;
// First animate toward each other
gem1.animateToPosition(gem1SwipePosX, gem1SwipePosY, 150, function () {
// Then animate back to original positions
gem1.animateToPosition(originalGem1PosX, originalGem1PosY, 150);
});
gem2.animateToPosition(gem2SwipePosX, gem2SwipePosY, 150, function () {
// Then animate back to original positions
gem2.animateToPosition(originalGem2PosX, originalGem2PosY, 150);
if (volumeEnabled) {
var invalidSound = LK.getSound('invalid_move');
if (invalidSound) invalidSound.play();
}
});
}
}
function checkForMatches() {
if (isProcessingMatches) return;
var matchesFound = [];
// Find all horizontal matches first
for (var y = 0; y < BOARD_SIZE; y++) {
for (var x = 0; x < BOARD_SIZE; x++) {
if (board[y][x] === -1) continue; // Skip empty cells
var gemType = board[y][x];
var horizontalCount = 1;
var horizontalMatches = [{
x: x,
y: y
}];
// Check right
for (var i = x + 1; i < BOARD_SIZE && board[y][i] === gemType; i++) {
horizontalCount++;
horizontalMatches.push({
x: i,
y: y
});
}
if (horizontalCount >= 3) {
// Add all horizontal matches, avoiding duplicates
for (var i = 0; i < horizontalMatches.length; i++) {
var match = horizontalMatches[i];
var alreadyFound = false;
for (var j = 0; j < matchesFound.length; j++) {
if (matchesFound[j].x === match.x && matchesFound[j].y === match.y) {
alreadyFound = true;
break;
}
}
if (!alreadyFound) {
matchesFound.push(match);
}
}
}
}
}
// Find all vertical matches
for (var x = 0; x < BOARD_SIZE; x++) {
for (var y = 0; y < BOARD_SIZE; y++) {
if (board[y][x] === -1) continue; // Skip empty cells
var gemType = board[y][x];
var verticalCount = 1;
var verticalMatches = [{
x: x,
y: y
}];
// Check down
for (var i = y + 1; i < BOARD_SIZE && board[i][x] === gemType; i++) {
verticalCount++;
verticalMatches.push({
x: x,
y: i
});
}
if (verticalCount >= 3) {
// Add all vertical matches, avoiding duplicates
for (var i = 0; i < verticalMatches.length; i++) {
var match = verticalMatches[i];
var alreadyFound = false;
for (var j = 0; j < matchesFound.length; j++) {
if (matchesFound[j].x === match.x && matchesFound[j].y === match.y) {
alreadyFound = true;
break;
}
}
if (!alreadyFound) {
matchesFound.push(match);
}
}
}
}
}
// Check for 2x2 square matches and add rows if found
for (var y = 0; y < BOARD_SIZE - 1; y++) {
for (var x = 0; x < BOARD_SIZE - 1; x++) {
var squareMatches = checkSquareMatch(x, y);
if (squareMatches.length === 4) {
// Check if any of these squares are already in our matches
var hasSquareMatch = false;
for (var i = 0; i < squareMatches.length; i++) {
for (var j = 0; j < matchesFound.length; j++) {
if (squareMatches[i].x === matchesFound[j].x && squareMatches[i].y === matchesFound[j].y) {
hasSquareMatch = true;
break;
}
}
if (hasSquareMatch) break;
}
if (hasSquareMatch) {
// Add entire rows for square matches
for (var rowY = y; rowY <= y + 1; rowY++) {
for (var rowX = 0; rowX < BOARD_SIZE; rowX++) {
var alreadyFound = false;
for (var j = 0; j < matchesFound.length; j++) {
if (matchesFound[j].x === rowX && matchesFound[j].y === rowY) {
alreadyFound = true;
break;
}
}
if (!alreadyFound) {
matchesFound.push({
x: rowX,
y: rowY
});
}
}
}
}
}
}
}
if (matchesFound.length > 0) {
isProcessingMatches = true;
removeMatches(matchesFound);
} else {
// No matches found, check if moves are depleted
if (movesRemaining <= 0) {
messageTxt.setText('NO MORE MOVES!');
LK.effects.flashScreen(0xFF0000, 1000); // Red flash for game over
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
}
}
function checkSquareMatch(x, y) {
if (x >= BOARD_SIZE - 1 || y >= BOARD_SIZE - 1) return [];
var gemType = board[y][x];
// Check if all 4 positions in 2x2 square have same gem type
if (board[y][x] === gemType && board[y][x + 1] === gemType && board[y + 1][x] === gemType && board[y + 1][x + 1] === gemType) {
return [{
x: x,
y: y
}, {
x: x + 1,
y: y
}, {
x: x,
y: y + 1
}, {
x: x + 1,
y: y + 1
}];
}
return [];
}
function getRowsToRemove(matches) {
var rowsToRemove = [];
// Check if any 2x2 square matches exist
for (var y = 0; y < BOARD_SIZE - 1; y++) {
for (var x = 0; x < BOARD_SIZE - 1; x++) {
var squareMatches = checkSquareMatch(x, y);
if (squareMatches.length === 4) {
// Check if this square is part of our current matches
var isPartOfMatches = false;
for (var i = 0; i < squareMatches.length; i++) {
for (var j = 0; j < matches.length; j++) {
if (squareMatches[i].x === matches[j].x && squareMatches[i].y === matches[j].y) {
isPartOfMatches = true;
break;
}
}
if (isPartOfMatches) break;
}
if (isPartOfMatches) {
// Add both rows to removal list
if (rowsToRemove.indexOf(y) === -1) rowsToRemove.push(y);
if (rowsToRemove.indexOf(y + 1) === -1) rowsToRemove.push(y + 1);
}
}
}
}
return rowsToRemove;
}
function getMatchesAt(x, y) {
if (board[y][x] === -1) return []; // Empty cell
var gemType = board[y][x];
var allMatches = [];
// Check horizontal matches
var horizontalMatches = [{
x: x,
y: y
}];
// Check left
for (var i = x - 1; i >= 0 && board[y][i] === gemType; i--) {
horizontalMatches.push({
x: i,
y: y
});
}
// Check right
for (var i = x + 1; i < BOARD_SIZE && board[y][i] === gemType; i++) {
horizontalMatches.push({
x: i,
y: y
});
}
if (horizontalMatches.length >= 3) {
for (var i = 0; i < horizontalMatches.length; i++) {
allMatches.push(horizontalMatches[i]);
}
}
// Check vertical matches
var verticalMatches = [{
x: x,
y: y
}];
// Check up
for (var i = y - 1; i >= 0 && board[i][x] === gemType; i--) {
verticalMatches.push({
x: x,
y: i
});
}
// Check down
for (var i = y + 1; i < BOARD_SIZE && board[i][x] === gemType; i++) {
verticalMatches.push({
x: x,
y: i
});
}
if (verticalMatches.length >= 3) {
// Add vertical matches, avoiding duplicates from horizontal
for (var i = 0; i < verticalMatches.length; i++) {
var vMatch = verticalMatches[i];
var alreadyExists = false;
for (var j = 0; j < allMatches.length; j++) {
if (allMatches[j].x === vMatch.x && allMatches[j].y === vMatch.y) {
alreadyExists = true;
break;
}
}
if (!alreadyExists) {
allMatches.push(vMatch);
}
}
}
return allMatches;
}
function removeMatches(matches) {
// Check for 2x2 square matches and get rows to clear
var rowsToRemove = getRowsToRemove(matches);
var totalGemsToRemove = matches.length;
// If we have a square match, add entire rows to removal
if (rowsToRemove.length > 0) {
var rowMatches = [];
for (var i = 0; i < rowsToRemove.length; i++) {
var rowY = rowsToRemove[i];
for (var x = 0; x < BOARD_SIZE; x++) {
rowMatches.push({
x: x,
y: rowY
});
}
}
// Combine with original matches, avoiding duplicates
for (var i = 0; i < rowMatches.length; i++) {
var rowMatch = rowMatches[i];
var alreadyExists = false;
for (var j = 0; j < matches.length; j++) {
if (matches[j].x === rowMatch.x && matches[j].y === rowMatch.y) {
alreadyExists = true;
break;
}
}
if (!alreadyExists) {
matches.push(rowMatch);
}
}
totalGemsToRemove = matches.length;
}
// Add score with celebration for big matches
score += matches.length * 10;
scoreTxt.setText('Score: ' + score);
// Kid-friendly encouraging messages based on match size and square detection
var encouragingMessages = ['Great job!', 'Awesome!', 'Fantastic!', 'Amazing!', 'Super cool!', 'You\'re doing great!', 'Keep going!', 'Brilliant!', 'Wonderful!'];
if (rowsToRemove.length > 0) {
messageTxt.setText('SQUARE POWER! ROW CLEARED!');
LK.effects.flashScreen(0x00FF00, 1000); // Bright green flash for square matches
if (volumeEnabled) {
var squareSound = LK.getSound('square_match');
if (squareSound) squareSound.play();
}
} else if (matches.length >= 6) {
messageTxt.setText('WOW! INCREDIBLE!');
LK.effects.flashScreen(0xFFD700, 800); // Extra long gold flash
if (volumeEnabled) {
var bigSound = LK.getSound('big_match');
if (bigSound) bigSound.play();
}
} else if (matches.length >= 5) {
messageTxt.setText('SUPER COMBO!');
LK.effects.flashScreen(0xFFD700, 500); // Gold flash for 5+ matches
if (volumeEnabled) {
var bigSound = LK.getSound('big_match');
if (bigSound) bigSound.play();
}
} else if (matches.length >= 4) {
messageTxt.setText('GREAT MATCH!');
LK.effects.flashScreen(0xFF69B4, 300); // Pink flash for 4+ matches
if (volumeEnabled) {
var bigSound = LK.getSound('big_match');
if (bigSound) bigSound.play();
}
} else {
var randomMessage = encouragingMessages[Math.floor(Math.random() * encouragingMessages.length)];
messageTxt.setText(randomMessage);
if (volumeEnabled) {
var matchSound = LK.getSound('match');
if (matchSound) matchSound.play();
}
}
// Update target display with progress
var progress = Math.min(score / targetScore, 1.0);
var progressPercent = Math.floor(progress * 100);
targetTxt.setText('Target: ' + targetScore + ' (' + progressPercent + '%)');
// Encouraging messages based on progress
if (progress >= 0.9) {
targetTxt.fill = 0xFF6347; // Orange - almost there!
} else if (progress >= 0.5) {
targetTxt.fill = 0xFFD700; // Gold - halfway there!
} else {
targetTxt.fill = 0x32CD32; // Green - keep going!
}
// Check if target is reached
if (score >= targetScore) {
messageTxt.setText('🎉 YOU DID IT! 🎉');
LK.effects.flashScreen(0x00FF00, 1000); // Bright green celebration
LK.showYouWin();
}
// Flash and remove matched gems with rainbow colors
var rainbowColors = [0xFF69B4, 0x00BFFF, 0x32CD32, 0xFFD700, 0xFF6347, 0x9370DB];
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var gem = gems[match.y][match.x];
if (gem) {
var flashColor = rainbowColors[i % rainbowColors.length];
LK.effects.flashObject(gem, flashColor, 300);
tween(gem, {
alpha: 0,
scaleX: 1.5,
// Make gems grow bigger before disappearing
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut,
// Bouncy effect
onFinish: function onFinish() {
// Properly destroy the gem after animation
if (gem && gem.destroy) {
gem.destroy();
}
}
});
}
board[match.y][match.x] = -1; // Mark as empty
gems[match.y][match.x] = null; // Clear gem reference
}
// Wait for animation then drop gems
LK.setTimeout(function () {
dropGems();
}, 350);
}
function dropGems() {
var moved = false;
// Drop existing gems
for (var x = 0; x < BOARD_SIZE; x++) {
var writePos = BOARD_SIZE - 1;
for (var y = BOARD_SIZE - 1; y >= 0; y--) {
if (board[y][x] !== -1) {
if (y !== writePos) {
// Move gem down
board[writePos][x] = board[y][x];
gems[writePos][x] = gems[y][x];
gems[writePos][x].setGridPosition(x, writePos);
gems[writePos][x].animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + writePos * CELL_SIZE + CELL_SIZE / 2, 200);
board[y][x] = -1;
gems[y][x] = null;
moved = true;
}
writePos--;
}
}
}
// Fill empty spaces with new gems - ensure we fill from top to bottom
for (var x = 0; x < BOARD_SIZE; x++) {
for (var y = 0; y < BOARD_SIZE; y++) {
if (board[y][x] === -1) {
var newType = Math.floor(Math.random() * 8);
var newGem = new Gem(newType);
newGem.setGridPosition(x, y);
newGem.y = boardStartY - (BOARD_SIZE - y) * CELL_SIZE + CELL_SIZE / 2; // Start above board
newGem.animateToPosition(boardStartX + x * CELL_SIZE + CELL_SIZE / 2, boardStartY + y * CELL_SIZE + CELL_SIZE / 2, 400);
board[y][x] = newType;
gems[y][x] = newGem;
game.addChild(newGem);
moved = true;
}
}
}
// Double check - ensure no empty spaces remain by creating additional gems if needed
for (var x = 0; x < BOARD_SIZE; x++) {
for (var y = 0; y < BOARD_SIZE; y++) {
if (!gems[y][x] || board[y][x] === -1) {
var newType = Math.floor(Math.random() * 8);
var newGem = new Gem(newType);
newGem.setGridPosition(x, y);
board[y][x] = newType;
gems[y][x] = newGem;
game.addChild(newGem);
moved = true;
}
}
}
if (moved) {
LK.setTimeout(function () {
isProcessingMatches = false;
checkForMatches(); // Check for cascade matches
}, 450);
} else {
isProcessingMatches = false;
}
}
game.down = function (x, y, obj) {
if (currentGameState === GAME_STATE_HOME) {
// Check if play button was clicked using coordinate bounds
if (playButton) {
var buttonLeft = playButton.x - playButton.width * playButton.scaleX / 2;
var buttonRight = playButton.x + playButton.width * playButton.scaleX / 2;
var buttonTop = playButton.y - playButton.height * playButton.scaleY / 2;
var buttonBottom = playButton.y + playButton.height * playButton.scaleY / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
// Add click effect to play button
tween(playButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(playButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
if (volumeEnabled) LK.getSound('button_click').play();
startGame();
}
});
}
});
}
// Check if text input field was clicked
if (textInputField) {
var fieldLeft = textInputField.x - textInputField.width / 2;
var fieldRight = textInputField.x + textInputField.width / 2;
var fieldTop = textInputField.y - textInputField.height / 2;
var fieldBottom = textInputField.y + textInputField.height / 2;
if (x >= fieldLeft && x <= fieldRight && y >= fieldTop && y <= fieldBottom) {
// Show custom keyboard
if (volumeEnabled) LK.getSound('button_click').play();
// Add visual feedback
tween(textInputField, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(textInputField, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
createCustomKeyboard();
}
});
}
});
return;
}
// Handle keyboard clicks
if (keyboardVisible && keyboardContainer) {
for (var i = 0; i < keyboardKeys.length; i++) {
var keyData = keyboardKeys[i];
var keyLeft = keyData.x - keyData.width / 2;
var keyRight = keyData.x + keyData.width / 2;
var keyTop = keyData.y - keyData.height / 2;
var keyBottom = keyData.y + keyData.height / 2;
if (x >= keyLeft && x <= keyRight && y >= keyTop && y <= keyBottom) {
// Key pressed - add visual feedback
if (volumeEnabled) LK.getSound('button_click').play();
var originalKey = keyData.key;
tween(originalKey, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(originalKey, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
}
});
handleKeyboardInput(keyData.letter);
return;
}
}
}
}
}
return;
}
if (currentGameState === GAME_STATE_PAUSED) {
// Handle pause menu clicks
if (resumeButton) {
var buttonLeft = resumeButton.x - resumeButton.width / 2;
var buttonRight = resumeButton.x + resumeButton.width / 2;
var buttonTop = resumeButton.y - resumeButton.height / 2;
var buttonBottom = resumeButton.y + resumeButton.height / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
// Resume game
if (volumeEnabled) LK.getSound('button_click').play();
currentGameState = GAME_STATE_PLAYING;
pauseMenuContainer.destroy();
pauseMenuContainer = null;
return;
}
}
if (volumeButton) {
var buttonLeft = volumeButton.x - volumeButton.width / 2;
var buttonRight = volumeButton.x + volumeButton.width / 2;
var buttonTop = volumeButton.y - volumeButton.height / 2;
var buttonBottom = volumeButton.y + volumeButton.height / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
// Toggle volume
if (volumeEnabled) LK.getSound('button_click').play();
volumeEnabled = !volumeEnabled;
storage.volumeEnabled = volumeEnabled;
pauseMenuContainer.volumeText.setText(volumeEnabled ? 'VOLUME: ON' : 'VOLUME: OFF');
return;
}
}
if (exitButton) {
var buttonLeft = exitButton.x - exitButton.width / 2;
var buttonRight = exitButton.x + exitButton.width / 2;
var buttonTop = exitButton.y - exitButton.height / 2;
var buttonBottom = exitButton.y + exitButton.height / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
// Exit to home screen
if (volumeEnabled) LK.getSound('button_click').play();
currentGameState = GAME_STATE_HOME;
// Clear all game elements
game.removeChildren();
// Reset UI elements
LK.gui.top.removeChildren();
scoreTxt = null;
targetTxt = null;
messageTxt = null;
movesTxt = null;
pauseButton = null;
pauseMenuContainer = null;
// Reset game variables
board = [];
gems = [];
selectedGem = null;
isProcessingMatches = false;
isDragging = false;
score = 0;
// Show home screen
createHomeScreen();
return;
}
}
return;
}
if (currentGameState !== GAME_STATE_PLAYING || isProcessingMatches) return;
// Check if pause button was clicked
if (pauseButton) {
var buttonLeft = pauseButton.x - pauseButton.width / 2;
var buttonRight = pauseButton.x + pauseButton.width / 2;
var buttonTop = pauseButton.y - pauseButton.height / 2;
var buttonBottom = pauseButton.y + pauseButton.height / 2;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
// Add click effect to pause button
tween(pauseButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(pauseButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
// Show pause menu
if (volumeEnabled) LK.getSound('button_click').play();
currentGameState = GAME_STATE_PAUSED;
createPauseMenu();
}
});
}
});
return;
}
}
selectedGem = getGemAt(x, y);
if (selectedGem) {
if (volumeEnabled) {
var selectSound = LK.getSound('select');
if (selectSound) selectSound.play();
}
isDragging = true;
dragStartX = x;
dragStartY = y;
// Fun rainbow flash and bigger bounce effect for kids
var rainbowColors = [0xFF69B4, 0x00BFFF, 0x32CD32, 0xFFD700, 0xFF6347, 0x9370DB];
var randomColor = rainbowColors[Math.floor(Math.random() * rainbowColors.length)];
LK.effects.flashObject(selectedGem, randomColor, 300);
// Store reference to selected gem for use in callbacks
var gemToAnimate = selectedGem;
// Check if gem exists and has valid properties before starting tween, and prevent multiple scale animations
if (gemToAnimate && gemToAnimate.scaleX !== undefined && gemToAnimate.scaleY !== undefined && !gemToAnimate.isScaling) {
// Stop any existing scale tweens on this gem
tween.stop(gemToAnimate, {
scaleX: true,
scaleY: true
});
// Mark gem as scaling to prevent multiple simultaneous animations
gemToAnimate.isScaling = true;
// Store original scale values
var originalScaleX = CELL_SIZE / 256;
var originalScaleY = CELL_SIZE / 256;
tween(gemToAnimate, {
scaleX: originalScaleX * 1.4,
// Bigger bounce for kids
scaleY: originalScaleY * 1.4
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Check if gem still exists and has valid properties before animating back
if (gemToAnimate && gemToAnimate.scaleX !== undefined && gemToAnimate.scaleY !== undefined) {
tween(gemToAnimate, {
scaleX: originalScaleX,
scaleY: originalScaleY
}, {
duration: 150,
easing: tween.easeIn,
onFinish: function onFinish() {
// Reset scaling flag when animation is complete
if (gemToAnimate) {
gemToAnimate.isScaling = false;
}
}
});
} else {
// Reset scaling flag even if gem no longer exists
if (gemToAnimate) {
gemToAnimate.isScaling = false;
}
}
}
});
}
}
};
game.move = function (x, y, obj) {
if (currentGameState !== GAME_STATE_PLAYING || !isDragging || !selectedGem || isProcessingMatches) return;
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var threshold = CELL_SIZE / 2;
if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) {
var targetGem = null;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swipe
if (deltaX > 0 && selectedGem.gridX < BOARD_SIZE - 1) {
targetGem = gems[selectedGem.gridY][selectedGem.gridX + 1];
} else if (deltaX < 0 && selectedGem.gridX > 0) {
targetGem = gems[selectedGem.gridY][selectedGem.gridX - 1];
}
} else {
// Vertical swipe
if (deltaY > 0 && selectedGem.gridY < BOARD_SIZE - 1) {
targetGem = gems[selectedGem.gridY + 1][selectedGem.gridX];
} else if (deltaY < 0 && selectedGem.gridY > 0) {
targetGem = gems[selectedGem.gridY - 1][selectedGem.gridX];
}
}
if (targetGem) {
swapGems(selectedGem, targetGem);
}
isDragging = false;
selectedGem = null;
}
};
game.up = function (x, y, obj) {
if (currentGameState !== GAME_STATE_PLAYING) return;
isDragging = false;
selectedGem = null;
};
// Initialize home screen
createHomeScreen();
make a orange gem realistic. In-Game asset. 2d. High contrast. No shadows
a purple gem not a diamond realistic. In-Game asset. 2d. High contrast. No shadows
a red gem realistic. In-Game asset. 2d. High contrast. No shadows
a yellow gem found from the caves of colorado make it realistic. In-Game asset. 2d. High contrast. No shadows
a cyan realistic gem. In-Game asset. 2d. High contrast. No shadows
a pink gem realistic. In-Game asset. 2d. High contrast. No shadows
a very modern pause button. In-Game asset. 2d. High contrast. No shadows
a fun play button that says play on it super modern and kid friendly. In-Game asset. 2d. High contrast. No shadows
a create account button for signing up in a game supa kid friendly and modern. In-Game asset. 2d. High contrast. No shadows