User prompt
arregla contador, no dura realmente 10 segundos, usa delta time
User prompt
el contador parece no tardar realmente 10 segundos, esta acelerado
User prompt
haz que el fast mode empiece con un contador de 10 segundos a medida que el record aumenta el tiempo disminuye a minimo 4 segundos
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'self.timerText.style.fill = 0xFFFFFF; // White normally' Line Number: 315
User prompt
caracteristicas de fast mode: Habra un contador de 3 segundos, cuando este llegue a 0 se pierde, la unica forma de reiniciarlo es rompiendo memes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
haz que todos los memeas sean especiales random
User prompt
haz que todos los memes sean verdes ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
arregla el bug que hace que no aparezcan nuevos memes despues de usar la habilidad verde
User prompt
arregla el bug que hace que no aparezcan nuevos memes despues de usar la habilidad verde
User prompt
caracteristicas de classic mode: Solo se pueden mover los memes si se rompen, de no romperse volveran a su posición
User prompt
arregla el siguiente error: despues de mover un meme y que se regrese a su posición no se puede seleccionar ningun otro meme para mover
User prompt
arregla el bug que no permite mover ningun meme despues de que el meme regrese a su posición
User prompt
caracteristicas de classic mode: Solo se pueden mover los memes si se rompen, de no romperse volveran a su posición
User prompt
caracteristicas de classic mode: Solo se pueden mover los memes si se rompen, de no romperse volveran a su posición
User prompt
crea dos botones en el menu Classic mode y Fast mode, luego especificaremos la caracteristicas de cada uno
User prompt
Crea un menu inicial separado del juego
User prompt
el juego no se inicia
User prompt
Agrega un menu inicial
User prompt
agrega un sistema de puntos
User prompt
agrega una variable GameStart, cuando este es verdadero el juego comienza y se inicia la posición aleatoria de los memes
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'visible')' in or related to this line: 'gridContainer.visible = false;' Line Number: 278
User prompt
Please fix the bug: 'Cannot set properties of undefined (setting 'visible')' in or related to this line: 'gridContainer.visible = false;' Line Number: 276
User prompt
crea un menu inicial
User prompt
Crea un menu inicial
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var GridCell = Container.expand(function () { var self = Container.call(this); self.init = function () { if (!self.background) { self.background = self.attachAsset('cuadricula', { anchorX: 0.5, anchorY: 0.5 }); } self.value = 0; self.sprite = null; self.row = -1; self.col = -1; self.isSpecial = false; self.specialType = null; return self; }; self.setValue = function (newValue) { if (self.value === newValue) { return; } self.value = newValue; if (self.sprite) { self.removeChild(self.sprite); } var spriteId = 'meme' + newValue; self.sprite = LK.getAsset(spriteId, { anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.sprite); // Apply tint if this is a special meme if (self.isSpecial) { if (self.specialType === 'bomb') { self.sprite.tint = 0x0088FF; // Blue tint for bomb special meme } else if (self.specialType === 'green') { self.sprite.tint = 0x00FF00; // Green tint for swap-destroy special meme } else { self.sprite.tint = 0xFF8800; // Orange tint for horizontal/vertical special meme } } }; self.activateSpecialPower = function () { if (!self.isSpecial) { return; } var cellsToDestroy = []; var bonusPoints = 0; if (self.specialType === 'horizontal') { // Destroy all cells in the same column for (var row = extraRows; row < gridSize + extraRows; row++) { if (gridCells[row][self.col] && gridCells[row][self.col] !== self) { cellsToDestroy.push(gridCells[row][self.col]); } } // Award bonus points for horizontal special activation bonusPoints = 100; } else if (self.specialType === 'vertical') { // Destroy all cells in the same row for (var col = 0; col < gridSize; col++) { if (gridCells[self.row][col] && gridCells[self.row][col] !== self) { cellsToDestroy.push(gridCells[self.row][col]); } } // Award bonus points for vertical special activation bonusPoints = 100; } else if (self.specialType === 'bomb') { // Destroy adjacent cells (bomb effect) for (var row = Math.max(extraRows, self.row - 1); row <= Math.min(gridSize + extraRows - 1, self.row + 1); row++) { for (var col = Math.max(0, self.col - 1); col <= Math.min(gridSize - 1, self.col + 1); col++) { if (gridCells[row][col] && gridCells[row][col] !== self) { cellsToDestroy.push(gridCells[row][col]); } } } // Award bonus points for bomb special activation bonusPoints = 150; } else if (self.specialType === 'green') { // Green special meme power is activated when swapped, not when destroyed // The power is implemented in handleCellTap function // Award bonus points for green special activation (though it should be handled elsewhere) bonusPoints = 200; } // Award special activation bonus points if (bonusPoints > 0) { updateScore(bonusPoints); // Show floating score text for special activation var scorePopup = new Text2("+" + bonusPoints, { size: 60, fill: 0xFFFF00 }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = self.x; scorePopup.y = self.y; game.addChild(scorePopup); // Animate score popup tween(scorePopup, { y: scorePopup.y - 80, alpha: 0 }, { duration: 800, onComplete: function onComplete() { game.removeChild(scorePopup); scorePopup.destroy(); } }); } // Destroy collected cells if (cellsToDestroy.length > 0) { destroyCells(cellsToDestroy); // Also destroy this special meme self.beingDestroyed = true; LK.getSound('Explosion').play(); LK.effects.flashObject(self, 0xFFFFFF, 200); gridContainer.removeChild(self); self.destroy(); gridCells[self.row][self.col] = null; } }; self.showSelection = function () { if (self.selectionHighlight) { return; } self.selectionHighlight = new Container(); // Create pulsating highlight effect var highlight = LK.getAsset('cuadricula', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.15, scaleY: 1.15, alpha: 0.6 }); highlight.tint = 0x00FFFF; // Cyan highlight self.selectionHighlight.addChild(highlight); self.addChildAt(self.selectionHighlight, 0); // Create pulsating animation function pulseAnimation() { tween(highlight, { alpha: 0.3, scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOutQuad, onComplete: function onComplete() { tween(highlight, { alpha: 0.6, scaleX: 1.15, scaleY: 1.15 }, { duration: 500, easing: tween.easeInOutQuad, onComplete: pulseAnimation }); } }); } pulseAnimation(); }; self.hideSelection = function () { if (self.selectionHighlight) { self.removeChild(self.selectionHighlight); self.selectionHighlight = null; } }; self.down = function (x, y, obj) { handleCellTap(self); }; self.init(); return self; }); var MenuScreen = Container.expand(function () { var self = Container.call(this); // Create title var title = new Text2("Meme Match", { size: 120, fill: 0x000000 }); title.anchor.set(0.5, 0); title.x = 2048 / 2; title.y = 300; self.addChild(title); // Create Classic mode button var classicButton = new Container(); var classicButtonBg = LK.getAsset('cuadricula', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1.5 }); classicButtonBg.tint = 0x00AA00; var classicText = new Text2("CLASSIC MODE", { size: 70, fill: 0xFFFFFF }); classicText.anchor.set(0.5, 0.5); classicButton.addChild(classicButtonBg); classicButton.addChild(classicText); classicButton.x = 2048 / 2; classicButton.y = 2732 / 2 - 200; self.addChild(classicButton); // Create Fast mode button var fastButton = new Container(); var fastButtonBg = LK.getAsset('cuadricula', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1.5 }); fastButtonBg.tint = 0x0088FF; var fastText = new Text2("FAST MODE", { size: 70, fill: 0xFFFFFF }); fastText.anchor.set(0.5, 0.5); fastButton.addChild(fastButtonBg); fastButton.addChild(fastText); fastButton.x = 2048 / 2; fastButton.y = 2732 / 2 + 100; self.addChild(fastButton); // Add button interactions classicButton.interactive = true; classicButton.down = function (x, y, obj) { LK.effects.flashObject(classicButtonBg, 0xFFFFFF, 200); LK.setTimeout(function () { self.startGame('classic'); }, 300); }; fastButton.interactive = true; fastButton.down = function (x, y, obj) { LK.effects.flashObject(fastButtonBg, 0xFFFFFF, 200); LK.setTimeout(function () { self.startGame('fast'); }, 300); }; // Function to start the game self.startGame = function (mode) { game.gameMode = mode || 'classic'; game.removeChild(self); game.initializeGame(); }; return self; }); var TimerDisplay = Container.expand(function () { var self = Container.call(this); // Create timer text self.timerText = new Text2("3", { size: 100, fill: 0xFF0000 }); self.timerText.style = self.timerText.style || {}; self.timerText.anchor.set(0.5, 0.5); self.addChild(self.timerText); // Initialize timer properties self.maxTime = 10; // 10 seconds default for Fast Mode self.currentTime = self.maxTime; self.active = false; self.warningThreshold = 1; // Flashing warning when 1 second left self.lastWholeSecond = Math.ceil(self.currentTime); self.baseMaxTime = 10; // Store the base maximum time self.minMaxTime = 4; // Minimum timer value is 4 seconds // Start the timer self.start = function () { self.active = true; self.currentTime = self.maxTime; self.lastWholeSecond = Math.ceil(self.currentTime); self.updateDisplay(); }; // Stop the timer self.stop = function () { self.active = false; }; // Calculate max time based on score self.calculateMaxTime = function () { // As score increases, time decreases, with a minimum of 4 seconds // Formula: Start with 10 seconds, subtract 0.01 seconds per point, but never go below 4 seconds var calculatedTime = self.baseMaxTime - score * 0.01; return Math.max(self.minMaxTime, calculatedTime); }; // Reset timer back to max self.reset = function () { // Update maxTime based on current score self.maxTime = self.calculateMaxTime(); self.currentTime = self.maxTime; self.lastWholeSecond = Math.ceil(self.currentTime); self.updateDisplay(); // Flash effect to indicate reset LK.effects.flashObject(self.timerText, 0x00FF00, 200); }; // Update timer display self.updateDisplay = function () { var displayTime = Math.ceil(self.currentTime); self.timerText.setText(displayTime.toString()); // Change color based on time remaining if (displayTime <= self.warningThreshold) { self.timerText.style.fill = 0xFF0000; // Red when low time // Pulse animation for urgency when time is low if (!self.pulsing) { self.pulsing = true; self.startPulseAnimation(); } } else { self.timerText.style.fill = 0xFFFFFF; // White normally self.stopPulseAnimation(); } }; // Pulse animation for low time warning self.startPulseAnimation = function () { tween.stop(self.timerText); self.doPulse(); }; self.doPulse = function () { if (!self.pulsing) return; tween(self.timerText, { scaleX: 1.3, scaleY: 1.3 }, { duration: 200, easing: tween.easeOut, onComplete: function onComplete() { tween(self.timerText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeIn, onComplete: self.doPulse }); } }); }; self.stopPulseAnimation = function () { self.pulsing = false; tween.stop(self.timerText); tween(self.timerText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100 }); }; // Update method called every frame self.update = function (deltaTime) { if (!self.active) return; // Use deltaTime for accurate timing regardless of frame rate var seconds = deltaTime ? deltaTime / 1000 : 1 / 60; self.currentTime -= seconds; // Check if we crossed a whole second boundary for display update var currentWholeSecond = Math.ceil(self.currentTime); if (currentWholeSecond !== self.lastWholeSecond) { self.lastWholeSecond = currentWholeSecond; self.updateDisplay(); } // Check if time is up if (self.currentTime <= 0) { self.currentTime = 0; self.active = false; self.onTimeUp && self.onTimeUp(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xF4FFFF }); /**** * Game Code ****/ // Game state and initialization var menuScreen; var gameInitialized = false; var score = 0; var scoreText; var gridContainer; var gameMode = 'classic'; // Track current game mode // Initialize the menu function initializeMenu() { menuScreen = new MenuScreen(); game.addChild(menuScreen); } // Initialize the game game.initializeGame = function () { // Initialize score system score = 0; // Create and position score text initializeScore(); // Create grid container if it doesn't exist if (!gridContainer) { gridContainer = new Container(); game.addChild(gridContainer); } else { // Clear existing grid container while (gridContainer.children.length > 0) { var child = gridContainer.children[0]; gridContainer.removeChild(child); child.destroy(); } } // Add mode indicator text var modeText = new Text2(game.gameMode === 'classic' ? "Classic Mode" : "Fast Mode", { size: 60, fill: game.gameMode === 'classic' ? 0x00AA00 : 0x0088FF }); modeText.anchor.set(0.5, 0); modeText.x = 2048 / 2; modeText.y = 180; game.addChild(modeText); // Initialize timer for Fast mode if (game.gameMode === 'fast') { if (!game.timer) { game.timer = new TimerDisplay(); game.timer.x = 2048 / 2; game.timer.y = 2732 - 120; game.addChild(game.timer); game.timer.onTimeUp = function () { // Game over when time runs out LK.effects.flashScreen(0xFF0000, 500); LK.showGameOver(); }; } else { // Reset existing timer game.timer.reset(); } // Calculate initial timer value based on score before starting game.timer.maxTime = game.timer.calculateMaxTime(); // Start timer game.timer.start(); } else if (game.timer) { // Remove timer if not in Fast mode game.timer.stop(); game.removeChild(game.timer); game.timer = null; } // Initialize the game grid initializeGrid(); ensureNoInitialMatches(); // Main game update loop game.update = function (deltaTime) { // Update timer in Fast mode if (game.gameMode === 'fast' && game.timer) { game.timer.update(deltaTime); } }; gameInitialized = true; }; // Create and position score text function initializeScore() { scoreText = new Text2("Score: 0", { size: 80, fill: 0x000000 }); scoreText.anchor.set(0.5, 0); scoreText.x = 2048 / 2; scoreText.y = 100; game.addChild(scoreText); } // Update score display function updateScore(points) { score += points; scoreText.setText("Score: " + score); } var cellPool = []; function getGridCell() { if (cellPool.length > 0) { return cellPool.pop().init(); } return new GridCell(); } function recycleGridCell(cell) { if (cell) { cellPool.push(cell); } } var selectedCell = null; var isAnimating = false; window.gravityInProgress = false; window.fillInProgress = false; // Track combo counts for sound effects var comboCounter = 0; var comboInProgress = false; function handleCellTap(tappedCell) { if (isAnimating || window.gravityInProgress || window.fillInProgress) { return; } if (!tappedCell || !gridCells[tappedCell.row] || gridCells[tappedCell.row][tappedCell.col] !== tappedCell || tappedCell.beingDestroyed) { return; } // Special memes need to be matched with other memes to be activated, so we don't check for special activation here // If we already have a selected cell if (selectedCell !== null) { // If it's valid if (selectedCell && gridCells[selectedCell.row] && gridCells[selectedCell.row][selectedCell.col] === selectedCell) { // If we tap the same cell, deselect it if (selectedCell === tappedCell) { selectedCell.hideSelection(); selectedCell = null; return; } // Check if they're adjacent var isAdjacent = Math.abs(selectedCell.row - tappedCell.row) === 1 && selectedCell.col === tappedCell.col || Math.abs(selectedCell.col - tappedCell.col) === 1 && selectedCell.row === tappedCell.row; if (!isAdjacent) { // Not adjacent, switch selection selectedCell.hideSelection(); selectedCell = tappedCell; selectedCell.showSelection(); return; } // They are adjacent, continue with swap var cell1 = selectedCell; var cell2 = tappedCell; // Hide selection before swap cell1.hideSelection(); selectedCell = null; var isAdjacent = Math.abs(cell1.row - cell2.row) === 1 && cell1.col === cell2.col || Math.abs(cell1.col - cell2.col) === 1 && cell1.row === cell2.row; if (!isAdjacent) { return; } } else { // Invalid selected cell, select the new one if (selectedCell) { selectedCell.hideSelection(); } selectedCell = tappedCell; selectedCell.showSelection(); return; } } else { // No selection yet, select this cell selectedCell = tappedCell; selectedCell.showSelection(); return; } isAnimating = true; // Store original positions and grid coordinates var pos1_x = cell1.x; var pos1_y = cell1.y; var pos2_x = cell2.x; var pos2_y = cell2.y; var row1 = cell1.row; var col1 = cell1.col; var row2 = cell2.row; var col2 = cell2.col; // Check if cells are special memes var greenSpecialCell = null; var regularCell = null; var lineSpecialCells = []; var twoGreenSpecials = false; // Check for two green special memes if (cell1.isSpecial && cell1.specialType === 'green' && cell2.isSpecial && cell2.specialType === 'green') { twoGreenSpecials = true; } // Check for green special meme else if (cell1.isSpecial && cell1.specialType === 'green') { greenSpecialCell = cell1; regularCell = cell2; } else if (cell2.isSpecial && cell2.specialType === 'green') { greenSpecialCell = cell2; regularCell = cell1; } // Check for line-clearing special memes (horizontal/vertical) if (cell1.isSpecial && (cell1.specialType === 'horizontal' || cell1.specialType === 'vertical')) { lineSpecialCells.push(cell1); } if (cell2.isSpecial && (cell2.specialType === 'horizontal' || cell2.specialType === 'vertical')) { lineSpecialCells.push(cell2); } gridCells[row1][col1] = cell2; gridCells[row2][col2] = cell1; cell1.row = row2; cell1.col = col2; cell2.row = row1; cell2.col = col1; // Make sure any selection highlights are removed if (cell1.selectionHighlight) { cell1.hideSelection(); } if (cell2.selectionHighlight) { cell2.hideSelection(); } // Check for special combinations: two green special memes, two bombs, line-clearing + bomb, or two line special memes if (twoGreenSpecials) { // Two green special memes combination - destroys all visible memes var cellsToDestroy = []; // Collect all visible cells on the board for (var row = extraRows; row < gridSize + extraRows; row++) { for (var col = 0; col < gridSize; col++) { if (gridCells[row][col] && gridCells[row][col] !== cell1 && gridCells[row][col] !== cell2) { cellsToDestroy.push(gridCells[row][col]); } } } // Award massive bonus for two green special meme combination updateScore(1000); // Show mega score popup var megaScorePopup = new Text2("+1000", { size: 100, fill: 0x00FF00 }); megaScorePopup.anchor.set(0.5, 0.5); megaScorePopup.x = 2048 / 2; megaScorePopup.y = 2732 / 2; game.addChild(megaScorePopup); // Animate mega score popup tween(megaScorePopup, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 1000, onComplete: function onComplete() { game.removeChild(megaScorePopup); megaScorePopup.destroy(); } }); // Mark special memes for destruction cell1.beingDestroyed = true; cell2.beingDestroyed = true; // Schedule destruction after the swap animation completes LK.setTimeout(function () { LK.getSound('Explosion').play(); // Flash screen effect for this powerful combination LK.effects.flashScreen(0x00FF00, 500); // Destroy the collected cells if (cellsToDestroy.length > 0) { destroyCells(cellsToDestroy); } // Destroy the special memes LK.effects.flashObject(cell1, 0xFFFFFF, 200); LK.effects.flashObject(cell2, 0xFFFFFF, 200); gridContainer.removeChild(cell1); gridContainer.removeChild(cell2); cell1.destroy(); cell2.destroy(); gridCells[cell1.row][cell1.col] = null; gridCells[cell2.row][cell2.col] = null; }, 250); } else if (cell1.isSpecial && cell1.specialType === 'bomb' && cell2.isSpecial && cell2.specialType === 'bomb') { // Two bomb special memes combination - creates a 5x5 explosion var cellsToDestroy = []; // Determine which cell was moved by the player var activatedCell = cell1; // Create a 5x5 area effect centered on the first bomb for (var r = Math.max(extraRows, cell1.row - 2); r <= Math.min(gridSize + extraRows - 1, cell1.row + 2); r++) { for (var c = Math.max(0, cell1.col - 2); c <= Math.min(gridSize - 1, cell1.col + 2); c++) { if (gridCells[r][c] && gridCells[r][c] !== cell1 && gridCells[r][c] !== cell2) { cellsToDestroy.push(gridCells[r][c]); } } } // Mark special memes for destruction cell1.beingDestroyed = true; cell2.beingDestroyed = true; // Schedule destruction after the swap animation completes LK.setTimeout(function () { LK.getSound('Explosion').play(); // Destroy the collected cells if (cellsToDestroy.length > 0) { destroyCells(cellsToDestroy); } // Destroy the special memes LK.effects.flashObject(cell1, 0xFFFFFF, 200); LK.effects.flashObject(cell2, 0xFFFFFF, 200); gridContainer.removeChild(cell1); gridContainer.removeChild(cell2); cell1.destroy(); cell2.destroy(); gridCells[cell1.row][cell1.col] = null; gridCells[cell2.row][cell2.col] = null; }, 250); } else if (cell1.isSpecial && cell1.specialType === 'bomb' && cell2.isSpecial && (cell2.specialType === 'horizontal' || cell2.specialType === 'vertical') || cell2.isSpecial && cell2.specialType === 'bomb' && cell1.isSpecial && (cell1.specialType === 'horizontal' || cell1.specialType === 'vertical')) { // Line-clearing + bomb special combination var bombCell = cell1.specialType === 'bomb' ? cell1 : cell2; var lineCell = cell1.specialType === 'horizontal' || cell1.specialType === 'vertical' ? cell1 : cell2; var cellsToDestroy = []; var affectedRows = []; // Determine which cell was moved by the player var activatedCell = cell1; // Enhanced effect: destroy 3 rows or columns based on the line special type if (lineCell.specialType === 'horizontal') { // Destroy 3 rows centered on the bomb's row for (var r = Math.max(extraRows, bombCell.row - 1); r <= Math.min(gridSize + extraRows - 1, bombCell.row + 1); r++) { affectedRows.push(r); for (var c = 0; c < gridSize; c++) { if (gridCells[r][c] && gridCells[r][c] !== bombCell && gridCells[r][c] !== lineCell) { cellsToDestroy.push(gridCells[r][c]); } } } } else { // vertical // Destroy 3 columns centered on the bomb's column for (var r = extraRows; r < gridSize + extraRows; r++) { for (var c = Math.max(0, bombCell.col - 1); c <= Math.min(gridSize - 1, bombCell.col + 1); c++) { if (gridCells[r][c] && gridCells[r][c] !== bombCell && gridCells[r][c] !== lineCell) { cellsToDestroy.push(gridCells[r][c]); } } } } // Mark special memes for destruction bombCell.beingDestroyed = true; lineCell.beingDestroyed = true; // Schedule destruction after the swap animation completes LK.setTimeout(function () { LK.getSound('Explosion').play(); // Destroy the collected cells if (cellsToDestroy.length > 0) { destroyCells(cellsToDestroy); } // Destroy the special memes LK.effects.flashObject(bombCell, 0xFFFFFF, 200); LK.effects.flashObject(lineCell, 0xFFFFFF, 200); gridContainer.removeChild(bombCell); gridContainer.removeChild(lineCell); bombCell.destroy(); lineCell.destroy(); gridCells[bombCell.row][bombCell.col] = null; gridCells[lineCell.row][lineCell.col] = null; }, 250); } // Check if two line special memes were swapped (horizontal and vertical) else if (lineSpecialCells.length === 2) { var cellsToDestroy = []; // Collect cells in both row and column var row1, col1, row2, col2; var activatedSpecial; // Determine which special meme was moved by the player (based on original positions) if (lineSpecialCells[0] === cell1) { activatedSpecial = lineSpecialCells[0]; row1 = lineSpecialCells[0].row; col1 = lineSpecialCells[0].col; } else { activatedSpecial = lineSpecialCells[1]; row1 = lineSpecialCells[1].row; col1 = lineSpecialCells[1].col; } // Add cells from the activated special's row or column for (var row = extraRows; row < gridSize + extraRows; row++) { // Add cells from column if (gridCells[row][col1] && gridCells[row][col1] !== lineSpecialCells[0] && gridCells[row][col1] !== lineSpecialCells[1]) { cellsToDestroy.push(gridCells[row][col1]); } } // Add cells from the activated special's row for (var col = 0; col < gridSize; col++) { // Add cells from row if (col !== col1 && gridCells[row1][col] && gridCells[row1][col] !== lineSpecialCells[0] && gridCells[row1][col] !== lineSpecialCells[1]) { cellsToDestroy.push(gridCells[row1][col]); } } // Mark special memes for destruction lineSpecialCells.forEach(function (specialMeme) { specialMeme.beingDestroyed = true; }); // Schedule destruction after the swap animation completes LK.setTimeout(function () { LK.getSound('Explosion').play(); // Destroy the collected cells if (cellsToDestroy.length > 0) { destroyCells(cellsToDestroy); } // Destroy the special memes lineSpecialCells.forEach(function (specialMeme) { LK.effects.flashObject(specialMeme, 0xFFFFFF, 200); gridContainer.removeChild(specialMeme); specialMeme.destroy(); gridCells[specialMeme.row][specialMeme.col] = null; }); }, 250); } // Check if greenSpecialCell was swapped with a line-clearing special meme or bomb else if (greenSpecialCell && regularCell) { // Check if regularCell is a line-clearing special meme if (regularCell.isSpecial && (regularCell.specialType === 'horizontal' || regularCell.specialType === 'vertical')) { var targetType = regularCell.value; var cellsToTransform = []; // Find all cells with the same type as the swapped line-clearing meme for (var row = extraRows; row < gridSize + extraRows; row++) { for (var col = 0; col < gridSize; col++) { var cell = gridCells[row][col]; if (cell && cell.value === targetType && cell !== greenSpecialCell && cell !== regularCell && !cell.isSpecial) { cellsToTransform.push(cell); } } } // Mark special memes for destruction greenSpecialCell.beingDestroyed = true; // Schedule transformation and activation after the swap animation completes LK.setTimeout(function () { LK.getSound('Explosion').play(); LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200); // Transform all cells of the same type into line-clearing memes cellsToTransform.forEach(function (cell) { cell.isSpecial = true; // Randomly assign horizontal or vertical cell.specialType = Math.random() < 0.5 ? 'horizontal' : 'vertical'; // Apply tint cell.sprite.tint = 0xFF8800; // Orange tint for line special memes LK.effects.flashObject(cell, 0xFFFFFF, 200); // Activate each special meme with a slight delay LK.setTimeout(function () { cell.activateSpecialPower(); }, 100 + Math.random() * 300); }); // Remove the green special meme gridContainer.removeChild(greenSpecialCell); greenSpecialCell.destroy(); gridCells[greenSpecialCell.row][greenSpecialCell.col] = null; // Activate the original line-clearing meme last LK.setTimeout(function () { regularCell.activateSpecialPower(); }, 500); }, 250); } else if (regularCell.isSpecial && regularCell.specialType === 'bomb') { // Green special + bomb special interaction var targetType = regularCell.value; var cellsToTransform = []; // Find all cells with the same type as the bomb meme for (var row = extraRows; row < gridSize + extraRows; row++) { for (var col = 0; col < gridSize; col++) { var cell = gridCells[row][col]; if (cell && cell.value === targetType && cell !== greenSpecialCell && cell !== regularCell && !cell.isSpecial) { cellsToTransform.push(cell); } } } // Mark green special meme for destruction greenSpecialCell.beingDestroyed = true; // Schedule transformation and activation after swap animation LK.setTimeout(function () { LK.getSound('Explosion').play(); LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200); // Transform all cells of same type into bomb memes cellsToTransform.forEach(function (cell) { cell.isSpecial = true; cell.specialType = 'bomb'; // Apply blue tint for bomb memes cell.sprite.tint = 0x0088FF; LK.effects.flashObject(cell, 0xFFFFFF, 200); // Activate each bomb with slight delay LK.setTimeout(function () { cell.activateSpecialPower(); }, 100 + Math.random() * 300); }); // Remove the green special meme gridContainer.removeChild(greenSpecialCell); greenSpecialCell.destroy(); gridCells[greenSpecialCell.row][greenSpecialCell.col] = null; // Activate the original bomb last LK.setTimeout(function () { regularCell.activateSpecialPower(); }, 500); }, 250); } else { var targetType = regularCell.value; var cellsToDestroy = []; // Find all cells with the same type as the swapped meme for (var row = extraRows; row < gridSize + extraRows; row++) { for (var col = 0; col < gridSize; col++) { var cell = gridCells[row][col]; if (cell && cell.value === targetType && cell !== greenSpecialCell) { cellsToDestroy.push(cell); } } } // Also destroy the green special meme itself greenSpecialCell.beingDestroyed = true; // Schedule destruction after the swap animation completes LK.setTimeout(function () { if (cellsToDestroy.length > 0) { LK.getSound('Explosion').play(); LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200); destroyCells(cellsToDestroy); gridContainer.removeChild(greenSpecialCell); greenSpecialCell.destroy(); gridCells[greenSpecialCell.row][greenSpecialCell.col] = null; } }, 250); } } tween(cell1, { x: pos2_x, y: pos2_y }, { duration: 200 }); tween(cell2, { x: pos1_x, y: pos1_y }, { duration: 200 }); selectedCell = null; LK.setTimeout(function () { checkForAndDestroyMatches(cell1, cell2); if (!window.destructionInProgress && !window.gravityInProgress && !window.fillInProgress) { isAnimating = false; } }, 250); } function getMatches() { var matches = []; function findDirectionalMatches(isHorizontal) { var primary, secondary; var primaryMax = isHorizontal ? gridSize + extraRows : gridSize; var secondaryMax = isHorizontal ? gridSize : gridSize + extraRows; for (primary = isHorizontal ? extraRows : 0; primary < primaryMax; primary++) { if (!gridCells[primary]) { continue; } for (secondary = 0; secondary < secondaryMax;) { if (secondary > secondaryMax - 3) { secondary++; continue; } var cell1 = isHorizontal ? gridCells[primary] ? gridCells[primary][secondary] : null : gridCells[secondary] ? gridCells[secondary][primary] : null; if (!cell1 || !cell1.value) { secondary++; continue; } var currentMatchValue = cell1.value; var currentMatchCells = [cell1]; for (var k = secondary + 1; k < secondaryMax; k++) { var nextCell = isHorizontal ? gridCells[primary] ? gridCells[primary][k] : null : gridCells[k] ? gridCells[k][primary] : null; if (nextCell && nextCell.value === currentMatchValue) { currentMatchCells.push(nextCell); } else { // If no new matches found, reset combo counter LK.setTimeout(function () { if (!window.gravityInProgress && !window.fillInProgress) { comboInProgress = false; comboCounter = 0; } }, 500); break; } } if (currentMatchCells.length >= 3) { var validCells = currentMatchCells.filter(function (cell) { return cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell; }); if (validCells.length >= 3) { var visibleCells = validCells.filter(function (cell) { return cell.row >= extraRows; }); var invisibleCells = validCells.filter(function (cell) { return cell.row < extraRows; }); // Either all cells are visible, or all cells are invisible, or there are at least 3 visible cells if (visibleCells.length === 0 || invisibleCells.length === 0 || visibleCells.length >= 3) { // Add isHorizontal and matchType to the match data validCells.isHorizontal = isHorizontal; validCells.matchType = currentMatchValue; matches.push(validCells); } } } secondary += currentMatchCells.length > 0 ? currentMatchCells.length : 1; } } } findDirectionalMatches(true); findDirectionalMatches(false); return matches; } function destroyCells(cellsToDestroy) { isAnimating = true; // Create a unique ID for this destruction process var destructionId = Date.now() + Math.random(); // Check if match crosses visible/invisible boundary var visibleCells = cellsToDestroy.filter(function (cell) { return cell.row >= extraRows; }); var invisibleCells = cellsToDestroy.filter(function (cell) { return cell.row < extraRows; }); // If mixed visibility and only one cell is visible, don't destroy any if (visibleCells.length > 0 && invisibleCells.length > 0 && (visibleCells.length === 1 || invisibleCells.length === 1)) { isAnimating = false; return; } // Calculate points for destroyed cells - only count visible cells var basePoints = visibleCells.length * 10; var visibleCellsToDestroy = cellsToDestroy.filter(function (cell) { return cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell; }); // Reset timer in Fast mode when cells are destroyed if (game.gameMode === 'fast' && game.timer && visibleCellsToDestroy.length > 0) { game.timer.reset(); } // Find the center cell (the one that triggered the match) var centerCell = null; // If we have the cells from a swap, use one of those as the center if (arguments.length > 1 && arguments[1]) { centerCell = arguments[1]; } else if (cellsToDestroy.length > 0) { // Otherwise use the middle cell of the match centerCell = cellsToDestroy[Math.floor(cellsToDestroy.length / 2)]; } // Group cells by meme type var cellsByType = {}; visibleCellsToDestroy.forEach(function (cell) { if (!cellsByType[cell.value]) { cellsByType[cell.value] = []; } cellsByType[cell.value].push(cell); }); // Count unique groups for combo sound var uniqueGroupCount = Object.keys(cellsByType).length; if (uniqueGroupCount > 0) { // Increment combo counter only if this is part of a continuous combo if (!comboInProgress) { comboCounter = uniqueGroupCount; comboInProgress = true; } else { comboCounter += uniqueGroupCount; } // Calculate score multiplier based on combo count var comboMultiplier = 1; if (comboCounter >= 9) { comboMultiplier = 5; } else if (comboCounter >= 6) { comboMultiplier = 4; } else if (comboCounter >= 4) { comboMultiplier = 3; } else if (comboCounter >= 3) { comboMultiplier = 2; } else if (comboCounter >= 2) { comboMultiplier = 1.5; } // Award points with combo multiplier var pointsToAdd = Math.floor(basePoints * comboMultiplier); updateScore(pointsToAdd); // Show floating score text at center cell if available if (centerCell && centerCell.row >= extraRows) { var scorePopup = new Text2("+" + pointsToAdd, { size: 60, fill: 0xFF8800 }); scorePopup.anchor.set(0.5, 0.5); scorePopup.x = centerCell.x; scorePopup.y = centerCell.y; game.addChild(scorePopup); // Animate score popup tween(scorePopup, { y: scorePopup.y - 80, alpha: 0 }, { duration: 800, onComplete: function onComplete() { game.removeChild(scorePopup); scorePopup.destroy(); } }); } // Stop any currently playing combo sounds before playing a new one LK.getSound('Combo1').stop(); LK.getSound('Combo2').stop(); LK.getSound('Combo3').stop(); LK.getSound('Combo4').stop(); LK.getSound('Combo5').stop(); if (comboCounter >= 9) { LK.getSound('Combo5').play(); } else if (comboCounter >= 6) { LK.getSound('Combo4').play(); } else if (comboCounter >= 4) { LK.getSound('Combo3').play(); } else if (comboCounter >= 3) { LK.getSound('Combo2').play(); } else if (comboCounter >= 2) { LK.getSound('Combo1').play(); } } var specialCell = null; var isHorizontalMatch = false; var isVerticalMatch = false; for (var type in cellsByType) { var typeCells = cellsByType[type]; if (typeCells.length >= 6) { // Create green special meme for 6 or more matches if (centerCell && centerCell.value === parseInt(type)) { specialCell = centerCell; } else { specialCell = typeCells[0]; } specialCell.isSpecial = true; specialCell.specialType = 'green'; specialCell.beingDestroyed = false; // Award bonus points for creating a green special meme updateScore(100); // Remove special cell from cells to destroy visibleCellsToDestroy = visibleCellsToDestroy.filter(function (cell) { return cell !== specialCell; }); break; // Only create one special meme } else if (typeCells.length === 5) { // Create bomb special meme (blue) if (centerCell && centerCell.value === parseInt(type)) { specialCell = centerCell; } else { specialCell = typeCells[0]; } specialCell.isSpecial = true; specialCell.specialType = 'bomb'; specialCell.beingDestroyed = false; // Award bonus points for creating a bomb special meme updateScore(75); // Remove special cell from cells to destroy visibleCellsToDestroy = visibleCellsToDestroy.filter(function (cell) { return cell !== specialCell; }); break; // Only create one special meme } else if (typeCells.length === 4) { // Determine if match is horizontal or vertical var allInSameRow = true; var allInSameCol = true; var firstCell = typeCells[0]; for (var i = 1; i < typeCells.length; i++) { if (typeCells[i].row !== firstCell.row) { allInSameRow = false; } if (typeCells[i].col !== firstCell.col) { allInSameCol = false; } } isHorizontalMatch = allInSameRow; isVerticalMatch = allInSameCol; // Create special meme only if it's a clean horizontal or vertical match if (isHorizontalMatch || isVerticalMatch) { // Use center cell if it matches the type, otherwise use the first cell of this type if (centerCell && centerCell.value === parseInt(type)) { specialCell = centerCell; } else { specialCell = typeCells[0]; } specialCell.isSpecial = true; specialCell.specialType = isHorizontalMatch ? 'horizontal' : 'vertical'; specialCell.beingDestroyed = false; // Award bonus points for creating a line-clearing special meme updateScore(50); // Remove special cell from cells to destroy visibleCellsToDestroy = visibleCellsToDestroy.filter(function (cell) { return cell !== specialCell; }); break; // Only create one special meme } } } // Sort cells by distance from center cell for ripple effect if (centerCell && visibleCellsToDestroy.length > 0) { visibleCellsToDestroy.sort(function (a, b) { var distA = Math.abs(a.row - centerCell.row) + Math.abs(a.col - centerCell.col); var distB = Math.abs(b.row - centerCell.row) + Math.abs(b.col - centerCell.col); return distA - distB; }); } var delay = 0; var delayIncrement = 50; var totalDestructionTime = visibleCellsToDestroy.length * delayIncrement; // Mark cells as being destroyed to prevent them from being part of new matches visibleCellsToDestroy.forEach(function (cell) { if (cell) { cell.beingDestroyed = true; // Check if any of these cells are matched with a special meme if (cell.isSpecial) { // Special meme is being destroyed, activate its power LK.setTimeout(function () { cell.activateSpecialPower(); }, 100); } } }); // If we have a special meme, apply the appropriate tint if (specialCell && specialCell.isSpecial) { if (specialCell.specialType === 'bomb') { specialCell.sprite.tint = 0x0088FF; // Blue tint for bomb } else if (specialCell.specialType === 'green') { specialCell.sprite.tint = 0x00FF00; // Green tint for swap-destroy special meme } else { specialCell.sprite.tint = 0xFF8800; // Orange tint for others } LK.effects.flashObject(specialCell, 0xFFFFFF, 300); } visibleCellsToDestroy.forEach(function (cell) { LK.setTimeout(function () { if (cell && cell.beingDestroyed && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) { LK.getSound('Explosion').play(); LK.effects.flashObject(cell, 0xFFFFFF, 200); gridContainer.removeChild(cell); cell.destroy(); gridCells[cell.row][cell.col] = null; } }, delay); delay += delayIncrement; }); // After all cells in this group are destroyed, check if we need to apply gravity LK.setTimeout(function () { // Check if all destructions are complete before applying gravity var allCellsDestroyed = true; for (var r = 0; r < gridSize + extraRows; r++) { for (var c = 0; c < gridSize; c++) { if (gridCells[r] && gridCells[r][c] && gridCells[r][c].beingDestroyed) { allCellsDestroyed = false; } } } // Only the last destruction process should trigger gravity if (allCellsDestroyed && !window.gravityInProgress && !window.fillInProgress) { applyGravity(); } }, totalDestructionTime + 50); } function applyGravity() { isAnimating = true; var cellsToFall = []; if (window.gravityInProgress) { return; } window.gravityInProgress = true; for (var col = 0; col < gridSize; col++) { for (var row = gridSize + extraRows - 1; row >= extraRows; row--) { if (!gridCells[row][col]) { var sourceRow = row - 1; while (sourceRow >= 0 && !gridCells[sourceRow][col]) { sourceRow--; } if (sourceRow >= 0) { var cellToMove = gridCells[sourceRow][col]; if (cellToMove) { cellsToFall.push({ cell: cellToMove, fromRow: sourceRow, toRow: row, col: col }); gridCells[row][col] = cellToMove; gridCells[sourceRow][col] = null; cellToMove.row = row; if (sourceRow < extraRows) { gridContainer.addChild(cellToMove); } } } } } } var longestDelay = 0; var baseDelay = 15; var constantDuration = 250; cellsToFall.sort(function (a, b) { if (a.col !== b.col) { return a.col - b.col; } return b.toRow - a.toRow; }); cellsToFall.forEach(function (fallInfo, index) { var delay = index * baseDelay; var newPos = getCellPosition(fallInfo.toRow, fallInfo.col); var totalTime = delay + constantDuration; if (totalTime > longestDelay) { longestDelay = totalTime; } LK.setTimeout(function () { if (fallInfo.cell && gridCells[fallInfo.cell.row] && gridCells[fallInfo.cell.row][fallInfo.cell.col] === fallInfo.cell) { tween(fallInfo.cell, { y: newPos.y }, { duration: constantDuration, easing: tween.linear }); } }, delay); }); LK.setTimeout(function () { window.gravityInProgress = false; if (!window.destructionInProgress) { fillEmptySpacesWithNewMemes(); } }, longestDelay + 50); } function fillEmptySpacesWithNewMemes() { if (window.fillInProgress || window.gravityInProgress) { return; } window.fillInProgress = true; var anyNewMemeAdded = false; var newCellsToAdd = []; for (var col = 0; col < gridSize; col++) { for (var row = 0; row < gridSize + extraRows; row++) { if (!gridCells[row][col]) { anyNewMemeAdded = true; var newCell = getGridCell(); var pos = getCellPosition(row, col); newCell.x = pos.x; newCell.y = pos.y - 400; var randomValue = Math.floor(Math.random() * 5) + 1; newCell.setValue(randomValue); newCell.row = row; newCell.col = col; gridCells[row][col] = newCell; newCellsToAdd.push({ cell: newCell, destY: pos.y, row: row, col: col }); if (row >= extraRows) { gridContainer.addChild(newCell); } } } } var longestDelay = 0; var baseDelay = 15; var constantDuration = 250; newCellsToAdd.sort(function (a, b) { if (a.col !== b.col) { return a.col - b.col; } return b.row - a.row; }); newCellsToAdd.forEach(function (cellData, index) { var delay = index * baseDelay; var totalTime = delay + constantDuration; if (totalTime > longestDelay) { longestDelay = totalTime; } LK.setTimeout(function () { if (cellData.cell && gridCells[cellData.row] && gridCells[cellData.row][cellData.col] === cellData.cell) { tween(cellData.cell, { y: cellData.destY }, { duration: constantDuration, easing: tween.linear }); } }, delay); }); if (anyNewMemeAdded) { LK.setTimeout(function () { window.fillInProgress = false; if (window.destructionInProgress || window.gravityInProgress) { isAnimating = false; return; } var visibleMatchGroups = getMatches().filter(function (group) { // Check if the match has cells in both visible and invisible areas var visibleCells = group.filter(function (cell) { return cell.row >= extraRows; }); var invisibleCells = group.filter(function (cell) { return cell.row < extraRows; }); // Don't count groups with both visible and invisible cells unless there are at least 3 visible cells if (visibleCells.length > 0 && invisibleCells.length > 0 && visibleCells.length < 3) { return false; } return visibleCells.length >= 3; // At least 3 visible cells make a valid visible match }); var newMatches = visibleMatchGroups; if (newMatches.length > 0) { // Group by meme type var matchesByType = {}; newMatches.forEach(function (group) { if (group.length > 0) { var type = group[0].value; if (!matchesByType[type]) { matchesByType[type] = []; } matchesByType[type].push(group); } }); var newCellsToDestroy = []; var newCellTracker = {}; // Process each type separately for (var type in matchesByType) { var typeGroups = matchesByType[type]; // Find a central cell for this type var centerCell = null; if (typeGroups.length > 0 && typeGroups[0].length > 0) { // Pick the center of the first match group of this type var matchGroup = typeGroups[0]; centerCell = matchGroup[Math.floor(matchGroup.length / 2)]; } // Collect all cells of this type var typeCells = []; typeGroups.forEach(function (group) { group.forEach(function (cell) { var cellKey = cell.row + "_" + cell.col; if (!newCellTracker[cellKey] && cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) { typeCells.push(cell); newCellTracker[cellKey] = true; } }); }); // Destroy cells of this type if (typeCells.length) { destroyCells(typeCells, centerCell); } } if (Object.keys(matchesByType).length === 0) { isAnimating = false; } } else { isAnimating = false; } }, longestDelay + 50); } else { window.fillInProgress = false; isAnimating = false; // Reset combo tracking when no more matches are being created comboInProgress = false; comboCounter = 0; } } // Handle game over events to return to menu game.onGameOver = function () { LK.setTimeout(function () { // Clear the game board while (gridContainer.children.length > 0) { var child = gridContainer.children[0]; gridContainer.removeChild(child); child.destroy(); } if (scoreText) { game.removeChild(scoreText); scoreText = null; } // Show menu initializeMenu(); }, 500); }; function checkForAndDestroyMatches(swappedCellA, swappedCellB) { if (window.gravityInProgress || window.fillInProgress) { return; } var allMatchGroupsOnBoard = getMatches(); if (!allMatchGroupsOnBoard.length) { // In Classic Mode, if no matches are found after a swap, revert the swap if (game.gameMode === 'classic' && swappedCellA && swappedCellB) { // Get original positions var pos1_x = swappedCellA.x; var pos1_y = swappedCellA.y; var pos2_x = swappedCellB.x; var pos2_y = swappedCellB.y; var row1 = swappedCellA.row; var col1 = swappedCellA.col; var row2 = swappedCellB.row; var col2 = swappedCellB.col; // Swap back in grid data gridCells[row1][col1] = swappedCellA; gridCells[row2][col2] = swappedCellB; swappedCellA.row = row1; swappedCellA.col = col1; swappedCellB.row = row2; swappedCellB.col = col2; // Animate swap back tween(swappedCellA, { x: pos2_x, y: pos2_y }, { duration: 200 }); tween(swappedCellB, { x: pos1_x, y: pos1_y }, { duration: 200, onComplete: function onComplete() { isAnimating = false; } }); } return; } var relevantMatchGroups = allMatchGroupsOnBoard.filter(function (group) { // Check if the match has cells in both visible and invisible areas var visibleCells = group.filter(function (cell) { return cell.row >= extraRows; }); var invisibleCells = group.filter(function (cell) { return cell.row < extraRows; }); // Don't count groups with both visible and invisible cells unless there are at least 3 visible cells if (visibleCells.length > 0 && invisibleCells.length > 0 && visibleCells.length < 3) { return false; } return group.some(function (cellInGroup) { return (cellInGroup === swappedCellA || cellInGroup === swappedCellB) && cellInGroup.row >= extraRows; }); }); if (!relevantMatchGroups.length) { // In Classic Mode, if matches exist but none involve the swapped cells, revert the swap if (game.gameMode === 'classic' && swappedCellA && swappedCellB) { // Get original positions var pos1_x = swappedCellA.x; var pos1_y = swappedCellA.y; var pos2_x = swappedCellB.x; var pos2_y = swappedCellB.y; var row1 = swappedCellA.row; var col1 = swappedCellA.col; var row2 = swappedCellB.row; var col2 = swappedCellB.col; // Swap back in grid data gridCells[row1][col1] = swappedCellA; gridCells[row2][col2] = swappedCellB; swappedCellA.row = row1; swappedCellA.col = col1; swappedCellB.row = row2; swappedCellB.col = col2; // Animate swap back tween(swappedCellA, { x: pos2_x, y: pos2_y }, { duration: 200 }); tween(swappedCellB, { x: pos1_x, y: pos1_y }, { duration: 200, onComplete: function onComplete() { isAnimating = false; } }); } return; } // Group by meme type var matchesByType = {}; relevantMatchGroups.forEach(function (group) { if (group.length > 0) { var type = group[0].value; if (!matchesByType[type]) { matchesByType[type] = []; } matchesByType[type].push(group); } }); var uniqueCellTracker = {}; var cellsToDestroy = []; // Process each type separately for (var type in matchesByType) { var typeGroups = matchesByType[type]; // Flatten all groups of this type var typeCells = []; typeGroups.forEach(function (group) { group.forEach(function (cell) { if (cell.row >= extraRows) { typeCells.push(cell); } }); }); // Add each cell of this type to cellsToDestroy typeCells.forEach(function (cell) { var cellKey = cell.row + "_" + cell.col; if (!uniqueCellTracker[cellKey] && cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) { cellsToDestroy.push(cell); uniqueCellTracker[cellKey] = true; } }); } ; if (cellsToDestroy.length) { // Pass the swapped cell that created the match as the center for the ripple effect var centerCell = swappedCellA && relevantMatchGroups.some(function (group) { return group.includes(swappedCellA); }) ? swappedCellA : swappedCellB; destroyCells(cellsToDestroy, centerCell); LK.setTimeout(function () { if (window.gravityInProgress || window.fillInProgress) { return; } var visibleMatchGroups = getMatches().filter(function (group) { // Check if the match has cells in both visible and invisible areas var visibleCells = group.filter(function (cell) { return cell.row >= extraRows; }); var invisibleCells = group.filter(function (cell) { return cell.row < extraRows; }); // Don't count groups with both visible and invisible cells unless there are at least 3 visible cells if (visibleCells.length > 0 && invisibleCells.length > 0 && visibleCells.length < 3) { return false; } return visibleCells.length >= 3; // At least 3 visible cells make a valid visible match }); var newMatches = visibleMatchGroups; if (newMatches.length > 0) { // Group by meme type var matchesByType = {}; newMatches.forEach(function (group) { if (group.length > 0) { var type = group[0].value; if (!matchesByType[type]) { matchesByType[type] = []; } matchesByType[type].push(group); } }); // Process each type separately for (var type in matchesByType) { var typeGroups = matchesByType[type]; var newCellsToDestroy = []; var newCellTracker = {}; // Collect all cells of this type typeGroups.forEach(function (group) { group.forEach(function (cell) { var cellKey = cell.row + "_" + cell.col; if (!newCellTracker[cellKey] && cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) { newCellsToDestroy.push(cell); newCellTracker[cellKey] = true; } }); }); if (newCellsToDestroy.length) { // Find center cell of this type var centerCell = newCellsToDestroy[Math.floor(newCellsToDestroy.length / 2)]; destroyCells(newCellsToDestroy, centerCell); } } } }, 400); } } var gridSize = 8; var extraRows = 9; var cellSpacing = 10; var cellSize = 208; var gridCells = []; var totalGridWidth = gridSize * cellSize + (gridSize - 1) * cellSpacing; var totalVisibleGridHeight = totalGridWidth; var totalGridHeight = totalVisibleGridHeight + extraRows * (cellSize + cellSpacing); var startX = (2048 - totalGridWidth) / 2 + cellSize / 2; var startY = (-1300 - totalVisibleGridHeight) / 2 + cellSize / 2 + extraRows * (cellSize + cellSpacing); function getCellPosition(row, col) { return { x: startX + col * (cellSize + cellSpacing), y: startY + row * (cellSize + cellSpacing) - extraRows * (cellSize + cellSpacing) }; } function initializeGrid() { gridCells = []; for (var row = 0; row < gridSize + extraRows; row++) { gridCells[row] = []; for (var col = 0; col < gridSize; col++) { var pos = getCellPosition(row, col); var cell = getGridCell ? getGridCell() : new GridCell(); cell.x = pos.x; cell.y = pos.y; cell.row = row; cell.col = col; var randomValue; var attempts = 0; do { randomValue = Math.floor(Math.random() * 5) + 1; attempts++; var leftMatchCount = 0; var aboveMatchCount = 0; if (col >= 2) { if (gridCells[row][col - 1].value === randomValue && gridCells[row][col - 2].value === randomValue) { leftMatchCount = 2; } } if (row >= 2) { if (gridCells[row - 1][col].value === randomValue && gridCells[row - 2][col].value === randomValue) { aboveMatchCount = 2; } } } while ((leftMatchCount >= 2 || aboveMatchCount >= 2) && attempts < 10); cell.setValue(randomValue); if (row >= extraRows) { gridContainer.addChild(cell); } gridCells[row][col] = cell; } } } // Initialize menu instead of directly starting the game initializeMenu(); function ensureNoInitialMatches() { var matches = getMatches(); if (matches.length > 0) { matches.forEach(function (group) { group.forEach(function (cell) { var currentValue = cell.value; var newValue; do { newValue = Math.floor(Math.random() * 5) + 1; } while (newValue === currentValue); cell.setValue(newValue); }); }); ensureNoInitialMatches(); } } ensureNoInitialMatches();
===================================================================
--- original.js
+++ change.js
@@ -347,13 +347,13 @@
duration: 100
});
};
// Update method called every frame
- self.update = function () {
+ self.update = function (deltaTime) {
if (!self.active) return;
- // Use LK.deltaTime instead of assuming fixed framerate
- // deltaTime is in milliseconds, convert to seconds
- self.currentTime -= 1 / 60 * (1000 / 16.67); // Normalize to 60fps equivalent
+ // Use deltaTime for accurate timing regardless of frame rate
+ var seconds = deltaTime ? deltaTime / 1000 : 1 / 60;
+ self.currentTime -= seconds;
// Check if we crossed a whole second boundary for display update
var currentWholeSecond = Math.ceil(self.currentTime);
if (currentWholeSecond !== self.lastWholeSecond) {
self.lastWholeSecond = currentWholeSecond;
@@ -447,12 +447,12 @@
// Initialize the game grid
initializeGrid();
ensureNoInitialMatches();
// Main game update loop
- game.update = function () {
+ game.update = function (deltaTime) {
// Update timer in Fast mode
if (game.gameMode === 'fast' && game.timer) {
- game.timer.update();
+ game.timer.update(deltaTime);
}
};
gameInitialized = true;
};
la figura de una casa color blanca simple para una interfaz. In-Game asset. 2d. High contrast. No shadows
haz el fondo color morado
circular check logo. In-Game asset. 2d. High contrast. No shadows
Cuadrado con los bordes redondeado negro. In-Game asset. 2d. High contrast. No shadows
hazlo un gris claro
Que sea blanco
Que sea blanco