User prompt
haz que el juego sea más dinamico disminuyendo el tiempo de caida y diley de roptura
User prompt
mejora la logica de caida
User prompt
arregla la caida de los memes despues de usar habilidades especiales
User prompt
crea un sistema de puntos
User prompt
Please fix the bug: 'Timeout.tick error: isValidCell is not defined' in or related to this line: 'if (isValidCell(fallInfo.cell)) {' Line Number: 810
User prompt
arregla la caida de los memes para evitar errores de atravesar memes, etc
User prompt
arregla la caída para evitar errores de mmes atravesando otros memes, etc
User prompt
Mejora las lineas de codigo utilizando metodos mas optimizados y ordenados
User prompt
arregla la caida por gravedad cuando se usa habilidades
User prompt
Please fix the bug: 'Timeout.tick error: isValidCell is not defined' in or related to this line: 'if (isValidCell(fallInfo.cell)) {' Line Number: 810
User prompt
Mejora las lineas de codigo utilizando metodos mas optimizados y ordenados
Code edit (3 edits merged)
Please save this source code
User prompt
elimina el diley de roptura
User prompt
si empieza un nuevo sonido de combo que el anterior se corte
Code edit (3 edits merged)
Please save this source code
User prompt
Si se mueve depende cuantos grupos se rompen empezaran a sonar sonidos de combo (2 grupos combo 1 / 3 grupos combo 2 / 4 combos etc ...)
Code edit (1 edits merged)
Please save this source code
User prompt
mejora la mecanica para que cualquier giro se regrese despues de gastar los movimientos libres
User prompt
haz que se puedan mover los memes libremente hasta 2 veces, si en la tercera no se rompe nada el meme regresara a su posición anterior
User prompt
Agrega animaciones ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
dale vida al proyecto con animaciones ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
haz que todos los memes sean especiales verde
User prompt
si se cambia de posición 2 memes especiales verde se activa una habilidad especial que rompe todos los memes visibles
User prompt
si se cambia de posición un meme especial verde con un bomb transformara todos los memes de ese tipo en bomb y consecutivamente activarlos
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GridCell = Container.expand(function () {
var self = Container.call(this);
// Define the special cell tint colors as constants
var BOMB_TINT = 0x0088FF;
var GREEN_TINT = 0x00FF00;
var LINE_TINT = 0xFF8800;
var SELECTION_TINT = 0x00FFFF;
// Initialize method with improved structure
self.init = function () {
// Create background only if it doesn't exist
if (!self.background) {
self.background = self.attachAsset('cuadricula', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Reset all properties to default values
self.value = 0;
self.sprite = null;
self.row = -1;
self.col = -1;
self.isSpecial = false;
self.specialType = null;
self.beingDestroyed = false;
self.lastIntersecting = false;
return self;
};
// Set value with improved appearance handling
self.setValue = function (newValue) {
// Skip if value hasn't changed
if (self.value === newValue) {
return;
}
// Update value
self.value = newValue;
// Remove existing sprite
if (self.sprite) {
self.removeChild(self.sprite);
}
// Create new sprite
var spriteId = 'meme' + newValue;
self.sprite = LK.getAsset(spriteId, {
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.sprite);
// Apply special effects if needed
self.updateAppearance();
};
// New helper method to update appearance based on special state
self.updateAppearance = function () {
if (!self.sprite) return;
// Reset tint first
self.sprite.tint = 0xFFFFFF;
// Apply special tint if needed
if (self.isSpecial) {
if (self.specialType === 'bomb') {
self.sprite.tint = BOMB_TINT;
} else if (self.specialType === 'green') {
self.sprite.tint = GREEN_TINT;
} else {
self.sprite.tint = LINE_TINT;
}
}
};
// Activate special power with improved efficiency
self.activateSpecialPower = function () {
if (!self.isSpecial) {
return;
}
var cellsToDestroy = [];
// Collect cells based on special type
if (self.specialType === 'horizontal') {
// Destroy all cells in the same row
for (var row = extraRows; row < gridSize + extraRows; row++) {
if (gridCells[row][self.col] && gridCells[row][self.col] !== self) {
cellsToDestroy.push(gridCells[row][self.col]);
}
}
} else if (self.specialType === 'vertical') {
// Destroy all cells in the same column
for (var col = 0; col < gridSize; col++) {
if (gridCells[self.row][col] && gridCells[self.row][col] !== self) {
cellsToDestroy.push(gridCells[self.row][col]);
}
}
} else if (self.specialType === 'bomb') {
// Destroy cells in a 3x3 area
var minRow = Math.max(extraRows, self.row - 1);
var maxRow = Math.min(gridSize + extraRows - 1, self.row + 1);
var minCol = Math.max(0, self.col - 1);
var maxCol = Math.min(gridSize - 1, self.col + 1);
for (var row = minRow; row <= maxRow; row++) {
for (var col = minCol; col <= maxCol; col++) {
if (gridCells[row][col] && gridCells[row][col] !== self) {
cellsToDestroy.push(gridCells[row][col]);
}
}
}
} else if (self.specialType === 'green') {
// Green special power is handled elsewhere
}
// Process destruction if we have cells to destroy
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
self.beingDestroyed = true;
LK.getSound('Explosion').play();
LK.effects.flashObject(self, 0xFFFFFF, 200);
gridContainer.removeChild(self);
self.destroy();
gridCells[self.row][self.col] = null;
}
};
// Show selection with improved animation
self.showSelection = function () {
if (self.selectionHighlight) {
return;
}
// Create selection container
self.selectionHighlight = new Container();
var highlight = LK.getAsset('cuadricula', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.15,
scaleY: 1.15,
alpha: 0.6
});
highlight.tint = SELECTION_TINT;
self.selectionHighlight.addChild(highlight);
self.addChildAt(self.selectionHighlight, 0);
// Define pulse 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
});
}
});
}
// Start animation
pulseAnimation();
};
// Hide selection with efficient cleanup
self.hideSelection = function () {
if (self.selectionHighlight) {
self.removeChild(self.selectionHighlight);
self.selectionHighlight = null;
}
};
// Handle tap/click events
self.down = function (x, y, obj) {
handleCellTap(self);
};
// Initialize on creation
self.init();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xF4FFFF
});
/****
* Game Code
****/
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;
window.destructionInProgress = false;
var comboCounter = 0;
var comboInProgress = false;
function handleCellTap(tappedCell) {
// Exit early if animations are in progress
if (isAnimating || window.gravityInProgress || window.fillInProgress) {
return;
}
// Validate tapped cell
if (!tappedCell || !gridCells[tappedCell.row] || gridCells[tappedCell.row][tappedCell.col] !== tappedCell || tappedCell.beingDestroyed) {
return;
}
// Handle first selection
if (selectedCell === null) {
selectedCell = tappedCell;
selectedCell.showSelection();
return;
}
// Validate selected cell still exists
if (!gridCells[selectedCell.row] || gridCells[selectedCell.row][selectedCell.col] !== selectedCell) {
// Selected cell no longer valid, use tapped cell instead
if (selectedCell) {
selectedCell.hideSelection();
}
selectedCell = tappedCell;
selectedCell.showSelection();
return;
}
// Handle tap on already selected cell (deselect)
if (selectedCell === tappedCell) {
selectedCell.hideSelection();
selectedCell = null;
return;
}
// Check if cells are 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 not adjacent, select the new cell instead
if (!isAdjacent) {
selectedCell.hideSelection();
selectedCell = tappedCell;
selectedCell.showSelection();
return;
}
// Set up cell swap
var cell1 = selectedCell;
var cell2 = tappedCell;
// Clear selection
cell1.hideSelection();
selectedCell = null;
// Begin swap animation
isAnimating = true;
// Store original positions for animation
var pos1_x = cell1.x;
var pos1_y = cell1.y;
var pos2_x = cell2.x;
var pos2_y = cell2.y;
// Store grid positions
var row1 = cell1.row;
var col1 = cell1.col;
var row2 = cell2.row;
var col2 = cell2.col;
// Categorize special cell interactions
var greenSpecialCell = null;
var regularCell = null;
var lineSpecialCells = [];
var twoGreenSpecials = false;
// Check for green special interactions
if (cell1.isSpecial && cell1.specialType === 'green' && cell2.isSpecial && cell2.specialType === 'green') {
twoGreenSpecials = true;
} 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 special interactions
if (cell1.isSpecial && (cell1.specialType === 'horizontal' || cell1.specialType === 'vertical')) {
lineSpecialCells.push(cell1);
}
if (cell2.isSpecial && (cell2.specialType === 'horizontal' || cell2.specialType === 'vertical')) {
lineSpecialCells.push(cell2);
}
// Update grid references
gridCells[row1][col1] = cell2;
gridCells[row2][col2] = cell1;
cell1.row = row2;
cell1.col = col2;
cell2.row = row1;
cell2.col = col1;
// Hide any remaining selection highlights
if (cell1.selectionHighlight) {
cell1.hideSelection();
}
if (cell2.selectionHighlight) {
cell2.hideSelection();
}
if (twoGreenSpecials) {
var cellsToDestroy = [];
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]);
}
}
}
cell1.beingDestroyed = true;
cell2.beingDestroyed = true;
LK.setTimeout(function () {
LK.getSound('Explosion').play();
LK.effects.flashScreen(0x00FF00, 500);
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
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;
}, 350);
} else if (cell1.isSpecial && cell1.specialType === 'bomb' && cell2.isSpecial && cell2.specialType === 'bomb') {
var cellsToDestroy = [];
var activatedCell = cell1;
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]);
}
}
}
cell1.beingDestroyed = true;
cell2.beingDestroyed = true;
LK.setTimeout(function () {
LK.getSound('Explosion').play();
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
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;
}, 350);
} 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')) {
var bombCell = cell1.specialType === 'bomb' ? cell1 : cell2;
var lineCell = cell1.specialType === 'horizontal' || cell1.specialType === 'vertical' ? cell1 : cell2;
var cellsToDestroy = [];
var affectedRows = [];
var activatedCell = cell1;
if (lineCell.specialType === 'horizontal') {
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 {
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]);
}
}
}
}
bombCell.beingDestroyed = true;
lineCell.beingDestroyed = true;
LK.setTimeout(function () {
LK.getSound('Explosion').play();
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
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;
}, 350);
} else if (lineSpecialCells.length === 2) {
var cellsToDestroy = [];
var row1, col1, row2, col2;
var activatedSpecial;
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;
}
for (var row = extraRows; row < gridSize + extraRows; row++) {
if (gridCells[row][col1] && gridCells[row][col1] !== lineSpecialCells[0] && gridCells[row][col1] !== lineSpecialCells[1]) {
cellsToDestroy.push(gridCells[row][col1]);
}
}
for (var col = 0; col < gridSize; col++) {
if (col !== col1 && gridCells[row1][col] && gridCells[row1][col] !== lineSpecialCells[0] && gridCells[row1][col] !== lineSpecialCells[1]) {
cellsToDestroy.push(gridCells[row1][col]);
}
}
lineSpecialCells.forEach(function (specialMeme) {
specialMeme.beingDestroyed = true;
});
LK.setTimeout(function () {
LK.getSound('Explosion').play();
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
lineSpecialCells.forEach(function (specialMeme) {
LK.effects.flashObject(specialMeme, 0xFFFFFF, 200);
gridContainer.removeChild(specialMeme);
specialMeme.destroy();
gridCells[specialMeme.row][specialMeme.col] = null;
});
}, 350);
} else if (greenSpecialCell && regularCell) {
if (regularCell.isSpecial && (regularCell.specialType === 'horizontal' || regularCell.specialType === 'vertical')) {
var targetType = regularCell.value;
var cellsToTransform = [];
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);
}
}
}
greenSpecialCell.beingDestroyed = true;
LK.setTimeout(function () {
LK.getSound('Explosion').play();
LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200);
cellsToTransform.forEach(function (cell) {
cell.isSpecial = true;
cell.specialType = Math.random() < 0.5 ? 'horizontal' : 'vertical';
cell.sprite.tint = 0xFF8800;
LK.effects.flashObject(cell, 0xFFFFFF, 200);
LK.setTimeout(function () {
cell.activateSpecialPower();
}, 100 + Math.random() * 300);
});
gridContainer.removeChild(greenSpecialCell);
greenSpecialCell.destroy();
gridCells[greenSpecialCell.row][greenSpecialCell.col] = null;
LK.setTimeout(function () {
regularCell.activateSpecialPower();
}, 500);
}, 350);
} else if (regularCell.isSpecial && regularCell.specialType === 'bomb') {
var targetType = regularCell.value;
var cellsToTransform = [];
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);
}
}
}
greenSpecialCell.beingDestroyed = true;
LK.setTimeout(function () {
LK.getSound('Explosion').play();
LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200);
cellsToTransform.forEach(function (cell) {
cell.isSpecial = true;
cell.specialType = 'bomb';
cell.sprite.tint = 0x0088FF;
LK.effects.flashObject(cell, 0xFFFFFF, 200);
LK.setTimeout(function () {
cell.activateSpecialPower();
}, 100 + Math.random() * 300);
});
gridContainer.removeChild(greenSpecialCell);
greenSpecialCell.destroy();
gridCells[greenSpecialCell.row][greenSpecialCell.col] = null;
LK.setTimeout(function () {
regularCell.activateSpecialPower();
}, 500);
}, 350);
} else {
var targetType = regularCell.value;
var cellsToDestroy = [];
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);
}
}
}
greenSpecialCell.beingDestroyed = true;
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;
}
}, 350);
}
}
tween(cell1, {
x: pos2_x,
y: pos2_y
}, {
duration: 300
});
tween(cell2, {
x: pos1_x,
y: pos1_y
}, {
duration: 300
});
selectedCell = null;
LK.setTimeout(function () {
checkForAndDestroyMatches(cell1, cell2);
if (!window.destructionInProgress && !window.gravityInProgress && !window.fillInProgress) {
isAnimating = false;
}
}, 350);
}
function getMatches() {
var matches = [];
// Optimized function to find matches in either horizontal or vertical direction
function findDirectionalMatches(isHorizontal) {
var primaryCount = isHorizontal ? gridSize + extraRows : gridSize;
var secondaryCount = isHorizontal ? gridSize : gridSize + extraRows;
// Loop through primary dimension (rows or columns)
for (var primary = isHorizontal ? 0 : 0; primary < primaryCount; primary++) {
if (!gridCells[primary] && isHorizontal) {
continue;
}
// Track current match sequence
var currentValue = -1;
var matchStart = 0;
var matchLength = 0;
// Scan through secondary dimension
for (var secondary = 0; secondary <= secondaryCount; secondary++) {
// Get current cell or null if beyond grid or at end of scan
var currentCell = null;
if (secondary < secondaryCount) {
currentCell = isHorizontal ? gridCells[primary] ? gridCells[primary][secondary] : null : gridCells[secondary] ? gridCells[secondary][primary] : null;
}
// Check if current cell continues the match
if (currentCell && currentCell.value && currentCell.value === currentValue) {
matchLength++;
} else {
// Process completed match if long enough
if (matchLength >= 3) {
var matchCells = [];
// Collect all cells in the match
for (var i = 0; i < matchLength; i++) {
var cell = isHorizontal ? gridCells[primary][matchStart + i] : gridCells[matchStart + i][primary];
if (cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
matchCells.push(cell);
}
}
// Only add valid matches with minimum length
if (matchCells.length >= 3) {
// Count visible and invisible cells
var visibleCount = 0;
var invisibleCount = 0;
for (var i = 0; i < matchCells.length; i++) {
if (matchCells[i].row >= extraRows) {
visibleCount++;
} else {
invisibleCount++;
}
}
// Add match if it satisfies visibility criteria
if (visibleCount === 0 || invisibleCount === 0 || visibleCount >= 3) {
matchCells.isHorizontal = isHorizontal;
matchCells.matchType = currentValue;
matches.push(matchCells);
}
}
}
// Start new potential match
if (currentCell && currentCell.value) {
currentValue = currentCell.value;
matchStart = secondary;
matchLength = 1;
} else {
currentValue = -1;
matchLength = 0;
}
}
}
}
}
// Find matches in both directions
findDirectionalMatches(true); // Horizontal
findDirectionalMatches(false); // Vertical
return matches;
}
function destroyCells(cellsToDestroy) {
isAnimating = true;
window.destructionInProgress = true;
// Partition cells into visible and valid cells in one pass
var visibleCellsToDestroy = [];
var invisibleCells = [];
var validCellMap = {};
for (var i = 0; i < cellsToDestroy.length; i++) {
var cell = cellsToDestroy[i];
if (!cell || !gridCells[cell.row] || gridCells[cell.row][cell.col] !== cell) continue;
if (cell.row >= extraRows) {
visibleCellsToDestroy.push(cell);
validCellMap[cell.row + "_" + cell.col] = cell;
} else {
invisibleCells.push(cell);
}
}
// Early exit if not enough visible or invisible cells
if (visibleCellsToDestroy.length > 0 && invisibleCells.length > 0 && (visibleCellsToDestroy.length === 1 || invisibleCells.length === 1)) {
isAnimating = false;
window.destructionInProgress = false;
return;
}
// Determine center cell
var centerCell = null;
if (arguments.length > 1 && arguments[1]) {
centerCell = arguments[1];
} else if (cellsToDestroy.length > 0) {
centerCell = cellsToDestroy[Math.floor(cellsToDestroy.length / 2)];
}
// Group cells by type efficiently
var cellsByType = {};
for (var i = 0; i < visibleCellsToDestroy.length; i++) {
var cell = visibleCellsToDestroy[i];
if (!cellsByType[cell.value]) {
cellsByType[cell.value] = [];
}
cellsByType[cell.value].push(cell);
}
// Handle combo sound
var uniqueGroupCount = Object.keys(cellsByType).length;
if (uniqueGroupCount > 0) {
if (!comboInProgress) {
comboCounter = uniqueGroupCount;
comboInProgress = true;
} else {
comboCounter += uniqueGroupCount;
}
// Stop all 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();
// Play the appropriate combo sound
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();
}
}
// Process special cells
var specialCell = null;
for (var type in cellsByType) {
var typeCells = cellsByType[type];
var typeValue = parseInt(type);
// Handle special cell creation based on match length
if (typeCells.length >= 6) {
specialCell = centerCell && centerCell.value === typeValue ? centerCell : typeCells[0];
specialCell.isSpecial = true;
specialCell.specialType = 'green';
specialCell.beingDestroyed = false;
delete validCellMap[specialCell.row + "_" + specialCell.col];
break;
} else if (typeCells.length === 5) {
specialCell = centerCell && centerCell.value === typeValue ? centerCell : typeCells[0];
specialCell.isSpecial = true;
specialCell.specialType = 'bomb';
specialCell.beingDestroyed = false;
delete validCellMap[specialCell.row + "_" + specialCell.col];
break;
} else if (typeCells.length === 4) {
// Check if cells are in same row or column
var firstCell = typeCells[0];
var allInSameRow = true;
var allInSameCol = true;
for (var i = 1; i < typeCells.length; i++) {
if (typeCells[i].row !== firstCell.row) allInSameRow = false;
if (typeCells[i].col !== firstCell.col) allInSameCol = false;
}
if (allInSameRow || allInSameCol) {
specialCell = centerCell && centerCell.value === typeValue ? centerCell : typeCells[0];
specialCell.isSpecial = true;
specialCell.specialType = allInSameRow ? 'horizontal' : 'vertical';
specialCell.beingDestroyed = false;
delete validCellMap[specialCell.row + "_" + specialCell.col];
break;
}
}
}
// Rebuild list of cells to destroy (excluding special cell)
visibleCellsToDestroy = Object.values(validCellMap);
// Sort cells by distance from center if needed
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;
});
}
// Mark cells for destruction
for (var i = 0; i < visibleCellsToDestroy.length; i++) {
var cell = visibleCellsToDestroy[i];
cell.beingDestroyed = true;
if (cell.isSpecial) {
LK.setTimeout(function (specialCellToActive) {
return function () {
if (specialCellToActive && specialCellToActive.activateSpecialPower) {
specialCellToActive.activateSpecialPower();
}
};
}(cell), 100); //{5J}{5K}
}
}
// Handle special cell appearance
if (specialCell && specialCell.isSpecial) {
if (specialCell.specialType === 'bomb') {
specialCell.sprite.tint = 0x0088FF;
} else if (specialCell.specialType === 'green') {
specialCell.sprite.tint = 0x00FF00;
} else {
specialCell.sprite.tint = 0xFF8800;
}
LK.effects.flashObject(specialCell, 0xFFFFFF, 300);
}
// Immediately destroy marked cells and clean grid
for (var i = 0; i < visibleCellsToDestroy.length; i++) {
var cell = visibleCellsToDestroy[i];
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;
}
}
// Apply gravity after destruction with a small delay to ensure proper grid state
LK.setTimeout(function () {
window.destructionInProgress = false;
applyGravity();
}, 50);
}
function applyGravity() {
isAnimating = true;
// Early return if gravity is already in progress
if (window.gravityInProgress) {
return;
}
window.gravityInProgress = true;
var cellsToFall = [];
// Process columns one by one
for (var col = 0; col < gridSize; col++) {
var emptySpaces = [];
// First pass: scan bottom to top to identify empty spaces
for (var row = gridSize + extraRows - 1; row >= 0; row--) {
if (!gridCells[row] || !gridCells[row][col]) {
if (row >= extraRows) {
emptySpaces.push(row);
}
} else if (emptySpaces.length > 0 && gridCells[row][col]) {
// Important: Take only the bottommost empty space for this cell
var targetRow = emptySpaces[0]; // Don't shift yet, just peek
var cellToMove = gridCells[row][col];
cellsToFall.push({
cell: cellToMove,
fromRow: row,
toRow: targetRow,
col: col
});
// Update grid references immediately to prevent cells from passing through each other
gridCells[targetRow][col] = cellToMove;
gridCells[row][col] = null;
cellToMove.row = targetRow;
// Add to visible container if coming from hidden area
if (row < extraRows && targetRow >= extraRows) {
gridContainer.addChild(cellToMove);
}
// Remove the filled space and add the now-empty source row
emptySpaces.shift(); // Now remove the space we used
emptySpaces.push(row);
// Sort empty spaces from bottom to top to preserve gravity physics
emptySpaces.sort(function (a, b) {
return b - a; // Higher row value means closer to bottom
});
}
}
}
// Use a constant animation duration for all cells
var animationDuration = 300;
// Sort cells to ensure bottom cells animate first
cellsToFall.sort(function (a, b) {
if (a.col !== b.col) {
return a.col - b.col;
}
return b.toRow - a.toRow; // Animate bottom cells first (higher row values)
});
// Apply animations with proper timing
for (var i = 0; i < cellsToFall.length; i++) {
var fallInfo = cellsToFall[i];
var newPos = getCellPosition(fallInfo.toRow, fallInfo.col);
tween(fallInfo.cell, {
y: newPos.y
}, {
duration: animationDuration,
easing: tween.easeInOutQuad
});
}
// Proceed to filling empty spaces after all animations complete
if (cellsToFall.length === 0) {
window.gravityInProgress = false;
fillEmptySpacesWithNewMemes();
} else {
// Wait for animations to complete before proceeding
LK.setTimeout(function () {
window.gravityInProgress = false;
fillEmptySpacesWithNewMemes();
}, animationDuration + 20);
}
}
function fillEmptySpacesWithNewMemes() {
// Early return if operations are already in progress
if (window.fillInProgress || window.gravityInProgress) {
return;
}
window.fillInProgress = true;
var newCellsToAdd = [];
// Find and fill all empty spaces in the right order (bottom-up)
for (var col = 0; col < gridSize; col++) {
// Process from bottom to top to maintain gravity physics
for (var row = gridSize + extraRows - 1; row >= 0; row--) {
if (!gridCells[row][col]) {
var newCell = getGridCell();
var pos = getCellPosition(row, col);
// Position new cell above the current position for animation
// Distance depends on how high up in the grid this cell is
var offsetY = Math.min(400, 200 + (gridSize + extraRows - row) * 30);
newCell.x = pos.x;
newCell.y = pos.y - offsetY;
// Generate random value while avoiding potential matches
var randomValue;
var attempts = 0;
var leftMatches = 0;
var aboveMatches = 0;
do {
randomValue = Math.floor(Math.random() * 5) + 1;
attempts++;
// Check horizontal matches
if (col >= 2 && gridCells[row][col - 1] && gridCells[row][col - 2] && gridCells[row][col - 1].value === randomValue && gridCells[row][col - 2].value === randomValue) {
leftMatches = 2;
} else {
leftMatches = 0;
}
// Check vertical matches
if (row >= 2 && gridCells[row - 1] && gridCells[row - 2] && gridCells[row - 1][col] && gridCells[row - 2][col] && gridCells[row - 1][col].value === randomValue && gridCells[row - 2][col].value === randomValue) {
aboveMatches = 2;
} else {
aboveMatches = 0;
}
} while ((leftMatches >= 2 || aboveMatches >= 2) && attempts < 5);
newCell.setValue(randomValue);
newCell.row = row;
newCell.col = col;
// Update grid immediately to prevent overlap issues
gridCells[row][col] = newCell;
newCellsToAdd.push({
cell: newCell,
destY: pos.y,
row: row,
col: col
});
// Only add to visible container if in visible area
if (row >= extraRows) {
gridContainer.addChild(newCell);
}
}
}
}
// Use a constant animation duration for consistent motion
var animationDuration = 300;
// Sort cells to animate in natural order (top cells last)
newCellsToAdd.sort(function (a, b) {
if (a.col !== b.col) {
return a.col - b.col;
}
return b.row - a.row; // Bottom cells animate first
});
// Start animations with proper timing
for (var i = 0; i < newCellsToAdd.length; i++) {
var cellData = newCellsToAdd[i];
tween(cellData.cell, {
y: cellData.destY
}, {
duration: animationDuration,
easing: tween.easeOutBounce
});
}
// If no new cells, reset states immediately
if (newCellsToAdd.length === 0) {
window.fillInProgress = false;
isAnimating = false;
comboInProgress = false;
comboCounter = 0;
return;
}
// Check for matches after animation completes
LK.setTimeout(function () {
window.fillInProgress = false;
if (window.destructionInProgress || window.gravityInProgress) {
isAnimating = false;
return;
}
// Get only valid, visible matches
var matches = getMatches();
var visibleMatchGroups = [];
for (var i = 0; i < matches.length; i++) {
var group = matches[i];
var visibleCount = 0;
var invisibleCount = 0;
for (var j = 0; j < group.length; j++) {
if (group[j].row >= extraRows) {
visibleCount++;
} else {
invisibleCount++;
}
}
// Only include groups with enough visible cells
if (visibleCount >= 3 || visibleCount > 0 && invisibleCount > 0 && visibleCount >= 3) {
visibleMatchGroups.push(group);
}
}
if (visibleMatchGroups.length > 0) {
// Process matches by cell type
var cellsByType = {};
var processedCells = {};
// Group cells by type
for (var i = 0; i < visibleMatchGroups.length; i++) {
var group = visibleMatchGroups[i];
if (group.length === 0) continue;
var type = group[0].value;
if (!cellsByType[type]) {
cellsByType[type] = [];
}
// Add unique cells
for (var j = 0; j < group.length; j++) {
var cell = group[j];
var cellKey = cell.row + "_" + cell.col;
if (!processedCells[cellKey] && cell.row >= extraRows && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
cellsByType[type].push(cell);
processedCells[cellKey] = true;
}
}
}
// Process each type group
for (var type in cellsByType) {
var cells = cellsByType[type];
if (cells.length === 0) continue;
// Use middle cell as center
var centerCell = cells[Math.floor(cells.length / 2)];
destroyCells(cells, centerCell);
}
} else {
// No matches, end animation state
isAnimating = false;
comboInProgress = false;
comboCounter = 0;
}
}, animationDuration + 50); // Slightly longer delay to ensure animations complete
}
function checkForAndDestroyMatches(swappedCellA, swappedCellB) {
// Don't process if animations are in progress
if (window.gravityInProgress || window.fillInProgress) {
return;
}
// Get all match groups
var allMatchGroupsOnBoard = getMatches();
if (!allMatchGroupsOnBoard.length) {
return;
}
// Find matches that contain the swapped cells and have enough visible cells
var relevantMatchGroups = [];
var cellsInSwap = [swappedCellA, swappedCellB];
for (var i = 0; i < allMatchGroupsOnBoard.length; i++) {
var group = allMatchGroupsOnBoard[i];
var visibleCount = 0;
var invisibleCount = 0;
var containsSwappedCell = false;
// Count visible cells and check for swapped cells in one pass
for (var j = 0; j < group.length; j++) {
var cell = group[j];
if (cell.row >= extraRows) {
visibleCount++;
// Check if this cell is one of the swapped cells
if (cell === swappedCellA || cell === swappedCellB) {
containsSwappedCell = true;
}
} else {
invisibleCount++;
}
}
// Include group if it has enough visible cells and contains a swapped cell
if (containsSwappedCell && (visibleCount >= 3 || !(visibleCount > 0 && invisibleCount > 0 && visibleCount < 3))) {
relevantMatchGroups.push(group);
}
}
if (!relevantMatchGroups.length) {
return;
}
// Process matches efficiently
var cellsByType = {};
var uniqueCellTracker = {};
// Group cells by type in one pass
for (var i = 0; i < relevantMatchGroups.length; i++) {
var group = relevantMatchGroups[i];
if (group.length === 0) continue;
var type = group[0].value;
if (!cellsByType[type]) {
cellsByType[type] = [];
}
// Add unique cells directly
for (var j = 0; j < group.length; j++) {
var cell = group[j];
if (cell.row < extraRows) continue;
var cellKey = cell.row + "_" + cell.col;
if (!uniqueCellTracker[cellKey] && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
cellsByType[type].push(cell);
uniqueCellTracker[cellKey] = true;
}
}
}
// Collect all cells to destroy
var cellsToDestroy = [];
for (var type in cellsByType) {
var typeCells = cellsByType[type];
cellsToDestroy = cellsToDestroy.concat(typeCells);
}
if (cellsToDestroy.length) {
// Determine center cell for special piece creation
var centerCell = null;
// Prioritize swapped cells that are part of a match
if (swappedCellA && uniqueCellTracker[swappedCellA.row + "_" + swappedCellA.col]) {
centerCell = swappedCellA;
} else if (swappedCellB && uniqueCellTracker[swappedCellB.row + "_" + swappedCellB.col]) {
centerCell = swappedCellB;
}
// Destroy matched cells
destroyCells(cellsToDestroy, centerCell);
// Reset combo at the end of all cascade matches
comboInProgress = false;
comboCounter = 0;
}
}
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)
};
}
var gridContainer = new Container();
game.addChild(gridContainer);
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;
}
}
}
initializeGrid();
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
@@ -202,8 +202,9 @@
var selectedCell = null;
var isAnimating = false;
window.gravityInProgress = false;
window.fillInProgress = false;
+window.destructionInProgress = false;
var comboCounter = 0;
var comboInProgress = false;
function handleCellTap(tappedCell) {
// Exit early if animations are in progress
@@ -611,8 +612,9 @@
return matches;
}
function destroyCells(cellsToDestroy) {
isAnimating = true;
+ window.destructionInProgress = true;
// Partition cells into visible and valid cells in one pass
var visibleCellsToDestroy = [];
var invisibleCells = [];
var validCellMap = {};
@@ -628,8 +630,9 @@
}
// Early exit if not enough visible or invisible cells
if (visibleCellsToDestroy.length > 0 && invisibleCells.length > 0 && (visibleCellsToDestroy.length === 1 || invisibleCells.length === 1)) {
isAnimating = false;
+ window.destructionInProgress = false;
return;
}
// Determine center cell
var centerCell = null;
@@ -728,11 +731,15 @@
for (var i = 0; i < visibleCellsToDestroy.length; i++) {
var cell = visibleCellsToDestroy[i];
cell.beingDestroyed = true;
if (cell.isSpecial) {
- LK.setTimeout(function () {
- cell.activateSpecialPower();
- }, 100);
+ LK.setTimeout(function (specialCellToActive) {
+ return function () {
+ if (specialCellToActive && specialCellToActive.activateSpecialPower) {
+ specialCellToActive.activateSpecialPower();
+ }
+ };
+ }(cell), 100); //{5J}{5K}
}
}
// Handle special cell appearance
if (specialCell && specialCell.isSpecial) {
@@ -744,9 +751,9 @@
specialCell.sprite.tint = 0xFF8800;
}
LK.effects.flashObject(specialCell, 0xFFFFFF, 300);
}
- // Immediately destroy marked cells
+ // Immediately destroy marked cells and clean grid
for (var i = 0; i < visibleCellsToDestroy.length; i++) {
var cell = visibleCellsToDestroy[i];
if (cell && cell.beingDestroyed && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
LK.getSound('Explosion').play();
@@ -755,10 +762,13 @@
cell.destroy();
gridCells[cell.row][cell.col] = null;
}
}
- // Apply gravity immediately after destruction
- applyGravity();
+ // Apply gravity after destruction with a small delay to ensure proper grid state
+ LK.setTimeout(function () {
+ window.destructionInProgress = false;
+ applyGravity();
+ }, 50);
}
function applyGravity() {
isAnimating = true;
// Early return if gravity is already in progress
@@ -766,54 +776,55 @@
return;
}
window.gravityInProgress = true;
var cellsToFall = [];
- // Find all cells that need to fall
+ // Process columns one by one
for (var col = 0; col < gridSize; col++) {
var emptySpaces = [];
- // First pass: identify empty spaces
+ // First pass: scan bottom to top to identify empty spaces
for (var row = gridSize + extraRows - 1; row >= 0; row--) {
if (!gridCells[row] || !gridCells[row][col]) {
if (row >= extraRows) {
emptySpaces.push(row);
}
} else if (emptySpaces.length > 0 && gridCells[row][col]) {
- // We have a cell that can fall into an empty space
- var targetRow = emptySpaces.shift();
+ // Important: Take only the bottommost empty space for this cell
+ var targetRow = emptySpaces[0]; // Don't shift yet, just peek
var cellToMove = gridCells[row][col];
cellsToFall.push({
cell: cellToMove,
fromRow: row,
toRow: targetRow,
col: col
});
- // Update grid references
+ // Update grid references immediately to prevent cells from passing through each other
gridCells[targetRow][col] = cellToMove;
gridCells[row][col] = null;
cellToMove.row = targetRow;
// Add to visible container if coming from hidden area
if (row < extraRows && targetRow >= extraRows) {
gridContainer.addChild(cellToMove);
}
- // Add the now-empty source row back to empty spaces
+ // Remove the filled space and add the now-empty source row
+ emptySpaces.shift(); // Now remove the space we used
emptySpaces.push(row);
- // Sort to maintain order
+ // Sort empty spaces from bottom to top to preserve gravity physics
emptySpaces.sort(function (a, b) {
- return b - a;
+ return b - a; // Higher row value means closer to bottom
});
}
}
}
- // Use a constant animation duration without incremental delays
+ // Use a constant animation duration for all cells
var animationDuration = 300;
- // Sort cells by column then by target row (bottom to top) for natural looking gravity
+ // Sort cells to ensure bottom cells animate first
cellsToFall.sort(function (a, b) {
if (a.col !== b.col) {
return a.col - b.col;
}
- return b.toRow - a.toRow;
+ return b.toRow - a.toRow; // Animate bottom cells first (higher row values)
});
- // Start all animations immediately
+ // Apply animations with proper timing
for (var i = 0; i < cellsToFall.length; i++) {
var fallInfo = cellsToFall[i];
var newPos = getCellPosition(fallInfo.toRow, fallInfo.col);
tween(fallInfo.cell, {
@@ -822,9 +833,9 @@
duration: animationDuration,
easing: tween.easeInOutQuad
});
}
- // If no cells to fall, proceed immediately to filling empty spaces
+ // Proceed to filling empty spaces after all animations complete
if (cellsToFall.length === 0) {
window.gravityInProgress = false;
fillEmptySpacesWithNewMemes();
} else {
@@ -841,17 +852,20 @@
return;
}
window.fillInProgress = true;
var newCellsToAdd = [];
- // Find and fill all empty spaces in one pass
+ // Find and fill all empty spaces in the right order (bottom-up)
for (var col = 0; col < gridSize; col++) {
- for (var row = 0; row < gridSize + extraRows; row++) {
+ // Process from bottom to top to maintain gravity physics
+ for (var row = gridSize + extraRows - 1; row >= 0; row--) {
if (!gridCells[row][col]) {
var newCell = getGridCell();
var pos = getCellPosition(row, col);
- // Position new cell above the grid for animation
+ // Position new cell above the current position for animation
+ // Distance depends on how high up in the grid this cell is
+ var offsetY = Math.min(400, 200 + (gridSize + extraRows - row) * 30);
newCell.x = pos.x;
- newCell.y = pos.y - 400;
+ newCell.y = pos.y - offsetY;
// Generate random value while avoiding potential matches
var randomValue;
var attempts = 0;
var leftMatches = 0;
@@ -874,8 +888,9 @@
} while ((leftMatches >= 2 || aboveMatches >= 2) && attempts < 5);
newCell.setValue(randomValue);
newCell.row = row;
newCell.col = col;
+ // Update grid immediately to prevent overlap issues
gridCells[row][col] = newCell;
newCellsToAdd.push({
cell: newCell,
destY: pos.y,
@@ -888,18 +903,18 @@
}
}
}
}
- // Use a constant animation duration without delays
+ // Use a constant animation duration for consistent motion
var animationDuration = 300;
- // Sort cells for natural falling appearance
+ // Sort cells to animate in natural order (top cells last)
newCellsToAdd.sort(function (a, b) {
if (a.col !== b.col) {
return a.col - b.col;
}
- return b.row - a.row;
+ return b.row - a.row; // Bottom cells animate first
});
- // Start all animations at once
+ // Start animations with proper timing
for (var i = 0; i < newCellsToAdd.length; i++) {
var cellData = newCellsToAdd[i];
tween(cellData.cell, {
y: cellData.destY
@@ -977,9 +992,9 @@
isAnimating = false;
comboInProgress = false;
comboCounter = 0;
}
- }, animationDuration + 20);
+ }, animationDuration + 50); // Slightly longer delay to ensure animations complete
}
function checkForAndDestroyMatches(swappedCellA, swappedCellB) {
// Don't process if animations are in progress
if (window.gravityInProgress || window.fillInProgress) {
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