User prompt
Zaman Baskısı
User prompt
son isteğimi kaldır
User prompt
Please fix the bug: 'Cannot read properties of undefined (reading 'length')' in or related to this line: 'for (var i = 0; i < powerUpData.length; i++) {' Line Number: 140
User prompt
alta seçilebilir özellikler olsun
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of null (reading 'gridX')' in or related to this line: 'explodeBomb(bombGem.gridX, bombGem.gridY);' Line Number: 542
User prompt
oklar ekle ve patlatınca bulunduğu sıranın hepsini patlatsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
eski bölüm arka plaanda kalmasın
User prompt
skor 500 olunca bölüm bitsin ve yeni bölüm başlasın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bomba patlaşasındada elşas başına 5 puan
User prompt
elşas başına 5 puan gelsin
User prompt
boşbayı patlatmak için yanındaki elmas ile yer değiştirmesi lazım ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bombayı patlatmak için başka bir mekanik ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
bomba ekle ve patladığında 3x3 bir alanı patlatsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
toplara patlama efekti ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (1 edits merged)
Please save this source code
User prompt
Gem Match Blitz
Initial prompt
candy crush tarzı bir oyun yapalım
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Gem = Container.expand(function (type) {
var self = Container.call(this);
self.gemType = type;
self.gridX = 0;
self.gridY = 0;
self.falling = false;
self.isBomb = type === 6;
self.isArrow = type === 7;
var gemAssets = ['redGem', 'blueGem', 'greenGem', 'yellowGem', 'purpleGem', 'orangeGem', 'bombGem', 'oklar'];
var gemGraphics = self.attachAsset(gemAssets[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = BOARD_OFFSET_X + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = BOARD_OFFSET_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeOut,
onFinish: onComplete
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var CELL_SIZE = 200;
var BOARD_SIZE = GRID_SIZE * CELL_SIZE;
var BOARD_OFFSET_X = (2048 - BOARD_SIZE) / 2;
var BOARD_OFFSET_Y = (2732 - BOARD_SIZE) / 2 - 200;
var grid = [];
var selectedGem = null;
var swapping = false;
var processingMatches = false;
var score = 0;
var cascadeMultiplier = 1;
var level = 1;
var levelTarget = 500;
var timeRemaining = 60;
var gameTimer = null;
var timerWarning = false;
// Initialize grid array
for (var x = 0; x < GRID_SIZE; x++) {
grid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
grid[x][y] = null;
}
}
// Create board background
var boardBg = game.attachAsset('board', {
anchorX: 0.5,
anchorY: 0.5,
x: BOARD_OFFSET_X + BOARD_SIZE / 2,
y: BOARD_OFFSET_Y + BOARD_SIZE / 2
});
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 150;
// Create level display
var levelTxt = new Text2('Level: 1', {
size: 100,
fill: 0xFFDD00
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 50;
// Create timer display
var timerTxt = new Text2('Time: 60', {
size: 80,
fill: 0xFF6666
});
timerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(timerTxt);
timerTxt.x = 120;
timerTxt.y = 50;
// Create power meter for bomb activation
var powerMeter = new Container();
var powerBg = LK.getAsset('board', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 2,
tint: 0x444444
});
var powerFill = LK.getAsset('board', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.08,
scaleY: 0,
tint: 0x00ff00
});
powerMeter.addChild(powerBg);
powerMeter.addChild(powerFill);
LK.gui.bottomRight.addChild(powerMeter);
powerMeter.x = -100;
powerMeter.y = -300;
var powerMeterTxt = new Text2('POWER', {
size: 40,
fill: 0xFFFFFF
});
powerMeterTxt.anchor.set(0.5, 0);
powerMeter.addChild(powerMeterTxt);
powerMeterTxt.y = -250;
var powerLevel = 0;
var maxPower = 100;
function createRandomGem(x, y, forceBomb, forceArrow) {
var gemType;
if (forceBomb) {
gemType = 6; // Bomb type
} else if (forceArrow) {
gemType = 7; // Arrow type
} else {
var rand = Math.random();
if (rand < 0.05) {
gemType = 6; // 5% chance for bomb
} else if (rand < 0.08) {
gemType = 7; // 3% chance for arrow
} else {
gemType = Math.floor(Math.random() * 6); // Regular gem
}
}
var gem = new Gem(gemType);
gem.setGridPosition(x, y);
game.addChild(gem);
grid[x][y] = gem;
return gem;
}
function initializeBoard() {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
createRandomGem(x, y);
}
}
// Remove initial matches to ensure valid starting board
while (findMatches().length > 0) {
var matches = findMatches();
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var newGem = createRandomGem(match.x, match.y);
match.gem.destroy();
grid[match.x][match.y] = newGem;
}
}
}
function findMatches() {
var matches = [];
// Check horizontal matches
for (var y = 0; y < GRID_SIZE; y++) {
var count = 1;
var currentType = grid[0][y] ? grid[0][y].gemType : -1;
for (var x = 1; x < GRID_SIZE; x++) {
var gem = grid[x][y];
if (gem && gem.gemType === currentType) {
count++;
} else {
if (count >= 3) {
for (var i = x - count; i < x; i++) {
matches.push({
x: i,
y: y,
gem: grid[i][y]
});
}
}
count = 1;
currentType = gem ? gem.gemType : -1;
}
}
if (count >= 3) {
for (var i = GRID_SIZE - count; i < GRID_SIZE; i++) {
matches.push({
x: i,
y: y,
gem: grid[i][y]
});
}
}
}
// Check vertical matches
for (var x = 0; x < GRID_SIZE; x++) {
var count = 1;
var currentType = grid[x][0] ? grid[x][0].gemType : -1;
for (var y = 1; y < GRID_SIZE; y++) {
var gem = grid[x][y];
if (gem && gem.gemType === currentType) {
count++;
} else {
if (count >= 3) {
for (var i = y - count; i < y; i++) {
matches.push({
x: x,
y: i,
gem: grid[x][i]
});
}
}
count = 1;
currentType = gem ? gem.gemType : -1;
}
}
if (count >= 3) {
for (var i = GRID_SIZE - count; i < GRID_SIZE; i++) {
matches.push({
x: x,
y: i,
gem: grid[x][i]
});
}
}
}
return matches;
}
function removeMatches() {
var matches = findMatches();
if (matches.length === 0) {
cascadeMultiplier = 1;
processingMatches = false;
return false;
}
// Check for bombs and arrows in matches and explode them
var bombsExploded = false;
var arrowsExploded = false;
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
if (match.gem && match.gem.isBomb) {
explodeBomb(match.x, match.y);
bombsExploded = true;
} else if (match.gem && match.gem.isArrow) {
explodeArrow(match.x, match.y);
arrowsExploded = true;
}
}
// Add score for regular matches
var baseScore = matches.length * 5;
var finalScore = baseScore * cascadeMultiplier;
if (doubleScoreActive) {
finalScore *= 2;
}
score += finalScore;
scoreTxt.setText('Score: ' + score);
// Add bonus time for good matches
if (matches.length >= 4) {
timeRemaining += 2; // 2 seconds bonus for 4+ matches
updateTimerDisplay();
LK.effects.flashObject(timerTxt, 0x00FF00, 300);
}
// Check for level completion
if (score >= levelTarget) {
completeLevel();
return false;
}
// Increase power level based on matches
powerLevel += matches.length * 5;
if (powerLevel > maxPower) powerLevel = maxPower;
updatePowerMeter();
// Remove matched gems with explosion effect (only non-bombs, as bombs are handled above)
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
if (match.gem && !match.gem.isBomb) {
// Create explosion effect
tween(match.gem, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (match.gem) {
match.gem.destroy();
}
}
});
LK.effects.flashObject(match.gem, 0xffffff, 200);
grid[match.x][match.y] = null;
}
}
if (bombsExploded || arrowsExploded) {
LK.getSound('explosion').play();
} else {
LK.getSound('match').play();
}
cascadeMultiplier++;
return true;
}
function dropGems() {
var gemsDropped = false;
for (var x = 0; x < GRID_SIZE; x++) {
// Collect existing gems from bottom to top
var gems = [];
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (grid[x][y]) {
gems.push(grid[x][y]);
grid[x][y] = null;
}
}
// Place gems at bottom
for (var i = 0; i < gems.length; i++) {
var newY = GRID_SIZE - 1 - i;
grid[x][newY] = gems[i];
gems[i].gridY = newY;
var targetY = BOARD_OFFSET_Y + newY * CELL_SIZE + CELL_SIZE / 2;
if (gems[i].y !== targetY) {
gems[i].animateToPosition(gems[i].x, targetY, 300);
gemsDropped = true;
}
}
// Fill empty spaces with new gems
for (var y = 0; y < GRID_SIZE - gems.length; y++) {
var newGem = createRandomGem(x, y);
newGem.y = BOARD_OFFSET_Y - (GRID_SIZE - gems.length - y) * CELL_SIZE + CELL_SIZE / 2;
newGem.animateToPosition(newGem.x, BOARD_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2, 300 + y * 50);
gemsDropped = true;
}
}
if (gemsDropped) {
LK.getSound('cascade').play();
}
return gemsDropped;
}
function updatePowerMeter() {
var fillPercentage = powerLevel / maxPower;
tween(powerFill, {
scaleY: fillPercentage * 2
}, {
duration: 300,
easing: tween.easeOut
});
// Change color based on power level
var color = powerLevel >= maxPower ? 0xff0000 : powerLevel >= 70 ? 0xffaa00 : 0x00ff00;
powerFill.tint = color;
}
var doubleScoreActive = false;
var doubleScoreTimer = null;
function startTimer() {
if (gameTimer) {
LK.clearInterval(gameTimer);
}
gameTimer = LK.setInterval(function () {
timeRemaining--;
updateTimerDisplay();
// Warning when 10 seconds left
if (timeRemaining <= 10 && !timerWarning) {
timerWarning = true;
timerTxt.fill = 0xFF0000;
LK.effects.flashObject(timerTxt, 0xFF0000, 200);
}
// Game over when time runs out
if (timeRemaining <= 0) {
LK.clearInterval(gameTimer);
LK.showGameOver();
}
}, 1000);
}
function updateTimerDisplay() {
timerTxt.setText('Time: ' + timeRemaining);
// Change color based on remaining time
if (timeRemaining <= 10) {
timerTxt.fill = 0xFF0000;
} else if (timeRemaining <= 20) {
timerTxt.fill = 0xFFAA00;
} else {
timerTxt.fill = 0xFF6666;
}
}
function resetTimer() {
if (gameTimer) {
LK.clearInterval(gameTimer);
}
timeRemaining = Math.max(60 - (level - 1) * 5, 30); // Decrease time each level, minimum 30 seconds
timerWarning = false;
updateTimerDisplay();
startTimer();
}
function completeLevel() {
level++;
score = 0;
powerLevel = 0;
cascadeMultiplier = 1;
selectedGem = null;
swapping = false;
processingMatches = false;
levelTxt.setText('Level: ' + level);
scoreTxt.setText('Score: 0');
updatePowerMeter();
resetTimer();
// Clear current board completely
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y]) {
grid[x][y].destroy();
grid[x][y] = null;
}
}
}
// Flash screen to indicate level completion
LK.effects.flashScreen(0x00ff00, 1000);
// Reinitialize board after flash
LK.setTimeout(function () {
initializeBoard();
}, 500);
}
function explodeArrow(arrowX, arrowY) {
var exploded = [];
// Destroy entire row
for (var x = 0; x < GRID_SIZE; x++) {
if (grid[x][arrowY]) {
exploded.push({
x: x,
y: arrowY,
gem: grid[x][arrowY]
});
}
}
// Animate explosion effect for all gems in row
for (var i = 0; i < exploded.length; i++) {
var explosion = exploded[i];
if (explosion.gem) {
// Create arrow explosion effect
tween(explosion.gem, {
scaleX: 2.5,
scaleY: 0.5,
alpha: 0,
rotation: Math.PI / 2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
if (explosion.gem) {
explosion.gem.destroy();
}
}
});
LK.effects.flashObject(explosion.gem, 0xffff00, 400);
grid[explosion.x][explosion.y] = null;
}
}
// Add score for each gem destroyed in arrow explosion (5 points per gem)
var arrowScore = exploded.length * 5 * cascadeMultiplier;
if (doubleScoreActive) {
arrowScore *= 2;
}
score += arrowScore;
scoreTxt.setText('Score: ' + score);
// Check for level completion
if (score >= levelTarget) {
LK.setTimeout(function () {
completeLevel();
}, 500);
}
LK.getSound('explosion').play();
return exploded.length > 0;
}
function explodeBomb(bombX, bombY) {
var exploded = [];
// Create 3x3 explosion area around bomb
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
var x = bombX + dx;
var y = bombY + dy;
if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE && grid[x][y]) {
exploded.push({
x: x,
y: y,
gem: grid[x][y]
});
}
}
}
// Animate explosion effect for all gems in 3x3 area
for (var i = 0; i < exploded.length; i++) {
var explosion = exploded[i];
if (explosion.gem) {
// Create bigger explosion effect for bomb
tween(explosion.gem, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0,
rotation: Math.PI
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (explosion.gem) {
explosion.gem.destroy();
}
}
});
LK.effects.flashObject(explosion.gem, 0xff4400, 300);
grid[explosion.x][explosion.y] = null;
}
}
// Add score for each gem destroyed in bomb explosion (5 points per gem)
var bombScore = exploded.length * 5 * cascadeMultiplier;
if (doubleScoreActive) {
bombScore *= 2;
}
score += bombScore;
scoreTxt.setText('Score: ' + score);
// Check for level completion
if (score >= levelTarget) {
LK.setTimeout(function () {
completeLevel();
}, 500);
}
LK.getSound('explosion').play();
return exploded.length > 0;
}
function isValidSwap(gem1, gem2) {
var dx = Math.abs(gem1.gridX - gem2.gridX);
var dy = Math.abs(gem1.gridY - gem2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapGems(gem1, gem2) {
if (swapping || !isValidSwap(gem1, gem2)) return;
swapping = true;
// Check if either gem is a bomb or arrow
var bombGem = null;
var arrowGem = null;
var normalGem = null;
if (gem1.isBomb && !gem2.isBomb && !gem2.isArrow) {
bombGem = gem1;
normalGem = gem2;
} else if (gem2.isBomb && !gem1.isBomb && !gem1.isArrow) {
bombGem = gem2;
normalGem = gem1;
} else if (gem1.isArrow && !gem2.isBomb && !gem2.isArrow) {
arrowGem = gem1;
normalGem = gem2;
} else if (gem2.isArrow && !gem1.isBomb && !gem1.isArrow) {
arrowGem = gem2;
normalGem = gem1;
}
// If swapping bomb with normal gem, trigger explosion
if (bombGem && normalGem) {
// Animate gems swapping briefly
var targetX1 = BOARD_OFFSET_X + gem2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + gem2.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + gem1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + gem1.gridY * CELL_SIZE + CELL_SIZE / 2;
gem1.animateToPosition(targetX1, targetY1, 150);
gem2.animateToPosition(targetX2, targetY2, 150);
// Trigger bomb explosion after brief swap animation
LK.setTimeout(function () {
explodeBomb(bombGem.gridX, bombGem.gridY);
processingMatches = true;
cascadeMultiplier = 1;
swapping = false;
LK.getSound('swap').play();
}, 200);
return;
}
// If swapping arrow with normal gem, trigger arrow explosion
if (arrowGem && normalGem) {
// Animate gems swapping briefly
var targetX1 = BOARD_OFFSET_X + gem2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + gem2.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + gem1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + gem1.gridY * CELL_SIZE + CELL_SIZE / 2;
gem1.animateToPosition(targetX1, targetY1, 150);
gem2.animateToPosition(targetX2, targetY2, 150);
// Trigger arrow explosion after brief swap animation
LK.setTimeout(function () {
explodeArrow(arrowGem.gridX, arrowGem.gridY);
processingMatches = true;
cascadeMultiplier = 1;
swapping = false;
LK.getSound('swap').play();
}, 200);
return;
}
// If swapping arrow with normal gem, trigger arrow explosion
if (arrowGem && normalGem) {
// Animate gems swapping briefly
var targetX1 = BOARD_OFFSET_X + gem2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + gem2.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + gem1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + gem1.gridY * CELL_SIZE + CELL_SIZE / 2;
gem1.animateToPosition(targetX1, targetY1, 150);
gem2.animateToPosition(targetX2, targetY2, 150);
// Trigger arrow explosion after brief swap animation
LK.setTimeout(function () {
explodeArrow(arrowGem.gridX, arrowGem.gridY);
processingMatches = true;
cascadeMultiplier = 1;
swapping = false;
LK.getSound('swap').play();
}, 200);
return;
}
// Store original positions
var x1 = gem1.gridX,
y1 = gem1.gridY;
var x2 = gem2.gridX,
y2 = gem2.gridY;
// Update grid
grid[x1][y1] = gem2;
grid[x2][y2] = gem1;
// Update gem positions
gem1.gridX = x2;
gem1.gridY = y2;
gem2.gridX = x1;
gem2.gridY = y1;
// Animate swap
var targetX1 = BOARD_OFFSET_X + x2 * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + y2 * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + x1 * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + y1 * CELL_SIZE + CELL_SIZE / 2;
var swapsCompleted = 0;
function onSwapComplete() {
swapsCompleted++;
if (swapsCompleted === 2) {
// Check if swap created matches
if (findMatches().length > 0) {
LK.getSound('swap').play();
processingMatches = true;
cascadeMultiplier = 1;
} else {
// Swap back if no matches
grid[x1][y1] = gem1;
grid[x2][y2] = gem2;
gem1.gridX = x1;
gem1.gridY = y1;
gem2.gridX = x2;
gem2.gridY = y2;
gem1.animateToPosition(BOARD_OFFSET_X + x1 * CELL_SIZE + CELL_SIZE / 2, BOARD_OFFSET_Y + y1 * CELL_SIZE + CELL_SIZE / 2, 200);
gem2.animateToPosition(BOARD_OFFSET_X + x2 * CELL_SIZE + CELL_SIZE / 2, BOARD_OFFSET_Y + y2 * CELL_SIZE + CELL_SIZE / 2, 200);
}
swapping = false;
}
}
gem1.animateToPosition(targetX1, targetY1, 300, onSwapComplete);
gem2.animateToPosition(targetX2, targetY2, 300, onSwapComplete);
}
function getGemAt(x, y) {
var gridX = Math.floor((x - BOARD_OFFSET_X) / CELL_SIZE);
var gridY = Math.floor((y - BOARD_OFFSET_Y) / CELL_SIZE);
if (gridX >= 0 && gridX < GRID_SIZE && gridY >= 0 && gridY < GRID_SIZE) {
return grid[gridX][gridY];
}
return null;
}
game.down = function (x, y, obj) {
if (swapping || processingMatches) return;
var gem = getGemAt(x, y);
if (gem) {
if (selectedGem) {
if (selectedGem === gem) {
// Deselect
tween.stop(selectedGem, {
scaleX: true,
scaleY: true
});
tween(selectedGem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
selectedGem = null;
} else {
// Try to swap
swapGems(selectedGem, gem);
tween.stop(selectedGem, {
scaleX: true,
scaleY: true
});
tween(selectedGem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
selectedGem = null;
}
} else {
// Select gem
selectedGem = gem;
tween(gem, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
}
}
};
game.update = function () {
if (processingMatches && !swapping) {
if (removeMatches()) {
LK.setTimeout(function () {
if (dropGems()) {
LK.setTimeout(function () {
processingMatches = true;
}, 400);
} else {
processingMatches = false;
cascadeMultiplier = 1;
}
}, 300);
} else {
dropGems();
}
}
};
// Initialize the game
initializeBoard();
startTimer(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Gem = Container.expand(function (type) {
var self = Container.call(this);
self.gemType = type;
self.gridX = 0;
self.gridY = 0;
self.falling = false;
self.isBomb = type === 6;
self.isArrow = type === 7;
var gemAssets = ['redGem', 'blueGem', 'greenGem', 'yellowGem', 'purpleGem', 'orangeGem', 'bombGem', 'oklar'];
var gemGraphics = self.attachAsset(gemAssets[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.setGridPosition = function (gridX, gridY) {
self.gridX = gridX;
self.gridY = gridY;
self.x = BOARD_OFFSET_X + gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = BOARD_OFFSET_Y + gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.animateToPosition = function (targetX, targetY, duration, onComplete) {
tween(self, {
x: targetX,
y: targetY
}, {
duration: duration || 300,
easing: tween.easeOut,
onFinish: onComplete
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var CELL_SIZE = 200;
var BOARD_SIZE = GRID_SIZE * CELL_SIZE;
var BOARD_OFFSET_X = (2048 - BOARD_SIZE) / 2;
var BOARD_OFFSET_Y = (2732 - BOARD_SIZE) / 2 - 200;
var grid = [];
var selectedGem = null;
var swapping = false;
var processingMatches = false;
var score = 0;
var cascadeMultiplier = 1;
var level = 1;
var levelTarget = 500;
var timeRemaining = 60;
var gameTimer = null;
var timerWarning = false;
// Initialize grid array
for (var x = 0; x < GRID_SIZE; x++) {
grid[x] = [];
for (var y = 0; y < GRID_SIZE; y++) {
grid[x][y] = null;
}
}
// Create board background
var boardBg = game.attachAsset('board', {
anchorX: 0.5,
anchorY: 0.5,
x: BOARD_OFFSET_X + BOARD_SIZE / 2,
y: BOARD_OFFSET_Y + BOARD_SIZE / 2
});
// Create score display
var scoreTxt = new Text2('Score: 0', {
size: 120,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 150;
// Create level display
var levelTxt = new Text2('Level: 1', {
size: 100,
fill: 0xFFDD00
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 50;
// Create timer display
var timerTxt = new Text2('Time: 60', {
size: 80,
fill: 0xFF6666
});
timerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(timerTxt);
timerTxt.x = 120;
timerTxt.y = 50;
// Create power meter for bomb activation
var powerMeter = new Container();
var powerBg = LK.getAsset('board', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 2,
tint: 0x444444
});
var powerFill = LK.getAsset('board', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.08,
scaleY: 0,
tint: 0x00ff00
});
powerMeter.addChild(powerBg);
powerMeter.addChild(powerFill);
LK.gui.bottomRight.addChild(powerMeter);
powerMeter.x = -100;
powerMeter.y = -300;
var powerMeterTxt = new Text2('POWER', {
size: 40,
fill: 0xFFFFFF
});
powerMeterTxt.anchor.set(0.5, 0);
powerMeter.addChild(powerMeterTxt);
powerMeterTxt.y = -250;
var powerLevel = 0;
var maxPower = 100;
function createRandomGem(x, y, forceBomb, forceArrow) {
var gemType;
if (forceBomb) {
gemType = 6; // Bomb type
} else if (forceArrow) {
gemType = 7; // Arrow type
} else {
var rand = Math.random();
if (rand < 0.05) {
gemType = 6; // 5% chance for bomb
} else if (rand < 0.08) {
gemType = 7; // 3% chance for arrow
} else {
gemType = Math.floor(Math.random() * 6); // Regular gem
}
}
var gem = new Gem(gemType);
gem.setGridPosition(x, y);
game.addChild(gem);
grid[x][y] = gem;
return gem;
}
function initializeBoard() {
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
createRandomGem(x, y);
}
}
// Remove initial matches to ensure valid starting board
while (findMatches().length > 0) {
var matches = findMatches();
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var newGem = createRandomGem(match.x, match.y);
match.gem.destroy();
grid[match.x][match.y] = newGem;
}
}
}
function findMatches() {
var matches = [];
// Check horizontal matches
for (var y = 0; y < GRID_SIZE; y++) {
var count = 1;
var currentType = grid[0][y] ? grid[0][y].gemType : -1;
for (var x = 1; x < GRID_SIZE; x++) {
var gem = grid[x][y];
if (gem && gem.gemType === currentType) {
count++;
} else {
if (count >= 3) {
for (var i = x - count; i < x; i++) {
matches.push({
x: i,
y: y,
gem: grid[i][y]
});
}
}
count = 1;
currentType = gem ? gem.gemType : -1;
}
}
if (count >= 3) {
for (var i = GRID_SIZE - count; i < GRID_SIZE; i++) {
matches.push({
x: i,
y: y,
gem: grid[i][y]
});
}
}
}
// Check vertical matches
for (var x = 0; x < GRID_SIZE; x++) {
var count = 1;
var currentType = grid[x][0] ? grid[x][0].gemType : -1;
for (var y = 1; y < GRID_SIZE; y++) {
var gem = grid[x][y];
if (gem && gem.gemType === currentType) {
count++;
} else {
if (count >= 3) {
for (var i = y - count; i < y; i++) {
matches.push({
x: x,
y: i,
gem: grid[x][i]
});
}
}
count = 1;
currentType = gem ? gem.gemType : -1;
}
}
if (count >= 3) {
for (var i = GRID_SIZE - count; i < GRID_SIZE; i++) {
matches.push({
x: x,
y: i,
gem: grid[x][i]
});
}
}
}
return matches;
}
function removeMatches() {
var matches = findMatches();
if (matches.length === 0) {
cascadeMultiplier = 1;
processingMatches = false;
return false;
}
// Check for bombs and arrows in matches and explode them
var bombsExploded = false;
var arrowsExploded = false;
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
if (match.gem && match.gem.isBomb) {
explodeBomb(match.x, match.y);
bombsExploded = true;
} else if (match.gem && match.gem.isArrow) {
explodeArrow(match.x, match.y);
arrowsExploded = true;
}
}
// Add score for regular matches
var baseScore = matches.length * 5;
var finalScore = baseScore * cascadeMultiplier;
if (doubleScoreActive) {
finalScore *= 2;
}
score += finalScore;
scoreTxt.setText('Score: ' + score);
// Add bonus time for good matches
if (matches.length >= 4) {
timeRemaining += 2; // 2 seconds bonus for 4+ matches
updateTimerDisplay();
LK.effects.flashObject(timerTxt, 0x00FF00, 300);
}
// Check for level completion
if (score >= levelTarget) {
completeLevel();
return false;
}
// Increase power level based on matches
powerLevel += matches.length * 5;
if (powerLevel > maxPower) powerLevel = maxPower;
updatePowerMeter();
// Remove matched gems with explosion effect (only non-bombs, as bombs are handled above)
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
if (match.gem && !match.gem.isBomb) {
// Create explosion effect
tween(match.gem, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (match.gem) {
match.gem.destroy();
}
}
});
LK.effects.flashObject(match.gem, 0xffffff, 200);
grid[match.x][match.y] = null;
}
}
if (bombsExploded || arrowsExploded) {
LK.getSound('explosion').play();
} else {
LK.getSound('match').play();
}
cascadeMultiplier++;
return true;
}
function dropGems() {
var gemsDropped = false;
for (var x = 0; x < GRID_SIZE; x++) {
// Collect existing gems from bottom to top
var gems = [];
for (var y = GRID_SIZE - 1; y >= 0; y--) {
if (grid[x][y]) {
gems.push(grid[x][y]);
grid[x][y] = null;
}
}
// Place gems at bottom
for (var i = 0; i < gems.length; i++) {
var newY = GRID_SIZE - 1 - i;
grid[x][newY] = gems[i];
gems[i].gridY = newY;
var targetY = BOARD_OFFSET_Y + newY * CELL_SIZE + CELL_SIZE / 2;
if (gems[i].y !== targetY) {
gems[i].animateToPosition(gems[i].x, targetY, 300);
gemsDropped = true;
}
}
// Fill empty spaces with new gems
for (var y = 0; y < GRID_SIZE - gems.length; y++) {
var newGem = createRandomGem(x, y);
newGem.y = BOARD_OFFSET_Y - (GRID_SIZE - gems.length - y) * CELL_SIZE + CELL_SIZE / 2;
newGem.animateToPosition(newGem.x, BOARD_OFFSET_Y + y * CELL_SIZE + CELL_SIZE / 2, 300 + y * 50);
gemsDropped = true;
}
}
if (gemsDropped) {
LK.getSound('cascade').play();
}
return gemsDropped;
}
function updatePowerMeter() {
var fillPercentage = powerLevel / maxPower;
tween(powerFill, {
scaleY: fillPercentage * 2
}, {
duration: 300,
easing: tween.easeOut
});
// Change color based on power level
var color = powerLevel >= maxPower ? 0xff0000 : powerLevel >= 70 ? 0xffaa00 : 0x00ff00;
powerFill.tint = color;
}
var doubleScoreActive = false;
var doubleScoreTimer = null;
function startTimer() {
if (gameTimer) {
LK.clearInterval(gameTimer);
}
gameTimer = LK.setInterval(function () {
timeRemaining--;
updateTimerDisplay();
// Warning when 10 seconds left
if (timeRemaining <= 10 && !timerWarning) {
timerWarning = true;
timerTxt.fill = 0xFF0000;
LK.effects.flashObject(timerTxt, 0xFF0000, 200);
}
// Game over when time runs out
if (timeRemaining <= 0) {
LK.clearInterval(gameTimer);
LK.showGameOver();
}
}, 1000);
}
function updateTimerDisplay() {
timerTxt.setText('Time: ' + timeRemaining);
// Change color based on remaining time
if (timeRemaining <= 10) {
timerTxt.fill = 0xFF0000;
} else if (timeRemaining <= 20) {
timerTxt.fill = 0xFFAA00;
} else {
timerTxt.fill = 0xFF6666;
}
}
function resetTimer() {
if (gameTimer) {
LK.clearInterval(gameTimer);
}
timeRemaining = Math.max(60 - (level - 1) * 5, 30); // Decrease time each level, minimum 30 seconds
timerWarning = false;
updateTimerDisplay();
startTimer();
}
function completeLevel() {
level++;
score = 0;
powerLevel = 0;
cascadeMultiplier = 1;
selectedGem = null;
swapping = false;
processingMatches = false;
levelTxt.setText('Level: ' + level);
scoreTxt.setText('Score: 0');
updatePowerMeter();
resetTimer();
// Clear current board completely
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y]) {
grid[x][y].destroy();
grid[x][y] = null;
}
}
}
// Flash screen to indicate level completion
LK.effects.flashScreen(0x00ff00, 1000);
// Reinitialize board after flash
LK.setTimeout(function () {
initializeBoard();
}, 500);
}
function explodeArrow(arrowX, arrowY) {
var exploded = [];
// Destroy entire row
for (var x = 0; x < GRID_SIZE; x++) {
if (grid[x][arrowY]) {
exploded.push({
x: x,
y: arrowY,
gem: grid[x][arrowY]
});
}
}
// Animate explosion effect for all gems in row
for (var i = 0; i < exploded.length; i++) {
var explosion = exploded[i];
if (explosion.gem) {
// Create arrow explosion effect
tween(explosion.gem, {
scaleX: 2.5,
scaleY: 0.5,
alpha: 0,
rotation: Math.PI / 2
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
if (explosion.gem) {
explosion.gem.destroy();
}
}
});
LK.effects.flashObject(explosion.gem, 0xffff00, 400);
grid[explosion.x][explosion.y] = null;
}
}
// Add score for each gem destroyed in arrow explosion (5 points per gem)
var arrowScore = exploded.length * 5 * cascadeMultiplier;
if (doubleScoreActive) {
arrowScore *= 2;
}
score += arrowScore;
scoreTxt.setText('Score: ' + score);
// Check for level completion
if (score >= levelTarget) {
LK.setTimeout(function () {
completeLevel();
}, 500);
}
LK.getSound('explosion').play();
return exploded.length > 0;
}
function explodeBomb(bombX, bombY) {
var exploded = [];
// Create 3x3 explosion area around bomb
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
var x = bombX + dx;
var y = bombY + dy;
if (x >= 0 && x < GRID_SIZE && y >= 0 && y < GRID_SIZE && grid[x][y]) {
exploded.push({
x: x,
y: y,
gem: grid[x][y]
});
}
}
}
// Animate explosion effect for all gems in 3x3 area
for (var i = 0; i < exploded.length; i++) {
var explosion = exploded[i];
if (explosion.gem) {
// Create bigger explosion effect for bomb
tween(explosion.gem, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0,
rotation: Math.PI
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (explosion.gem) {
explosion.gem.destroy();
}
}
});
LK.effects.flashObject(explosion.gem, 0xff4400, 300);
grid[explosion.x][explosion.y] = null;
}
}
// Add score for each gem destroyed in bomb explosion (5 points per gem)
var bombScore = exploded.length * 5 * cascadeMultiplier;
if (doubleScoreActive) {
bombScore *= 2;
}
score += bombScore;
scoreTxt.setText('Score: ' + score);
// Check for level completion
if (score >= levelTarget) {
LK.setTimeout(function () {
completeLevel();
}, 500);
}
LK.getSound('explosion').play();
return exploded.length > 0;
}
function isValidSwap(gem1, gem2) {
var dx = Math.abs(gem1.gridX - gem2.gridX);
var dy = Math.abs(gem1.gridY - gem2.gridY);
return dx === 1 && dy === 0 || dx === 0 && dy === 1;
}
function swapGems(gem1, gem2) {
if (swapping || !isValidSwap(gem1, gem2)) return;
swapping = true;
// Check if either gem is a bomb or arrow
var bombGem = null;
var arrowGem = null;
var normalGem = null;
if (gem1.isBomb && !gem2.isBomb && !gem2.isArrow) {
bombGem = gem1;
normalGem = gem2;
} else if (gem2.isBomb && !gem1.isBomb && !gem1.isArrow) {
bombGem = gem2;
normalGem = gem1;
} else if (gem1.isArrow && !gem2.isBomb && !gem2.isArrow) {
arrowGem = gem1;
normalGem = gem2;
} else if (gem2.isArrow && !gem1.isBomb && !gem1.isArrow) {
arrowGem = gem2;
normalGem = gem1;
}
// If swapping bomb with normal gem, trigger explosion
if (bombGem && normalGem) {
// Animate gems swapping briefly
var targetX1 = BOARD_OFFSET_X + gem2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + gem2.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + gem1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + gem1.gridY * CELL_SIZE + CELL_SIZE / 2;
gem1.animateToPosition(targetX1, targetY1, 150);
gem2.animateToPosition(targetX2, targetY2, 150);
// Trigger bomb explosion after brief swap animation
LK.setTimeout(function () {
explodeBomb(bombGem.gridX, bombGem.gridY);
processingMatches = true;
cascadeMultiplier = 1;
swapping = false;
LK.getSound('swap').play();
}, 200);
return;
}
// If swapping arrow with normal gem, trigger arrow explosion
if (arrowGem && normalGem) {
// Animate gems swapping briefly
var targetX1 = BOARD_OFFSET_X + gem2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + gem2.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + gem1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + gem1.gridY * CELL_SIZE + CELL_SIZE / 2;
gem1.animateToPosition(targetX1, targetY1, 150);
gem2.animateToPosition(targetX2, targetY2, 150);
// Trigger arrow explosion after brief swap animation
LK.setTimeout(function () {
explodeArrow(arrowGem.gridX, arrowGem.gridY);
processingMatches = true;
cascadeMultiplier = 1;
swapping = false;
LK.getSound('swap').play();
}, 200);
return;
}
// If swapping arrow with normal gem, trigger arrow explosion
if (arrowGem && normalGem) {
// Animate gems swapping briefly
var targetX1 = BOARD_OFFSET_X + gem2.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + gem2.gridY * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + gem1.gridX * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + gem1.gridY * CELL_SIZE + CELL_SIZE / 2;
gem1.animateToPosition(targetX1, targetY1, 150);
gem2.animateToPosition(targetX2, targetY2, 150);
// Trigger arrow explosion after brief swap animation
LK.setTimeout(function () {
explodeArrow(arrowGem.gridX, arrowGem.gridY);
processingMatches = true;
cascadeMultiplier = 1;
swapping = false;
LK.getSound('swap').play();
}, 200);
return;
}
// Store original positions
var x1 = gem1.gridX,
y1 = gem1.gridY;
var x2 = gem2.gridX,
y2 = gem2.gridY;
// Update grid
grid[x1][y1] = gem2;
grid[x2][y2] = gem1;
// Update gem positions
gem1.gridX = x2;
gem1.gridY = y2;
gem2.gridX = x1;
gem2.gridY = y1;
// Animate swap
var targetX1 = BOARD_OFFSET_X + x2 * CELL_SIZE + CELL_SIZE / 2;
var targetY1 = BOARD_OFFSET_Y + y2 * CELL_SIZE + CELL_SIZE / 2;
var targetX2 = BOARD_OFFSET_X + x1 * CELL_SIZE + CELL_SIZE / 2;
var targetY2 = BOARD_OFFSET_Y + y1 * CELL_SIZE + CELL_SIZE / 2;
var swapsCompleted = 0;
function onSwapComplete() {
swapsCompleted++;
if (swapsCompleted === 2) {
// Check if swap created matches
if (findMatches().length > 0) {
LK.getSound('swap').play();
processingMatches = true;
cascadeMultiplier = 1;
} else {
// Swap back if no matches
grid[x1][y1] = gem1;
grid[x2][y2] = gem2;
gem1.gridX = x1;
gem1.gridY = y1;
gem2.gridX = x2;
gem2.gridY = y2;
gem1.animateToPosition(BOARD_OFFSET_X + x1 * CELL_SIZE + CELL_SIZE / 2, BOARD_OFFSET_Y + y1 * CELL_SIZE + CELL_SIZE / 2, 200);
gem2.animateToPosition(BOARD_OFFSET_X + x2 * CELL_SIZE + CELL_SIZE / 2, BOARD_OFFSET_Y + y2 * CELL_SIZE + CELL_SIZE / 2, 200);
}
swapping = false;
}
}
gem1.animateToPosition(targetX1, targetY1, 300, onSwapComplete);
gem2.animateToPosition(targetX2, targetY2, 300, onSwapComplete);
}
function getGemAt(x, y) {
var gridX = Math.floor((x - BOARD_OFFSET_X) / CELL_SIZE);
var gridY = Math.floor((y - BOARD_OFFSET_Y) / CELL_SIZE);
if (gridX >= 0 && gridX < GRID_SIZE && gridY >= 0 && gridY < GRID_SIZE) {
return grid[gridX][gridY];
}
return null;
}
game.down = function (x, y, obj) {
if (swapping || processingMatches) return;
var gem = getGemAt(x, y);
if (gem) {
if (selectedGem) {
if (selectedGem === gem) {
// Deselect
tween.stop(selectedGem, {
scaleX: true,
scaleY: true
});
tween(selectedGem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
selectedGem = null;
} else {
// Try to swap
swapGems(selectedGem, gem);
tween.stop(selectedGem, {
scaleX: true,
scaleY: true
});
tween(selectedGem, {
scaleX: 1,
scaleY: 1
}, {
duration: 200
});
selectedGem = null;
}
} else {
// Select gem
selectedGem = gem;
tween(gem, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
}
}
};
game.update = function () {
if (processingMatches && !swapping) {
if (removeMatches()) {
LK.setTimeout(function () {
if (dropGems()) {
LK.setTimeout(function () {
processingMatches = true;
}, 400);
} else {
processingMatches = false;
cascadeMultiplier = 1;
}
}, 300);
} else {
dropGems();
}
}
};
// Initialize the game
initializeBoard();
startTimer();
mavi bir elmas. In-Game asset. 2d. High contrast. No shadows
yeşil elmas. In-Game asset. 2d. High contrast. No shadows
turuncu elmas. In-Game asset. 2d. High contrast. No shadows
mor elmas. In-Game asset. 2d. High contrast. No shadows
kırmızı elmas. In-Game asset. 2d. High contrast. No shadows
sarı elmas. In-Game asset. 2d. High contrast. No shadows
bomba. In-Game asset. 2d. High contrast. No shadows
çift tarafl ok. In-Game asset. 2d. High contrast. No shadows