User prompt
17. Satırı düzelt yoksa ananı sikerim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
L17 plugins load ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
17 düzelt yoksa ananı sikerim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
17. Satıtı düzelt yoksa ananı sikerim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
17 ve 37 düzelt yoksa ananı sikerim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Düzelt kodları ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Düzelt kodları ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
L37 and l17 fix ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Uncaught ReferenceError: tween is not defined' in or related to this line: 'tween(self, {' Line Number: 37 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
L17 düzenle
User prompt
17. Satırı düzenle
User prompt
17 satırdaki kodu eklentileri yükle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
17 satırdaki kodu eklentileri yükle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Eklentileri yükle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Ha bide bunlara patlama efekti ekleyelim ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Tamam ama şeker patlatdığım zamam şekerlerde daire oluşuyor onu düzelt
User prompt
Parmağımla şekerleri sürükleyebileyim
User prompt
Mobil için
Code edit (1 edits merged)
Please save this source code
User prompt
Sweet Crush Match
Initial prompt
Bana candy crush benzeri şeker patlatma oyunu yap
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Candy = Container.expand(function (type) {
var self = Container.call(this);
self.candyType = type;
self.gridX = 0;
self.gridY = 0;
self.isAnimating = false;
self.isMatched = false;
var candyAssets = ['candy_red', 'candy_blue', 'candy_green', 'candy_yellow', 'candy_purple', 'candy_orange', 'bomb'];
var candyGraphics = self.attachAsset(candyAssets[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
self.isAnimating = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isAnimating = false;
if (onComplete) {
onComplete();
}
}
});
};
self.animateMatch = function (onComplete) {
self.isMatched = true;
tween(self, {
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: onComplete
});
};
self.explodeBomb = function (onComplete) {
self.isMatched = true;
// Scale up and fade out for bomb explosion
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: onComplete
});
};
self.isBomb = function () {
return self.candyType === 6; // Bomb is type 6
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// Game constants
var GRID_SIZE = 8;
var CELL_SIZE = 180;
var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var GRID_START_Y = 500;
var CANDY_TYPES = 7; // 6 regular candies + 1 bomb type
// Game variables
var grid = [];
var selectedCandy = null;
var isProcessing = false;
var score = 0;
var moves = 30;
var targetScore = 5000;
var draggedCandy = null;
var dragStartX = 0;
var dragStartY = 0;
var originalCandyX = 0;
var originalCandyY = 0;
// Initialize UI
var scoreText = new Text2('Score: 0', {
size: 90,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 50;
LK.gui.top.addChild(scoreText);
var movesText = new Text2('Moves: 30', {
size: 70,
fill: '#FFD700'
});
movesText.anchor.set(0.5, 0);
movesText.y = 150;
LK.gui.top.addChild(movesText);
var targetText = new Text2('Target: 5000', {
size: 70,
fill: '#FF6B6B'
});
targetText.anchor.set(0.5, 0);
targetText.y = 220;
LK.gui.top.addChild(targetText);
// Initialize grid
function initializeGrid() {
grid = [];
for (var x = 0; x < GRID_SIZE; x++) {
grid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
// Only spawn one bomb in the entire grid occasionally
var candyType;
var hasBombInGrid = false;
// Check if there's already a bomb in the grid
for (var checkX = 0; checkX < GRID_SIZE; checkX++) {
for (var checkY = 0; checkY < GRID_SIZE; checkY++) {
if (grid[checkX] && grid[checkX][checkY] && grid[checkX][checkY].candyType === 6) {
hasBombInGrid = true;
break;
}
}
if (hasBombInGrid) break;
}
// Only 2% chance for bomb if no bomb exists yet
if (!hasBombInGrid && Math.random() < 0.02) {
candyType = 6; // Bomb type
} else {
candyType = Math.floor(Math.random() * 6); // Regular candy types only
}
var candy = new Candy(candyType);
candy.setGridPosition(x, y);
grid[x][y] = candy;
game.addChild(candy);
}
}
// Remove initial matches
removeInitialMatches();
}
function removeInitialMatches() {
var hasMatches = true;
while (hasMatches) {
var matches = findAllMatches();
if (matches.length === 0) {
hasMatches = false;
} else {
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var newType = Math.floor(Math.random() * CANDY_TYPES);
match.candyType = newType;
match.removeChild(match.children[0]);
var candyAssets = ['candy_red', 'candy_blue', 'candy_green', 'candy_yellow', 'candy_purple', 'candy_orange', 'bomb'];
match.attachAsset(candyAssets[newType], {
anchorX: 0.5,
anchorY: 0.5
});
}
}
}
}
function getCandyAt(x, y) {
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) {
return null;
}
return grid[x][y];
}
function getCandiesAroundBomb(bombX, bombY) {
var surroundingCandies = [];
// Get all 8 surrounding cells plus the bomb itself
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
var candy = getCandyAt(bombX + dx, bombY + dy);
if (candy && !candy.isMatched) {
surroundingCandies.push(candy);
}
}
}
return surroundingCandies;
}
function swapCandies(candy1, candy2) {
if (!candy1 || !candy2 || candy1.isAnimating || candy2.isAnimating) {
return false;
}
var tempX = candy1.gridX;
var tempY = candy1.gridY;
// Update grid positions
grid[candy1.gridX][candy1.gridY] = candy2;
grid[candy2.gridX][candy2.gridY] = candy1;
// Update candy grid positions
candy1.setGridPosition(candy2.gridX, candy2.gridY);
candy2.setGridPosition(tempX, tempY);
return true;
}
function findMatches(startX, startY) {
var candy = getCandyAt(startX, startY);
if (!candy) {
return [];
}
var matches = [];
var type = candy.candyType;
// Check horizontal matches
var horizontalMatches = [candy];
// Check left
for (var x = startX - 1; x >= 0; x--) {
var leftCandy = getCandyAt(x, startY);
if (leftCandy && leftCandy.candyType === type) {
horizontalMatches.unshift(leftCandy);
} else {
break;
}
}
// Check right
for (var x = startX + 1; x < GRID_SIZE; x++) {
var rightCandy = getCandyAt(x, startY);
if (rightCandy && rightCandy.candyType === type) {
horizontalMatches.push(rightCandy);
} else {
break;
}
}
if (horizontalMatches.length >= 3) {
matches = matches.concat(horizontalMatches);
}
// Check vertical matches
var verticalMatches = [candy];
// Check up
for (var y = startY - 1; y >= 0; y--) {
var upCandy = getCandyAt(startX, y);
if (upCandy && upCandy.candyType === type) {
verticalMatches.unshift(upCandy);
} else {
break;
}
}
// Check down
for (var y = startY + 1; y < GRID_SIZE; y++) {
var downCandy = getCandyAt(startX, y);
if (downCandy && downCandy.candyType === type) {
verticalMatches.push(downCandy);
} else {
break;
}
}
if (verticalMatches.length >= 3) {
matches = matches.concat(verticalMatches);
}
// Remove duplicates
var uniqueMatches = [];
for (var i = 0; i < matches.length; i++) {
var found = false;
for (var j = 0; j < uniqueMatches.length; j++) {
if (matches[i] === uniqueMatches[j]) {
found = true;
break;
}
}
if (!found) {
uniqueMatches.push(matches[i]);
}
}
return uniqueMatches;
}
function findAllMatches() {
var allMatches = [];
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var matches = findMatches(x, y);
for (var i = 0; i < matches.length; i++) {
var found = false;
for (var j = 0; j < allMatches.length; j++) {
if (matches[i] === allMatches[j]) {
found = true;
break;
}
}
if (!found) {
allMatches.push(matches[i]);
}
}
}
}
return allMatches;
}
function createExplosionEffect(centerX, centerY, candyType) {
var candyAssets = ['candy_red', 'candy_blue', 'candy_green', 'candy_yellow', 'candy_purple', 'candy_orange'];
var particleCount = 8;
var colors = [0xff4757, 0x3742fa, 0x2ed573, 0xffa502, 0xa55eea, 0xff6348];
var particleColor = colors[candyType];
// Create multiple small particles
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('candy_' + ['red', 'blue', 'green', 'yellow', 'purple', 'orange'][candyType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
particle.x = centerX;
particle.y = centerY;
particle.alpha = 0.8;
game.addChild(particle);
// Calculate random direction for explosion
var angle = Math.PI * 2 / particleCount * i + (Math.random() - 0.5) * 0.5;
var distance = 80 + Math.random() * 40;
var targetX = centerX + Math.cos(angle) * distance;
var targetY = centerY + Math.sin(angle) * distance;
// Animate particle explosion
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 400 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
function createBombExplosionEffect(centerX, centerY) {
var particleCount = 16;
// Create multiple dark particles for bomb explosion
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2
});
particle.x = centerX;
particle.y = centerY;
particle.alpha = 0.9;
particle.tint = 0xff4500; // Orange tint for explosion
game.addChild(particle);
// Calculate random direction for explosion
var angle = Math.PI * 2 / particleCount * i + (Math.random() - 0.5) * 0.8;
var distance = 120 + Math.random() * 80; // Larger explosion radius
var targetX = centerX + Math.cos(angle) * distance;
var targetY = centerY + Math.sin(angle) * distance;
// Animate particle explosion
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.05,
scaleY: 0.05
}, {
duration: 600 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
function removeMatches(matches) {
if (matches.length === 0) {
return;
}
// Check for bombs in matches and add surrounding candies
var allCandieToRemove = [];
var hasBombs = false;
// Check if any candy in matches is a bomb OR if there's a bomb adjacent to matched candies
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
allCandieToRemove.push(candy);
if (candy.isBomb()) {
hasBombs = true;
// Add all surrounding candies to removal list
var surroundingCandies = getCandiesAroundBomb(candy.gridX, candy.gridY);
for (var j = 0; j < surroundingCandies.length; j++) {
var surroundingCandy = surroundingCandies[j];
// Check if not already in removal list
var alreadyAdded = false;
for (var k = 0; k < allCandieToRemove.length; k++) {
if (allCandieToRemove[k] === surroundingCandy) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
allCandieToRemove.push(surroundingCandy);
}
}
} else {
// Check if there's a bomb adjacent to this matched candy
var adjacentPositions = [{
x: candy.gridX - 1,
y: candy.gridY
}, {
x: candy.gridX + 1,
y: candy.gridY
}, {
x: candy.gridX,
y: candy.gridY - 1
}, {
x: candy.gridX,
y: candy.gridY + 1
}];
for (var j = 0; j < adjacentPositions.length; j++) {
var pos = adjacentPositions[j];
var adjacentCandy = getCandyAt(pos.x, pos.y);
if (adjacentCandy && adjacentCandy.isBomb() && !adjacentCandy.isMatched) {
hasBombs = true;
// Add bomb and its surrounding candies
var alreadyAdded = false;
for (var k = 0; k < allCandieToRemove.length; k++) {
if (allCandieToRemove[k] === adjacentCandy) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
allCandieToRemove.push(adjacentCandy);
var surroundingCandies = getCandiesAroundBomb(adjacentCandy.gridX, adjacentCandy.gridY);
for (var l = 0; l < surroundingCandies.length; l++) {
var surroundingCandy = surroundingCandies[l];
var bombAlreadyAdded = false;
for (var m = 0; m < allCandieToRemove.length; m++) {
if (allCandieToRemove[m] === surroundingCandy) {
bombAlreadyAdded = true;
break;
}
}
if (!bombAlreadyAdded) {
allCandieToRemove.push(surroundingCandy);
}
}
}
}
}
}
}
// Add screen shake effect when bombs explode
if (hasBombs) {
var originalX = game.x;
var originalY = game.y;
var shakeIntensity = 15;
var shakeDuration = 500;
// Create shake effect by tweening the game container back and forth
tween(game, {
x: originalX + shakeIntensity
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX + shakeIntensity / 2
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity / 2
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
}
});
}
});
}
// Calculate points based on total candies removed
var points = 0;
if (allCandieToRemove.length === 3) {
points = 100;
} else if (allCandieToRemove.length === 4) {
points = 200;
} else if (allCandieToRemove.length <= 6) {
points = 500;
} else {
points = 1000; // Bonus points for bomb explosions
}
score += points;
scoreText.setText('Score: ' + score);
// Play appropriate sound
if (hasBombs) {
LK.getSound('explosion').play();
} else {
LK.getSound('match').play();
}
// Flash effect for matches
if (hasBombs) {
LK.effects.flashScreen(0xff4500, 500); // Orange flash for bombs
} else if (allCandieToRemove.length >= 4) {
LK.effects.flashScreen(0xffd700, 300);
} else if (allCandieToRemove.length >= 3) {
LK.effects.flashScreen(0x2ed573, 200);
}
// Create explosion effects for each candy
for (var i = 0; i < allCandieToRemove.length; i++) {
var candy = allCandieToRemove[i];
if (candy.isBomb()) {
createBombExplosionEffect(candy.x, candy.y);
} else {
createExplosionEffect(candy.x, candy.y, candy.candyType);
}
}
// Animate candies disappearing
var animationsComplete = 0;
for (var i = 0; i < allCandieToRemove.length; i++) {
var candy = allCandieToRemove[i];
grid[candy.gridX][candy.gridY] = null;
// Use bomb explosion animation for bombs
if (candy.isBomb()) {
candy.explodeBomb(function () {
animationsComplete++;
if (animationsComplete === allCandieToRemove.length) {
applyGravity();
}
});
} else {
candy.animateMatch(function () {
animationsComplete++;
if (animationsComplete === allCandieToRemove.length) {
applyGravity();
}
});
}
}
}
function applyGravity() {
var needsGravity = false;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (grid[x][y] === null) {
// Find candy above
for (var searchY = y - 1; searchY >= 0; searchY--) {
if (grid[x][searchY] !== null) {
var candy = grid[x][searchY];
grid[x][y] = candy;
grid[x][searchY] = null;
candy.gridY = y;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
candy.animateToPosition(candy.x, targetY, 300);
needsGravity = true;
break;
}
}
}
}
}
// Spawn new candies
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y] === null) {
// Only spawn one bomb in the entire grid occasionally
var candyType;
var hasBombInGrid = false;
// Check if there's already a bomb in the grid
for (var checkX = 0; checkX < GRID_SIZE; checkX++) {
for (var checkY = 0; checkY < GRID_SIZE; checkY++) {
if (grid[checkX] && grid[checkX][checkY] && grid[checkX][checkY].candyType === 6) {
hasBombInGrid = true;
break;
}
}
if (hasBombInGrid) break;
}
// Only 1% chance for bomb if no bomb exists yet
if (!hasBombInGrid && Math.random() < 0.01) {
candyType = 6; // Bomb type
} else {
candyType = Math.floor(Math.random() * 6); // Regular candy types only
}
var candy = new Candy(candyType);
candy.setGridPosition(x, y);
candy.y = GRID_START_Y - CELL_SIZE;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
candy.animateToPosition(candy.x, targetY, 400);
grid[x][y] = candy;
game.addChild(candy);
needsGravity = true;
}
}
}
if (needsGravity) {
LK.setTimeout(function () {
checkForMatches();
}, 500);
} else {
isProcessing = false;
}
}
function checkForMatches() {
var matches = findAllMatches();
if (matches.length > 0) {
removeMatches(matches);
} else {
isProcessing = false;
}
}
function isAdjacent(candy1, candy2) {
var dx = Math.abs(candy1.gridX - candy2.gridX);
var dy = Math.abs(candy1.gridY - candy2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function getCandyAtPosition(x, y) {
for (var gx = 0; gx < GRID_SIZE; gx++) {
for (var gy = 0; gy < GRID_SIZE; gy++) {
var candy = grid[gx][gy];
if (candy && !candy.isMatched) {
var candyBounds = {
x: candy.x - CELL_SIZE / 2,
y: candy.y - CELL_SIZE / 2,
width: CELL_SIZE,
height: CELL_SIZE
};
if (x >= candyBounds.x && x <= candyBounds.x + candyBounds.width && y >= candyBounds.y && y <= candyBounds.y + candyBounds.height) {
return candy;
}
}
}
}
return null;
}
// Game event handlers
game.down = function (x, y, obj) {
if (isProcessing) {
return;
}
var candy = getCandyAtPosition(x, y);
if (candy) {
if (selectedCandy && selectedCandy !== candy) {
selectedCandy.alpha = 1.0;
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
}
selectedCandy = candy;
draggedCandy = candy;
dragStartX = x;
dragStartY = y;
originalCandyX = candy.x;
originalCandyY = candy.y;
candy.alpha = 0.8;
candy.scaleX = 1.15;
candy.scaleY = 1.15;
LK.getSound('swap').play();
}
};
game.move = function (x, y, obj) {
if (isProcessing || !draggedCandy) {
return;
}
// Calculate drag distance
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Only start visual dragging if moved enough distance
if (distance > 30) {
// Limit drag distance to adjacent cells
var maxDrag = CELL_SIZE * 0.7;
var dragX = Math.max(-maxDrag, Math.min(maxDrag, deltaX));
var dragY = Math.max(-maxDrag, Math.min(maxDrag, deltaY));
// Move the candy with the drag
draggedCandy.x = originalCandyX + dragX;
draggedCandy.y = originalCandyY + dragY;
}
};
game.up = function (x, y, obj) {
if (isProcessing || !selectedCandy) {
return;
}
var targetCandy = null;
var performedSwap = false;
if (draggedCandy) {
// Calculate drag direction and find target candy
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 60) {
// Determine which direction was dragged most
var targetGridX = draggedCandy.gridX;
var targetGridY = draggedCandy.gridY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal drag
if (deltaX > 0) {
targetGridX++; // Right
} else {
targetGridX--; // Left
}
} else {
// Vertical drag
if (deltaY > 0) {
targetGridY++; // Down
} else {
targetGridY--; // Up
}
}
targetCandy = getCandyAt(targetGridX, targetGridY);
} else {
// Small drag, check position under finger
targetCandy = getCandyAtPosition(x, y);
}
} else {
// No drag, check position under finger
targetCandy = getCandyAtPosition(x, y);
}
if (targetCandy && targetCandy !== selectedCandy && isAdjacent(selectedCandy, targetCandy)) {
isProcessing = true;
performedSwap = true;
// Try the swap
var candy1 = selectedCandy;
var candy2 = targetCandy;
if (swapCandies(candy1, candy2)) {
LK.getSound('swap').play();
// Animate the swap
var targetX1 = candy1.x;
var targetY1 = candy1.y;
var targetX2 = candy2.x;
var targetY2 = candy2.y;
// Reset candy1 position first if it was dragged
if (draggedCandy === candy1) {
candy1.x = originalCandyX;
candy1.y = originalCandyY;
}
candy1.animateToPosition(targetX1, targetY1, 200);
candy2.animateToPosition(targetX2, targetY2, 200, function () {
// Check for matches after swap
var matches1 = findMatches(candy1.gridX, candy1.gridY);
var matches2 = findMatches(candy2.gridX, candy2.gridY);
var allSwapMatches = matches1.concat(matches2);
// Remove duplicates
var uniqueMatches = [];
for (var i = 0; i < allSwapMatches.length; i++) {
var found = false;
for (var j = 0; j < uniqueMatches.length; j++) {
if (allSwapMatches[i] === uniqueMatches[j]) {
found = true;
break;
}
}
if (!found) {
uniqueMatches.push(allSwapMatches[i]);
}
}
if (uniqueMatches.length > 0) {
moves--;
movesText.setText('Moves: ' + moves);
removeMatches(uniqueMatches);
} else {
// Invalid move, swap back
swapCandies(candy1, candy2);
candy1.animateToPosition(targetX2, targetY2, 200);
candy2.animateToPosition(targetX1, targetY1, 200, function () {
isProcessing = false;
});
}
});
} else {
isProcessing = false;
}
}
// Reset dragged candy position if no valid swap was made
if (draggedCandy && !performedSwap) {
draggedCandy.animateToPosition(originalCandyX, originalCandyY, 200);
}
if (selectedCandy) {
selectedCandy.alpha = 1.0;
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
selectedCandy = null;
}
// Reset drag variables
draggedCandy = null;
dragStartX = 0;
dragStartY = 0;
originalCandyX = 0;
originalCandyY = 0;
};
// Game update loop
game.update = function () {
// Check win condition
if (score >= targetScore) {
LK.showYouWin();
}
// Check lose condition
if (moves <= 0 && score < targetScore) {
LK.showGameOver();
}
};
// Initialize the game
initializeGrid(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Candy = Container.expand(function (type) {
var self = Container.call(this);
self.candyType = type;
self.gridX = 0;
self.gridY = 0;
self.isAnimating = false;
self.isMatched = false;
var candyAssets = ['candy_red', 'candy_blue', 'candy_green', 'candy_yellow', 'candy_purple', 'candy_orange', 'bomb'];
var candyGraphics = self.attachAsset(candyAssets[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = GRID_START_X + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = GRID_START_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
self.isAnimating = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isAnimating = false;
if (onComplete) {
onComplete();
}
}
});
};
self.animateMatch = function (onComplete) {
self.isMatched = true;
tween(self, {
alpha: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: onComplete
});
};
self.explodeBomb = function (onComplete) {
self.isMatched = true;
// Scale up and fade out for bomb explosion
tween(self, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: onComplete
});
};
self.isBomb = function () {
return self.candyType === 6; // Bomb is type 6
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// Game constants
var GRID_SIZE = 8;
var CELL_SIZE = 180;
var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var GRID_START_Y = 500;
var CANDY_TYPES = 7; // 6 regular candies + 1 bomb type
// Game variables
var grid = [];
var selectedCandy = null;
var isProcessing = false;
var score = 0;
var moves = 30;
var targetScore = 5000;
var draggedCandy = null;
var dragStartX = 0;
var dragStartY = 0;
var originalCandyX = 0;
var originalCandyY = 0;
// Initialize UI
var scoreText = new Text2('Score: 0', {
size: 90,
fill: '#FFFFFF'
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 50;
LK.gui.top.addChild(scoreText);
var movesText = new Text2('Moves: 30', {
size: 70,
fill: '#FFD700'
});
movesText.anchor.set(0.5, 0);
movesText.y = 150;
LK.gui.top.addChild(movesText);
var targetText = new Text2('Target: 5000', {
size: 70,
fill: '#FF6B6B'
});
targetText.anchor.set(0.5, 0);
targetText.y = 220;
LK.gui.top.addChild(targetText);
// Initialize grid
function initializeGrid() {
grid = [];
for (var x = 0; x < GRID_SIZE; x++) {
grid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
// Only spawn one bomb in the entire grid occasionally
var candyType;
var hasBombInGrid = false;
// Check if there's already a bomb in the grid
for (var checkX = 0; checkX < GRID_SIZE; checkX++) {
for (var checkY = 0; checkY < GRID_SIZE; checkY++) {
if (grid[checkX] && grid[checkX][checkY] && grid[checkX][checkY].candyType === 6) {
hasBombInGrid = true;
break;
}
}
if (hasBombInGrid) break;
}
// Only 2% chance for bomb if no bomb exists yet
if (!hasBombInGrid && Math.random() < 0.02) {
candyType = 6; // Bomb type
} else {
candyType = Math.floor(Math.random() * 6); // Regular candy types only
}
var candy = new Candy(candyType);
candy.setGridPosition(x, y);
grid[x][y] = candy;
game.addChild(candy);
}
}
// Remove initial matches
removeInitialMatches();
}
function removeInitialMatches() {
var hasMatches = true;
while (hasMatches) {
var matches = findAllMatches();
if (matches.length === 0) {
hasMatches = false;
} else {
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var newType = Math.floor(Math.random() * CANDY_TYPES);
match.candyType = newType;
match.removeChild(match.children[0]);
var candyAssets = ['candy_red', 'candy_blue', 'candy_green', 'candy_yellow', 'candy_purple', 'candy_orange', 'bomb'];
match.attachAsset(candyAssets[newType], {
anchorX: 0.5,
anchorY: 0.5
});
}
}
}
}
function getCandyAt(x, y) {
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) {
return null;
}
return grid[x][y];
}
function getCandiesAroundBomb(bombX, bombY) {
var surroundingCandies = [];
// Get all 8 surrounding cells plus the bomb itself
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
var candy = getCandyAt(bombX + dx, bombY + dy);
if (candy && !candy.isMatched) {
surroundingCandies.push(candy);
}
}
}
return surroundingCandies;
}
function swapCandies(candy1, candy2) {
if (!candy1 || !candy2 || candy1.isAnimating || candy2.isAnimating) {
return false;
}
var tempX = candy1.gridX;
var tempY = candy1.gridY;
// Update grid positions
grid[candy1.gridX][candy1.gridY] = candy2;
grid[candy2.gridX][candy2.gridY] = candy1;
// Update candy grid positions
candy1.setGridPosition(candy2.gridX, candy2.gridY);
candy2.setGridPosition(tempX, tempY);
return true;
}
function findMatches(startX, startY) {
var candy = getCandyAt(startX, startY);
if (!candy) {
return [];
}
var matches = [];
var type = candy.candyType;
// Check horizontal matches
var horizontalMatches = [candy];
// Check left
for (var x = startX - 1; x >= 0; x--) {
var leftCandy = getCandyAt(x, startY);
if (leftCandy && leftCandy.candyType === type) {
horizontalMatches.unshift(leftCandy);
} else {
break;
}
}
// Check right
for (var x = startX + 1; x < GRID_SIZE; x++) {
var rightCandy = getCandyAt(x, startY);
if (rightCandy && rightCandy.candyType === type) {
horizontalMatches.push(rightCandy);
} else {
break;
}
}
if (horizontalMatches.length >= 3) {
matches = matches.concat(horizontalMatches);
}
// Check vertical matches
var verticalMatches = [candy];
// Check up
for (var y = startY - 1; y >= 0; y--) {
var upCandy = getCandyAt(startX, y);
if (upCandy && upCandy.candyType === type) {
verticalMatches.unshift(upCandy);
} else {
break;
}
}
// Check down
for (var y = startY + 1; y < GRID_SIZE; y++) {
var downCandy = getCandyAt(startX, y);
if (downCandy && downCandy.candyType === type) {
verticalMatches.push(downCandy);
} else {
break;
}
}
if (verticalMatches.length >= 3) {
matches = matches.concat(verticalMatches);
}
// Remove duplicates
var uniqueMatches = [];
for (var i = 0; i < matches.length; i++) {
var found = false;
for (var j = 0; j < uniqueMatches.length; j++) {
if (matches[i] === uniqueMatches[j]) {
found = true;
break;
}
}
if (!found) {
uniqueMatches.push(matches[i]);
}
}
return uniqueMatches;
}
function findAllMatches() {
var allMatches = [];
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var matches = findMatches(x, y);
for (var i = 0; i < matches.length; i++) {
var found = false;
for (var j = 0; j < allMatches.length; j++) {
if (matches[i] === allMatches[j]) {
found = true;
break;
}
}
if (!found) {
allMatches.push(matches[i]);
}
}
}
}
return allMatches;
}
function createExplosionEffect(centerX, centerY, candyType) {
var candyAssets = ['candy_red', 'candy_blue', 'candy_green', 'candy_yellow', 'candy_purple', 'candy_orange'];
var particleCount = 8;
var colors = [0xff4757, 0x3742fa, 0x2ed573, 0xffa502, 0xa55eea, 0xff6348];
var particleColor = colors[candyType];
// Create multiple small particles
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('candy_' + ['red', 'blue', 'green', 'yellow', 'purple', 'orange'][candyType], {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3
});
particle.x = centerX;
particle.y = centerY;
particle.alpha = 0.8;
game.addChild(particle);
// Calculate random direction for explosion
var angle = Math.PI * 2 / particleCount * i + (Math.random() - 0.5) * 0.5;
var distance = 80 + Math.random() * 40;
var targetX = centerX + Math.cos(angle) * distance;
var targetY = centerY + Math.sin(angle) * distance;
// Animate particle explosion
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 400 + Math.random() * 200,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
function createBombExplosionEffect(centerX, centerY) {
var particleCount = 16;
// Create multiple dark particles for bomb explosion
for (var i = 0; i < particleCount; i++) {
var particle = LK.getAsset('bomb', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.2,
scaleY: 0.2
});
particle.x = centerX;
particle.y = centerY;
particle.alpha = 0.9;
particle.tint = 0xff4500; // Orange tint for explosion
game.addChild(particle);
// Calculate random direction for explosion
var angle = Math.PI * 2 / particleCount * i + (Math.random() - 0.5) * 0.8;
var distance = 120 + Math.random() * 80; // Larger explosion radius
var targetX = centerX + Math.cos(angle) * distance;
var targetY = centerY + Math.sin(angle) * distance;
// Animate particle explosion
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 0.05,
scaleY: 0.05
}, {
duration: 600 + Math.random() * 300,
easing: tween.easeOut,
onFinish: function onFinish() {
particle.destroy();
}
});
}
}
function removeMatches(matches) {
if (matches.length === 0) {
return;
}
// Check for bombs in matches and add surrounding candies
var allCandieToRemove = [];
var hasBombs = false;
// Check if any candy in matches is a bomb OR if there's a bomb adjacent to matched candies
for (var i = 0; i < matches.length; i++) {
var candy = matches[i];
allCandieToRemove.push(candy);
if (candy.isBomb()) {
hasBombs = true;
// Add all surrounding candies to removal list
var surroundingCandies = getCandiesAroundBomb(candy.gridX, candy.gridY);
for (var j = 0; j < surroundingCandies.length; j++) {
var surroundingCandy = surroundingCandies[j];
// Check if not already in removal list
var alreadyAdded = false;
for (var k = 0; k < allCandieToRemove.length; k++) {
if (allCandieToRemove[k] === surroundingCandy) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
allCandieToRemove.push(surroundingCandy);
}
}
} else {
// Check if there's a bomb adjacent to this matched candy
var adjacentPositions = [{
x: candy.gridX - 1,
y: candy.gridY
}, {
x: candy.gridX + 1,
y: candy.gridY
}, {
x: candy.gridX,
y: candy.gridY - 1
}, {
x: candy.gridX,
y: candy.gridY + 1
}];
for (var j = 0; j < adjacentPositions.length; j++) {
var pos = adjacentPositions[j];
var adjacentCandy = getCandyAt(pos.x, pos.y);
if (adjacentCandy && adjacentCandy.isBomb() && !adjacentCandy.isMatched) {
hasBombs = true;
// Add bomb and its surrounding candies
var alreadyAdded = false;
for (var k = 0; k < allCandieToRemove.length; k++) {
if (allCandieToRemove[k] === adjacentCandy) {
alreadyAdded = true;
break;
}
}
if (!alreadyAdded) {
allCandieToRemove.push(adjacentCandy);
var surroundingCandies = getCandiesAroundBomb(adjacentCandy.gridX, adjacentCandy.gridY);
for (var l = 0; l < surroundingCandies.length; l++) {
var surroundingCandy = surroundingCandies[l];
var bombAlreadyAdded = false;
for (var m = 0; m < allCandieToRemove.length; m++) {
if (allCandieToRemove[m] === surroundingCandy) {
bombAlreadyAdded = true;
break;
}
}
if (!bombAlreadyAdded) {
allCandieToRemove.push(surroundingCandy);
}
}
}
}
}
}
}
// Add screen shake effect when bombs explode
if (hasBombs) {
var originalX = game.x;
var originalY = game.y;
var shakeIntensity = 15;
var shakeDuration = 500;
// Create shake effect by tweening the game container back and forth
tween(game, {
x: originalX + shakeIntensity
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX + shakeIntensity / 2
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX - shakeIntensity / 2
}, {
duration: 50,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(game, {
x: originalX
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
});
}
});
}
});
}
// Calculate points based on total candies removed
var points = 0;
if (allCandieToRemove.length === 3) {
points = 100;
} else if (allCandieToRemove.length === 4) {
points = 200;
} else if (allCandieToRemove.length <= 6) {
points = 500;
} else {
points = 1000; // Bonus points for bomb explosions
}
score += points;
scoreText.setText('Score: ' + score);
// Play appropriate sound
if (hasBombs) {
LK.getSound('explosion').play();
} else {
LK.getSound('match').play();
}
// Flash effect for matches
if (hasBombs) {
LK.effects.flashScreen(0xff4500, 500); // Orange flash for bombs
} else if (allCandieToRemove.length >= 4) {
LK.effects.flashScreen(0xffd700, 300);
} else if (allCandieToRemove.length >= 3) {
LK.effects.flashScreen(0x2ed573, 200);
}
// Create explosion effects for each candy
for (var i = 0; i < allCandieToRemove.length; i++) {
var candy = allCandieToRemove[i];
if (candy.isBomb()) {
createBombExplosionEffect(candy.x, candy.y);
} else {
createExplosionEffect(candy.x, candy.y, candy.candyType);
}
}
// Animate candies disappearing
var animationsComplete = 0;
for (var i = 0; i < allCandieToRemove.length; i++) {
var candy = allCandieToRemove[i];
grid[candy.gridX][candy.gridY] = null;
// Use bomb explosion animation for bombs
if (candy.isBomb()) {
candy.explodeBomb(function () {
animationsComplete++;
if (animationsComplete === allCandieToRemove.length) {
applyGravity();
}
});
} else {
candy.animateMatch(function () {
animationsComplete++;
if (animationsComplete === allCandieToRemove.length) {
applyGravity();
}
});
}
}
}
function applyGravity() {
var needsGravity = false;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (grid[x][y] === null) {
// Find candy above
for (var searchY = y - 1; searchY >= 0; searchY--) {
if (grid[x][searchY] !== null) {
var candy = grid[x][searchY];
grid[x][y] = candy;
grid[x][searchY] = null;
candy.gridY = y;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
candy.animateToPosition(candy.x, targetY, 300);
needsGravity = true;
break;
}
}
}
}
}
// Spawn new candies
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y] === null) {
// Only spawn one bomb in the entire grid occasionally
var candyType;
var hasBombInGrid = false;
// Check if there's already a bomb in the grid
for (var checkX = 0; checkX < GRID_SIZE; checkX++) {
for (var checkY = 0; checkY < GRID_SIZE; checkY++) {
if (grid[checkX] && grid[checkX][checkY] && grid[checkX][checkY].candyType === 6) {
hasBombInGrid = true;
break;
}
}
if (hasBombInGrid) break;
}
// Only 1% chance for bomb if no bomb exists yet
if (!hasBombInGrid && Math.random() < 0.01) {
candyType = 6; // Bomb type
} else {
candyType = Math.floor(Math.random() * 6); // Regular candy types only
}
var candy = new Candy(candyType);
candy.setGridPosition(x, y);
candy.y = GRID_START_Y - CELL_SIZE;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
candy.animateToPosition(candy.x, targetY, 400);
grid[x][y] = candy;
game.addChild(candy);
needsGravity = true;
}
}
}
if (needsGravity) {
LK.setTimeout(function () {
checkForMatches();
}, 500);
} else {
isProcessing = false;
}
}
function checkForMatches() {
var matches = findAllMatches();
if (matches.length > 0) {
removeMatches(matches);
} else {
isProcessing = false;
}
}
function isAdjacent(candy1, candy2) {
var dx = Math.abs(candy1.gridX - candy2.gridX);
var dy = Math.abs(candy1.gridY - candy2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function getCandyAtPosition(x, y) {
for (var gx = 0; gx < GRID_SIZE; gx++) {
for (var gy = 0; gy < GRID_SIZE; gy++) {
var candy = grid[gx][gy];
if (candy && !candy.isMatched) {
var candyBounds = {
x: candy.x - CELL_SIZE / 2,
y: candy.y - CELL_SIZE / 2,
width: CELL_SIZE,
height: CELL_SIZE
};
if (x >= candyBounds.x && x <= candyBounds.x + candyBounds.width && y >= candyBounds.y && y <= candyBounds.y + candyBounds.height) {
return candy;
}
}
}
}
return null;
}
// Game event handlers
game.down = function (x, y, obj) {
if (isProcessing) {
return;
}
var candy = getCandyAtPosition(x, y);
if (candy) {
if (selectedCandy && selectedCandy !== candy) {
selectedCandy.alpha = 1.0;
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
}
selectedCandy = candy;
draggedCandy = candy;
dragStartX = x;
dragStartY = y;
originalCandyX = candy.x;
originalCandyY = candy.y;
candy.alpha = 0.8;
candy.scaleX = 1.15;
candy.scaleY = 1.15;
LK.getSound('swap').play();
}
};
game.move = function (x, y, obj) {
if (isProcessing || !draggedCandy) {
return;
}
// Calculate drag distance
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Only start visual dragging if moved enough distance
if (distance > 30) {
// Limit drag distance to adjacent cells
var maxDrag = CELL_SIZE * 0.7;
var dragX = Math.max(-maxDrag, Math.min(maxDrag, deltaX));
var dragY = Math.max(-maxDrag, Math.min(maxDrag, deltaY));
// Move the candy with the drag
draggedCandy.x = originalCandyX + dragX;
draggedCandy.y = originalCandyY + dragY;
}
};
game.up = function (x, y, obj) {
if (isProcessing || !selectedCandy) {
return;
}
var targetCandy = null;
var performedSwap = false;
if (draggedCandy) {
// Calculate drag direction and find target candy
var deltaX = x - dragStartX;
var deltaY = y - dragStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 60) {
// Determine which direction was dragged most
var targetGridX = draggedCandy.gridX;
var targetGridY = draggedCandy.gridY;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal drag
if (deltaX > 0) {
targetGridX++; // Right
} else {
targetGridX--; // Left
}
} else {
// Vertical drag
if (deltaY > 0) {
targetGridY++; // Down
} else {
targetGridY--; // Up
}
}
targetCandy = getCandyAt(targetGridX, targetGridY);
} else {
// Small drag, check position under finger
targetCandy = getCandyAtPosition(x, y);
}
} else {
// No drag, check position under finger
targetCandy = getCandyAtPosition(x, y);
}
if (targetCandy && targetCandy !== selectedCandy && isAdjacent(selectedCandy, targetCandy)) {
isProcessing = true;
performedSwap = true;
// Try the swap
var candy1 = selectedCandy;
var candy2 = targetCandy;
if (swapCandies(candy1, candy2)) {
LK.getSound('swap').play();
// Animate the swap
var targetX1 = candy1.x;
var targetY1 = candy1.y;
var targetX2 = candy2.x;
var targetY2 = candy2.y;
// Reset candy1 position first if it was dragged
if (draggedCandy === candy1) {
candy1.x = originalCandyX;
candy1.y = originalCandyY;
}
candy1.animateToPosition(targetX1, targetY1, 200);
candy2.animateToPosition(targetX2, targetY2, 200, function () {
// Check for matches after swap
var matches1 = findMatches(candy1.gridX, candy1.gridY);
var matches2 = findMatches(candy2.gridX, candy2.gridY);
var allSwapMatches = matches1.concat(matches2);
// Remove duplicates
var uniqueMatches = [];
for (var i = 0; i < allSwapMatches.length; i++) {
var found = false;
for (var j = 0; j < uniqueMatches.length; j++) {
if (allSwapMatches[i] === uniqueMatches[j]) {
found = true;
break;
}
}
if (!found) {
uniqueMatches.push(allSwapMatches[i]);
}
}
if (uniqueMatches.length > 0) {
moves--;
movesText.setText('Moves: ' + moves);
removeMatches(uniqueMatches);
} else {
// Invalid move, swap back
swapCandies(candy1, candy2);
candy1.animateToPosition(targetX2, targetY2, 200);
candy2.animateToPosition(targetX1, targetY1, 200, function () {
isProcessing = false;
});
}
});
} else {
isProcessing = false;
}
}
// Reset dragged candy position if no valid swap was made
if (draggedCandy && !performedSwap) {
draggedCandy.animateToPosition(originalCandyX, originalCandyY, 200);
}
if (selectedCandy) {
selectedCandy.alpha = 1.0;
selectedCandy.scaleX = 1.0;
selectedCandy.scaleY = 1.0;
selectedCandy = null;
}
// Reset drag variables
draggedCandy = null;
dragStartX = 0;
dragStartY = 0;
originalCandyX = 0;
originalCandyY = 0;
};
// Game update loop
game.update = function () {
// Check win condition
if (score >= targetScore) {
LK.showYouWin();
}
// Check lose condition
if (moves <= 0 && score < targetScore) {
LK.showGameOver();
}
};
// Initialize the game
initializeGrid();