/****
* 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.isMoving = false;
self.isMatched = false;
self.isSpecial = function () {
return self.candyType === 7 || self.candyType === 8;
};
self.isHorizontalBreaker = function () {
return self.candyType === 7;
};
self.isVerticalBreaker = function () {
return self.candyType === 8;
};
var candyGraphics = self.attachAsset('candy' + type, {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gx, gy) {
self.gridX = gx;
self.gridY = gy;
self.x = GRID_START_X + gx * CELL_SIZE + CELL_SIZE / 2;
self.y = GRID_START_Y + gy * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
if (!duration) duration = 300;
self.isMoving = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isMoving = false;
if (onComplete) onComplete();
}
});
};
self.animateMatch = function (onComplete) {
self.isMatched = true;
tween(self, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.7
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 150,
easing: tween.easeIn,
onFinish: onComplete
});
}
});
};
return self;
});
var Grid = Container.expand(function () {
var self = Container.call(this);
self.grid = [];
self.selectedCandy = null;
self.swapping = false;
self.initializeGrid = function () {
// Create background cells
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var cell = self.attachAsset('gridCell', {
x: GRID_START_X + x * CELL_SIZE,
y: GRID_START_Y + y * CELL_SIZE,
alpha: 0.3
});
}
}
// Initialize grid array
for (var x = 0; x < GRID_SIZE; x++) {
self.grid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
self.grid[x][y] = null;
}
}
// Fill grid with candies
self.fillGrid();
};
self.fillGrid = function () {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (self.grid[x][y] === null) {
var candyType = self.getRandomCandyType();
var candy = new Candy(candyType);
candy.setGridPosition(x, y);
self.grid[x][y] = candy;
self.addChild(candy);
}
}
}
};
self.getRandomCandyType = function () {
// 0.5% chance for candy 8 (very rare)
if (Math.random() < 0.005) {
return 8; // Candy 8 is very rare
}
// 2% chance for candy 7 (horizontal line breaker)
if (Math.random() < 0.02) {
return 7; // Candy 7 is less rare
}
return Math.floor(Math.random() * 6) + 1;
};
self.getCandyAt = function (x, y) {
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) return null;
return self.grid[x][y];
};
self.swapCandies = function (candy1, candy2) {
if (self.swapping || !candy1 || !candy2) return;
self.swapping = true;
var tempX = candy1.gridX;
var tempY = candy1.gridY;
// Update grid positions
self.grid[candy1.gridX][candy1.gridY] = candy2;
self.grid[candy2.gridX][candy2.gridY] = candy1;
// Update candy grid positions
candy1.gridX = candy2.gridX;
candy1.gridY = candy2.gridY;
candy2.gridX = tempX;
candy2.gridY = tempY;
// Animate swap
var targetX1 = GRID_START_X + candy1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = GRID_START_Y + candy1.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = GRID_START_X + candy2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = GRID_START_Y + candy2.gridY * CELL_SIZE + CELL_SIZE / 2;
var swapsComplete = 0;
var onSwapComplete = function onSwapComplete() {
swapsComplete++;
if (swapsComplete === 2) {
LK.getSound('swap').play();
self.swapping = false;
self.checkForMatches();
}
};
candy1.animateToPosition(targetX1, targetY1, 250, onSwapComplete);
candy2.animateToPosition(targetX2, targetY2, 250, onSwapComplete);
};
self.checkForMatches = function () {
var matches = self.findMatches();
if (matches.length > 0) {
self.removeMatches(matches);
}
};
self.findMatches = function () {
var matches = [];
var checked = [];
// Initialize checked array
for (var x = 0; x < GRID_SIZE; x++) {
checked[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
checked[x][y] = false;
}
}
// Check horizontal matches
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE - 2; x++) {
var candy1 = self.getCandyAt(x, y);
var candy2 = self.getCandyAt(x + 1, y);
var candy3 = self.getCandyAt(x + 2, y);
if (candy1 && candy2 && candy3 && candy1.candyType === candy2.candyType && candy2.candyType === candy3.candyType) {
var match = [candy1, candy2, candy3];
// Extend match if possible
var checkX = x + 3;
while (checkX < GRID_SIZE) {
var nextCandy = self.getCandyAt(checkX, y);
if (nextCandy && nextCandy.candyType === candy1.candyType) {
match.push(nextCandy);
checkX++;
} else {
break;
}
}
matches.push(match);
x += match.length - 1;
}
}
}
// Check vertical matches
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE - 2; y++) {
var candy1 = self.getCandyAt(x, y);
var candy2 = self.getCandyAt(x, y + 1);
var candy3 = self.getCandyAt(x, y + 2);
if (candy1 && candy2 && candy3 && candy1.candyType === candy2.candyType && candy2.candyType === candy3.candyType) {
var match = [candy1, candy2, candy3];
// Extend match if possible
var checkY = y + 3;
while (checkY < GRID_SIZE) {
var nextCandy = self.getCandyAt(x, checkY);
if (nextCandy && nextCandy.candyType === candy1.candyType) {
match.push(nextCandy);
checkY++;
} else {
break;
}
}
matches.push(match);
y += match.length - 1;
}
}
}
return matches;
};
self.removeMatches = function (matches) {
var totalMatched = 0;
var matchesRemoved = 0;
var specialCandiesActivated = [];
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
totalMatched += match.length;
for (var j = 0; j < match.length; j++) {
var candy = match[j];
// Check if this is a special candy before removing
if (candy.isSpecial()) {
specialCandiesActivated.push({
candy: candy,
x: candy.gridX,
y: candy.gridY
});
}
self.grid[candy.gridX][candy.gridY] = null;
candy.animateMatch(function () {
matchesRemoved++;
if (matchesRemoved === totalMatched) {
self.activateSpecialCandies(specialCandiesActivated);
}
});
}
}
// Add score
var baseScore = 10;
var scoreToAdd = 0;
for (var i = 0; i < matches.length; i++) {
var matchSize = matches[i].length;
scoreToAdd += baseScore * matchSize * matchSize;
}
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
LK.getSound('match').play();
};
self.applyGravity = function () {
var needsUpdate = false;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (self.grid[x][y] === null) {
// Find candy above to fall down
for (var searchY = y - 1; searchY >= 0; searchY--) {
if (self.grid[x][searchY] !== null) {
var candy = self.grid[x][searchY];
self.grid[x][y] = candy;
self.grid[x][searchY] = null;
candy.gridY = y;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
candy.animateToPosition(candy.x, targetY, 400);
needsUpdate = true;
break;
}
}
}
}
}
if (needsUpdate) {
LK.setTimeout(function () {
self.fillGrid();
LK.setTimeout(function () {
self.checkForMatches();
}, 500);
}, 450);
}
};
self.activateSpecialCandies = function (specialCandies) {
var candiesRemoved = 0;
var totalToRemove = 0;
var hasClearAllCandy = false;
for (var i = 0; i < specialCandies.length; i++) {
var specialCandy = specialCandies[i];
if (specialCandy.candy.candyType === 8) {
// Candy 8 clears all candies
hasClearAllCandy = true;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (self.grid[x][y] !== null) {
totalToRemove++;
}
}
}
break;
} else if (specialCandy.candy.isHorizontalBreaker()) {
// Break entire horizontal line
for (var x = 0; x < GRID_SIZE; x++) {
if (self.grid[x][specialCandy.y] !== null) {
totalToRemove++;
}
}
} else if (specialCandy.candy.isVerticalBreaker()) {
// Break entire vertical line
for (var y = 0; y < GRID_SIZE; y++) {
if (self.grid[specialCandy.x][y] !== null) {
totalToRemove++;
}
}
}
}
if (totalToRemove === 0) {
self.applyGravity();
return;
}
if (hasClearAllCandy) {
// Remove all candies from the grid
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var candy = self.grid[x][y];
if (candy !== null) {
self.grid[x][y] = null;
candy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
self.applyGravity();
}
});
}
}
}
} else {
for (var i = 0; i < specialCandies.length; i++) {
var specialCandy = specialCandies[i];
if (specialCandy.candy.isHorizontalBreaker()) {
// Remove entire horizontal line
for (var x = 0; x < GRID_SIZE; x++) {
var candy = self.grid[x][specialCandy.y];
if (candy !== null) {
self.grid[x][specialCandy.y] = null;
candy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
self.applyGravity();
}
});
}
}
} else if (specialCandy.candy.isVerticalBreaker()) {
// Remove entire vertical line
for (var y = 0; y < GRID_SIZE; y++) {
var candy = self.grid[specialCandy.x][y];
if (candy !== null) {
self.grid[specialCandy.x][y] = null;
candy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
self.applyGravity();
}
});
}
}
}
}
}
};
self.getGridPosition = function (worldX, worldY) {
var localX = worldX - GRID_START_X;
var localY = worldY - GRID_START_Y;
if (localX < 0 || localY < 0 || localX >= GRID_SIZE * CELL_SIZE || localY >= GRID_SIZE * CELL_SIZE) {
return null;
}
return {
x: Math.floor(localX / CELL_SIZE),
y: Math.floor(localY / CELL_SIZE)
};
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// Constants
var GRID_SIZE = 8;
var CELL_SIZE = 220;
var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var GRID_START_Y = (2732 - GRID_SIZE * CELL_SIZE) / 2;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.setText(LK.getScore());
LK.gui.top.addChild(scoreTxt);
// Game grid
var grid = new Grid();
game.addChild(grid);
grid.initializeGrid();
// Input handling
var dragStart = null;
var dragCandy = null;
game.down = function (x, y, obj) {
if (grid.swapping) return;
var gridPos = grid.getGridPosition(x, y);
if (gridPos) {
var candy = grid.getCandyAt(gridPos.x, gridPos.y);
if (candy && !candy.isMoving) {
// Check if it's candy 8 (clear all candy)
if (candy.candyType === 8) {
// Create explosion effect
tween(candy, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clear all candies after explosion
var totalToRemove = 0;
var candiesRemoved = 0;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid.grid[x][y] !== null) {
totalToRemove++;
}
}
}
// Calculate score for clearing all candies
var scoreToAdd = totalToRemove * 50; // 50 points per candy cleared
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var gridCandy = grid.grid[x][y];
if (gridCandy !== null) {
grid.grid[x][y] = null;
gridCandy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
// Fill grid with new candies after clearing
LK.setTimeout(function () {
grid.fillGrid();
LK.setTimeout(function () {
grid.checkForMatches();
}, 300);
}, 200);
}
});
}
}
}
}
});
return; // Don't continue with normal drag behavior
}
// Check if it's candy 7 (horizontal line breaker)
if (candy.candyType === 7) {
// Create explosion effect
tween(candy, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clear entire horizontal line
var totalToRemove = 0;
var candiesRemoved = 0;
var lineY = candy.gridY;
// Count candies in the line
for (var x = 0; x < GRID_SIZE; x++) {
if (grid.grid[x][lineY] !== null) {
totalToRemove++;
}
}
// Calculate score for clearing the line
var scoreToAdd = totalToRemove * 30; // 30 points per candy cleared
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
// Remove candies from the horizontal line
for (var x = 0; x < GRID_SIZE; x++) {
var gridCandy = grid.grid[x][lineY];
if (gridCandy !== null) {
grid.grid[x][lineY] = null;
gridCandy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
// Apply gravity and refill after line is cleared
LK.setTimeout(function () {
grid.applyGravity();
}, 200);
}
});
}
}
}
});
return; // Don't continue with normal drag behavior
}
dragStart = {
x: x,
y: y
};
dragCandy = candy;
grid.selectedCandy = candy;
// Visual feedback
tween(candy, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut
});
}
}
};
game.move = function (x, y, obj) {
if (dragStart && dragCandy && !grid.swapping) {
var deltaX = x - dragStart.x;
var deltaY = y - dragStart.y;
var threshold = 60;
if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) {
var swapX = dragCandy.gridX;
var swapY = dragCandy.gridY;
// Determine swap direction
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swap
if (deltaX > 0) {
swapX += 1;
} else {
swapX -= 1;
}
} else {
// Vertical swap
if (deltaY > 0) {
swapY += 1;
} else {
swapY -= 1;
}
}
var targetCandy = grid.getCandyAt(swapX, swapY);
if (targetCandy) {
grid.swapCandies(dragCandy, targetCandy);
}
// Reset drag
dragStart = null;
dragCandy = null;
}
}
};
game.up = function (x, y, obj) {
if (dragCandy) {
// Reset visual feedback
tween(dragCandy, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
dragStart = null;
dragCandy = null;
grid.selectedCandy = null;
};
game.update = function () {
// Game loop runs automatically
// Grid handles its own updates through animations and match checking
}; /****
* 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.isMoving = false;
self.isMatched = false;
self.isSpecial = function () {
return self.candyType === 7 || self.candyType === 8;
};
self.isHorizontalBreaker = function () {
return self.candyType === 7;
};
self.isVerticalBreaker = function () {
return self.candyType === 8;
};
var candyGraphics = self.attachAsset('candy' + type, {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gx, gy) {
self.gridX = gx;
self.gridY = gy;
self.x = GRID_START_X + gx * CELL_SIZE + CELL_SIZE / 2;
self.y = GRID_START_Y + gy * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
if (!duration) duration = 300;
self.isMoving = true;
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isMoving = false;
if (onComplete) onComplete();
}
});
};
self.animateMatch = function (onComplete) {
self.isMatched = true;
tween(self, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.7
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0,
scaleY: 0,
alpha: 0
}, {
duration: 150,
easing: tween.easeIn,
onFinish: onComplete
});
}
});
};
return self;
});
var Grid = Container.expand(function () {
var self = Container.call(this);
self.grid = [];
self.selectedCandy = null;
self.swapping = false;
self.initializeGrid = function () {
// Create background cells
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var cell = self.attachAsset('gridCell', {
x: GRID_START_X + x * CELL_SIZE,
y: GRID_START_Y + y * CELL_SIZE,
alpha: 0.3
});
}
}
// Initialize grid array
for (var x = 0; x < GRID_SIZE; x++) {
self.grid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
self.grid[x][y] = null;
}
}
// Fill grid with candies
self.fillGrid();
};
self.fillGrid = function () {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (self.grid[x][y] === null) {
var candyType = self.getRandomCandyType();
var candy = new Candy(candyType);
candy.setGridPosition(x, y);
self.grid[x][y] = candy;
self.addChild(candy);
}
}
}
};
self.getRandomCandyType = function () {
// 0.5% chance for candy 8 (very rare)
if (Math.random() < 0.005) {
return 8; // Candy 8 is very rare
}
// 2% chance for candy 7 (horizontal line breaker)
if (Math.random() < 0.02) {
return 7; // Candy 7 is less rare
}
return Math.floor(Math.random() * 6) + 1;
};
self.getCandyAt = function (x, y) {
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) return null;
return self.grid[x][y];
};
self.swapCandies = function (candy1, candy2) {
if (self.swapping || !candy1 || !candy2) return;
self.swapping = true;
var tempX = candy1.gridX;
var tempY = candy1.gridY;
// Update grid positions
self.grid[candy1.gridX][candy1.gridY] = candy2;
self.grid[candy2.gridX][candy2.gridY] = candy1;
// Update candy grid positions
candy1.gridX = candy2.gridX;
candy1.gridY = candy2.gridY;
candy2.gridX = tempX;
candy2.gridY = tempY;
// Animate swap
var targetX1 = GRID_START_X + candy1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = GRID_START_Y + candy1.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = GRID_START_X + candy2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = GRID_START_Y + candy2.gridY * CELL_SIZE + CELL_SIZE / 2;
var swapsComplete = 0;
var onSwapComplete = function onSwapComplete() {
swapsComplete++;
if (swapsComplete === 2) {
LK.getSound('swap').play();
self.swapping = false;
self.checkForMatches();
}
};
candy1.animateToPosition(targetX1, targetY1, 250, onSwapComplete);
candy2.animateToPosition(targetX2, targetY2, 250, onSwapComplete);
};
self.checkForMatches = function () {
var matches = self.findMatches();
if (matches.length > 0) {
self.removeMatches(matches);
}
};
self.findMatches = function () {
var matches = [];
var checked = [];
// Initialize checked array
for (var x = 0; x < GRID_SIZE; x++) {
checked[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
checked[x][y] = false;
}
}
// Check horizontal matches
for (var y = 0; y < GRID_SIZE; y++) {
for (var x = 0; x < GRID_SIZE - 2; x++) {
var candy1 = self.getCandyAt(x, y);
var candy2 = self.getCandyAt(x + 1, y);
var candy3 = self.getCandyAt(x + 2, y);
if (candy1 && candy2 && candy3 && candy1.candyType === candy2.candyType && candy2.candyType === candy3.candyType) {
var match = [candy1, candy2, candy3];
// Extend match if possible
var checkX = x + 3;
while (checkX < GRID_SIZE) {
var nextCandy = self.getCandyAt(checkX, y);
if (nextCandy && nextCandy.candyType === candy1.candyType) {
match.push(nextCandy);
checkX++;
} else {
break;
}
}
matches.push(match);
x += match.length - 1;
}
}
}
// Check vertical matches
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE - 2; y++) {
var candy1 = self.getCandyAt(x, y);
var candy2 = self.getCandyAt(x, y + 1);
var candy3 = self.getCandyAt(x, y + 2);
if (candy1 && candy2 && candy3 && candy1.candyType === candy2.candyType && candy2.candyType === candy3.candyType) {
var match = [candy1, candy2, candy3];
// Extend match if possible
var checkY = y + 3;
while (checkY < GRID_SIZE) {
var nextCandy = self.getCandyAt(x, checkY);
if (nextCandy && nextCandy.candyType === candy1.candyType) {
match.push(nextCandy);
checkY++;
} else {
break;
}
}
matches.push(match);
y += match.length - 1;
}
}
}
return matches;
};
self.removeMatches = function (matches) {
var totalMatched = 0;
var matchesRemoved = 0;
var specialCandiesActivated = [];
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
totalMatched += match.length;
for (var j = 0; j < match.length; j++) {
var candy = match[j];
// Check if this is a special candy before removing
if (candy.isSpecial()) {
specialCandiesActivated.push({
candy: candy,
x: candy.gridX,
y: candy.gridY
});
}
self.grid[candy.gridX][candy.gridY] = null;
candy.animateMatch(function () {
matchesRemoved++;
if (matchesRemoved === totalMatched) {
self.activateSpecialCandies(specialCandiesActivated);
}
});
}
}
// Add score
var baseScore = 10;
var scoreToAdd = 0;
for (var i = 0; i < matches.length; i++) {
var matchSize = matches[i].length;
scoreToAdd += baseScore * matchSize * matchSize;
}
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
LK.getSound('match').play();
};
self.applyGravity = function () {
var needsUpdate = false;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (self.grid[x][y] === null) {
// Find candy above to fall down
for (var searchY = y - 1; searchY >= 0; searchY--) {
if (self.grid[x][searchY] !== null) {
var candy = self.grid[x][searchY];
self.grid[x][y] = candy;
self.grid[x][searchY] = null;
candy.gridY = y;
var targetY = GRID_START_Y + y * CELL_SIZE + CELL_SIZE / 2;
candy.animateToPosition(candy.x, targetY, 400);
needsUpdate = true;
break;
}
}
}
}
}
if (needsUpdate) {
LK.setTimeout(function () {
self.fillGrid();
LK.setTimeout(function () {
self.checkForMatches();
}, 500);
}, 450);
}
};
self.activateSpecialCandies = function (specialCandies) {
var candiesRemoved = 0;
var totalToRemove = 0;
var hasClearAllCandy = false;
for (var i = 0; i < specialCandies.length; i++) {
var specialCandy = specialCandies[i];
if (specialCandy.candy.candyType === 8) {
// Candy 8 clears all candies
hasClearAllCandy = true;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (self.grid[x][y] !== null) {
totalToRemove++;
}
}
}
break;
} else if (specialCandy.candy.isHorizontalBreaker()) {
// Break entire horizontal line
for (var x = 0; x < GRID_SIZE; x++) {
if (self.grid[x][specialCandy.y] !== null) {
totalToRemove++;
}
}
} else if (specialCandy.candy.isVerticalBreaker()) {
// Break entire vertical line
for (var y = 0; y < GRID_SIZE; y++) {
if (self.grid[specialCandy.x][y] !== null) {
totalToRemove++;
}
}
}
}
if (totalToRemove === 0) {
self.applyGravity();
return;
}
if (hasClearAllCandy) {
// Remove all candies from the grid
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var candy = self.grid[x][y];
if (candy !== null) {
self.grid[x][y] = null;
candy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
self.applyGravity();
}
});
}
}
}
} else {
for (var i = 0; i < specialCandies.length; i++) {
var specialCandy = specialCandies[i];
if (specialCandy.candy.isHorizontalBreaker()) {
// Remove entire horizontal line
for (var x = 0; x < GRID_SIZE; x++) {
var candy = self.grid[x][specialCandy.y];
if (candy !== null) {
self.grid[x][specialCandy.y] = null;
candy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
self.applyGravity();
}
});
}
}
} else if (specialCandy.candy.isVerticalBreaker()) {
// Remove entire vertical line
for (var y = 0; y < GRID_SIZE; y++) {
var candy = self.grid[specialCandy.x][y];
if (candy !== null) {
self.grid[specialCandy.x][y] = null;
candy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
self.applyGravity();
}
});
}
}
}
}
}
};
self.getGridPosition = function (worldX, worldY) {
var localX = worldX - GRID_START_X;
var localY = worldY - GRID_START_Y;
if (localX < 0 || localY < 0 || localX >= GRID_SIZE * CELL_SIZE || localY >= GRID_SIZE * CELL_SIZE) {
return null;
}
return {
x: Math.floor(localX / CELL_SIZE),
y: Math.floor(localY / CELL_SIZE)
};
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1A1A2E
});
/****
* Game Code
****/
// Constants
var GRID_SIZE = 8;
var CELL_SIZE = 220;
var GRID_START_X = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var GRID_START_Y = (2732 - GRID_SIZE * CELL_SIZE) / 2;
// Score display
var scoreTxt = new Text2('0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
scoreTxt.setText(LK.getScore());
LK.gui.top.addChild(scoreTxt);
// Game grid
var grid = new Grid();
game.addChild(grid);
grid.initializeGrid();
// Input handling
var dragStart = null;
var dragCandy = null;
game.down = function (x, y, obj) {
if (grid.swapping) return;
var gridPos = grid.getGridPosition(x, y);
if (gridPos) {
var candy = grid.getCandyAt(gridPos.x, gridPos.y);
if (candy && !candy.isMoving) {
// Check if it's candy 8 (clear all candy)
if (candy.candyType === 8) {
// Create explosion effect
tween(candy, {
scaleX: 3,
scaleY: 3,
alpha: 0
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clear all candies after explosion
var totalToRemove = 0;
var candiesRemoved = 0;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid.grid[x][y] !== null) {
totalToRemove++;
}
}
}
// Calculate score for clearing all candies
var scoreToAdd = totalToRemove * 50; // 50 points per candy cleared
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var gridCandy = grid.grid[x][y];
if (gridCandy !== null) {
grid.grid[x][y] = null;
gridCandy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
// Fill grid with new candies after clearing
LK.setTimeout(function () {
grid.fillGrid();
LK.setTimeout(function () {
grid.checkForMatches();
}, 300);
}, 200);
}
});
}
}
}
}
});
return; // Don't continue with normal drag behavior
}
// Check if it's candy 7 (horizontal line breaker)
if (candy.candyType === 7) {
// Create explosion effect
tween(candy, {
scaleX: 2.5,
scaleY: 2.5,
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
// Clear entire horizontal line
var totalToRemove = 0;
var candiesRemoved = 0;
var lineY = candy.gridY;
// Count candies in the line
for (var x = 0; x < GRID_SIZE; x++) {
if (grid.grid[x][lineY] !== null) {
totalToRemove++;
}
}
// Calculate score for clearing the line
var scoreToAdd = totalToRemove * 30; // 30 points per candy cleared
LK.setScore(LK.getScore() + scoreToAdd);
scoreTxt.setText(LK.getScore());
// Remove candies from the horizontal line
for (var x = 0; x < GRID_SIZE; x++) {
var gridCandy = grid.grid[x][lineY];
if (gridCandy !== null) {
grid.grid[x][lineY] = null;
gridCandy.animateMatch(function () {
candiesRemoved++;
if (candiesRemoved === totalToRemove) {
// Apply gravity and refill after line is cleared
LK.setTimeout(function () {
grid.applyGravity();
}, 200);
}
});
}
}
}
});
return; // Don't continue with normal drag behavior
}
dragStart = {
x: x,
y: y
};
dragCandy = candy;
grid.selectedCandy = candy;
// Visual feedback
tween(candy, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 100,
easing: tween.easeOut
});
}
}
};
game.move = function (x, y, obj) {
if (dragStart && dragCandy && !grid.swapping) {
var deltaX = x - dragStart.x;
var deltaY = y - dragStart.y;
var threshold = 60;
if (Math.abs(deltaX) > threshold || Math.abs(deltaY) > threshold) {
var swapX = dragCandy.gridX;
var swapY = dragCandy.gridY;
// Determine swap direction
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swap
if (deltaX > 0) {
swapX += 1;
} else {
swapX -= 1;
}
} else {
// Vertical swap
if (deltaY > 0) {
swapY += 1;
} else {
swapY -= 1;
}
}
var targetCandy = grid.getCandyAt(swapX, swapY);
if (targetCandy) {
grid.swapCandies(dragCandy, targetCandy);
}
// Reset drag
dragStart = null;
dragCandy = null;
}
}
};
game.up = function (x, y, obj) {
if (dragCandy) {
// Reset visual feedback
tween(dragCandy, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
easing: tween.easeOut
});
}
dragStart = null;
dragCandy = null;
grid.selectedCandy = null;
};
game.update = function () {
// Game loop runs automatically
// Grid handles its own updates through animations and match checking
};
Red candy. In-Game asset. 2d. High contrast. No shadows
Cyan candy. In-Game asset. 2d. High contrast. No shadows
Blue candy. In-Game asset. 2d. High contrast. No shadows
Orange candy. In-Game asset. 2d. High contrast. No shadows
Green candy. In-Game asset. 2d. High contrast. No shadows
Chocolate ball with candies. In-Game asset. 2d. High contrast. No shadows
Yellow candy. In-Game asset. 2d. High contrast. No shadows