User prompt
Oyuna basit bir başlangıç ekranı ekle bu ekranda "Start" butonu ve "Options" butonu olsun Options Butonuna tıkladığımız zaman açılan bölümde ses seviyesi bulunsun bunu değiştirebilelim ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Oyuna puan sistemi ekle alt kisımda puanımiz yazsın her bir patlayan gem için 10 puan eklensin
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '8')' in or related to this line: 'if (grid[x][y]) {' Line Number: 503
User prompt
Some bombs and gems can fit into each other. Fix this issue.
User prompt
Bazı gemler patladıgı zaman alt kısımlarda 1x1 alana sahip bölgeler boş kaliyor bunu düzelt bir nesne patladığı zaman hemen o kalan boşlukları üstten gelen bomba gem ve benzeri nesneler doldursun
User prompt
Oyuna bomba mekaniği ekle patladığı zaman 3x3 alana sahip bir bölgeyi patlatsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Bir topun altındaki blok gidince o topun aşagı düşmesini sağla
Code edit (1 edits merged)
Please save this source code
User prompt
Gem Cascade
Initial prompt
Design me a game similar to Candy Crush, and in addition to the game, make sure that the coefficient of the points we earn increases after reaching a certain score.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Gem = Container.expand(function () {
var self = Container.call(this);
self.gemType = 0;
self.gridX = 0;
self.gridY = 0;
self.graphics = null;
self.isSelected = false;
self.isMatched = false;
self.isFalling = false;
self.isBomb = false;
self.init = function (type, gx, gy) {
self.gemType = type;
self.gridX = gx;
self.gridY = gy;
var gemTypes = ['gemRed', 'gemBlue', 'gemGreen', 'gemYellow', 'gemPurple', 'gemOrange', 'gemBomb'];
if (type === 6) {
self.isBomb = true;
}
self.graphics = self.attachAsset(gemTypes[type], {
anchorX: 0.5,
anchorY: 0.5
});
self.updatePosition();
};
self.updatePosition = function () {
var startX = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var startY = 400;
self.x = startX + self.gridX * CELL_SIZE + CELL_SIZE / 2;
self.y = startY + self.gridY * CELL_SIZE + CELL_SIZE / 2;
};
self.setSelected = function (selected) {
self.isSelected = selected;
if (selected) {
self.graphics.alpha = 0.7;
tween(self.graphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200
});
} else {
self.graphics.alpha = 1.0;
tween(self.graphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
};
self.fallTo = function (newY, callback) {
self.isFalling = true;
self.gridY = newY;
var newPosY = 400 + newY * CELL_SIZE + CELL_SIZE / 2;
tween(self, {
y: newPosY
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
self.isFalling = false;
if (callback) callback();
}
});
};
self.destroy = function () {
self.isMatched = true;
tween(self.graphics, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
self.explodeBomb = function () {
if (!self.isBomb) return;
// Create explosion effect
tween(self.graphics, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
// Mark gems in 3x3 area for destruction
var gemsToDestroy = [];
for (var dx = -1; dx <= 1; dx++) {
for (var dy = -1; dy <= 1; dy++) {
var targetX = self.gridX + dx;
var targetY = self.gridY + dy;
if (targetX >= 0 && targetX < GRID_SIZE && targetY >= 0 && targetY < GRID_SIZE) {
if (grid[targetX][targetY] && !grid[targetX][targetY].isMatched) {
gemsToDestroy.push({
x: targetX,
y: targetY
});
}
}
}
}
// Destroy gems with delay for visual effect
for (var i = 0; i < gemsToDestroy.length; i++) {
(function (destroyData) {
LK.setTimeout(function () {
if (grid[destroyData.x][destroyData.y]) {
grid[destroyData.x][destroyData.y].destroy();
grid[destroyData.x][destroyData.y] = null;
}
}, i * 50);
})(gemsToDestroy[i]);
}
// Add explosion score
var explosionScore = gemsToDestroy.length * 50 * multiplier;
score += explosionScore;
updateScore();
// Play explosion sound
LK.getSound('explosion').play();
// Wait for all destruction then cascade
LK.setTimeout(function () {
cascadeGems();
}, 500);
};
self.down = function (x, y, obj) {
if (!self.isFalling && !isProcessing) {
if (self.isBomb) {
isProcessing = true;
self.explodeBomb();
} else {
selectGem(self);
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var GRID_SIZE = 8;
var CELL_SIZE = 200;
var GEM_TYPES = 6;
var BOMB_TYPE = 6;
var grid = [];
var selectedGem = null;
var score = 0;
var multiplier = 1;
var isProcessing = false;
var cascadeCount = 0;
// Initialize score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var multiplierTxt = new Text2('Multiplier: x1', {
size: 60,
fill: 0xFFFF00
});
multiplierTxt.anchor.set(0.5, 0);
multiplierTxt.y = 100;
LK.gui.top.addChild(multiplierTxt);
// Initialize grid
function initializeGrid() {
var startX = (2048 - GRID_SIZE * CELL_SIZE) / 2;
var startY = 400;
// Create background cells
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
var cell = LK.getAsset('gridCell', {
anchorX: 0,
anchorY: 0,
alpha: 0.3
});
cell.x = startX + x * CELL_SIZE;
cell.y = startY + y * CELL_SIZE;
game.addChild(cell);
}
}
// 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;
}
}
// Fill grid with gems
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
createGem(x, y);
}
}
// Remove initial matches
removeInitialMatches();
}
function createGem(x, y) {
var gem = new Gem();
var gemType = Math.floor(Math.random() * GEM_TYPES);
gem.init(gemType, x, y);
grid[x][y] = gem;
game.addChild(gem);
return gem;
}
function removeInitialMatches() {
var hasMatches = true;
var attempts = 0;
while (hasMatches && attempts < 50) {
hasMatches = false;
attempts++;
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y] && hasMatchAt(x, y)) {
// Regenerate this gem
var oldGem = grid[x][y];
if (oldGem.parent) {
oldGem.parent.removeChild(oldGem);
}
createGem(x, y);
hasMatches = true;
}
}
}
}
}
function selectGem(gem) {
if (selectedGem === gem) {
// Deselect
selectedGem.setSelected(false);
selectedGem = null;
return;
}
if (selectedGem === null) {
// First selection
selectedGem = gem;
gem.setSelected(true);
} else {
// Second selection - check if adjacent
if (areAdjacent(selectedGem, gem)) {
swapGems(selectedGem, gem);
}
selectedGem.setSelected(false);
selectedGem = null;
}
}
function areAdjacent(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 (isProcessing) return;
isProcessing = true;
// Store positions
var tempX = gem1.gridX;
var tempY = gem1.gridY;
// Update grid positions
gem1.gridX = gem2.gridX;
gem1.gridY = gem2.gridY;
gem2.gridX = tempX;
gem2.gridY = tempY;
// Update grid array
grid[gem1.gridX][gem1.gridY] = gem1;
grid[gem2.gridX][gem2.gridY] = gem2;
// Animate swap
var gem1NewX = gem1.x;
var gem1NewY = gem1.y;
gem1.updatePosition();
var gem2NewX = gem2.x;
var gem2NewY = gem2.y;
gem2.updatePosition();
gem1.x = gem2NewX;
gem1.y = gem2NewY;
gem2.x = gem1NewX;
gem2.y = gem1NewY;
tween(gem1, {
x: gem1NewX,
y: gem1NewY
}, {
duration: 300
});
tween(gem2, {
x: gem2NewX,
y: gem2NewY
}, {
duration: 300,
onFinish: function onFinish() {
checkForMatches();
}
});
}
function hasMatchAt(x, y) {
if (!grid[x] || !grid[x][y]) return false;
var gemType = grid[x][y].gemType;
// Check horizontal
var hCount = 1;
// Check left
for (var i = x - 1; i >= 0 && grid[i][y] && grid[i][y].gemType === gemType; i--) {
hCount++;
}
// Check right
for (var i = x + 1; i < GRID_SIZE && grid[i][y] && grid[i][y].gemType === gemType; i++) {
hCount++;
}
if (hCount >= 3) return true;
// Check vertical
var vCount = 1;
// Check up
for (var i = y - 1; i >= 0 && grid[x][i] && grid[x][i].gemType === gemType; i--) {
vCount++;
}
// Check down
for (var i = y + 1; i < GRID_SIZE && grid[x][i] && grid[x][i].gemType === gemType; i++) {
vCount++;
}
return vCount >= 3;
}
function checkForMatches() {
var matches = [];
// Find all matches
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y] && hasMatchAt(x, y)) {
matches.push({
x: x,
y: y
});
}
}
}
if (matches.length > 0) {
cascadeCount++;
LK.getSound('match').play();
// Calculate score
var points = matches.length * 10 * multiplier * cascadeCount;
score += points;
updateScore();
// Create bomb if match is 4 or more gems
var shouldCreateBomb = matches.length >= 4;
var bombPosition = null;
if (shouldCreateBomb && matches.length > 0) {
bombPosition = matches[Math.floor(Math.random() * matches.length)];
}
// Mark matched gems for destruction
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
if (grid[match.x][match.y]) {
grid[match.x][match.y].destroy();
grid[match.x][match.y] = null;
}
}
// Create bomb after destruction
if (shouldCreateBomb && bombPosition) {
LK.setTimeout(function () {
if (grid[bombPosition.x][bombPosition.y] === null) {
var bomb = new Gem();
bomb.init(BOMB_TYPE, bombPosition.x, bombPosition.y);
grid[bombPosition.x][bombPosition.y] = bomb;
game.addChild(bomb);
// Animate bomb creation
bomb.graphics.scaleX = 0;
bomb.graphics.scaleY = 0;
tween(bomb.graphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.bounceOut
});
}
}, 200);
}
// Wait for destruction animation then cascade
LK.setTimeout(function () {
cascadeGems();
}, 400);
} else {
cascadeCount = 0;
isProcessing = false;
}
}
function cascadeGems() {
var needsCascade = false;
var fallPromises = 0;
// Process each column from left to right
for (var x = 0; x < GRID_SIZE; x++) {
// Compact the column - move all existing gems down to fill gaps
var compactedGems = [];
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y] !== null && !grid[x][y].isMatched) {
compactedGems.push(grid[x][y]);
grid[x][y] = null;
}
}
// Place compacted gems at the bottom of the column with proper spacing
var startY = GRID_SIZE - compactedGems.length;
for (var i = 0; i < compactedGems.length; i++) {
var gem = compactedGems[i];
var newY = startY + i;
var oldY = gem.gridY;
if (oldY !== newY) {
needsCascade = true;
grid[x][newY] = gem;
fallPromises++;
// Ensure gems don't overlap during falling animation
gem.isFalling = true;
(function (currentGem, delay) {
LK.setTimeout(function () {
currentGem.fallTo(newY, function () {
fallPromises--;
if (fallPromises === 0) {
fillEmptySpaces();
}
});
}, delay * 50); // Stagger fall animations to prevent overlaps
})(gem, i);
} else {
// Gem doesn't need to move
grid[x][newY] = gem;
gem.isFalling = false; // Ensure falling state is cleared
}
}
}
if (!needsCascade) {
fillEmptySpaces();
} else {
LK.getSound('cascade').play();
}
}
function fillEmptySpaces() {
var newGemsCreated = 0;
var columnNewGems = []; // Track new gems per column to avoid overlaps
for (var x = 0; x < GRID_SIZE; x++) {
columnNewGems[x] = 0;
}
for (var x = 0; x < GRID_SIZE; x++) {
for (var y = 0; y < GRID_SIZE; y++) {
if (grid[x][y] === null) {
createGem(x, y);
newGemsCreated++;
columnNewGems[x]++;
// Start gem above the screen with proper spacing to avoid overlaps
var startY = 400 - columnNewGems[x] * CELL_SIZE;
grid[x][y].y = startY;
grid[x][y].isFalling = true; // Mark as falling to prevent interaction
// Capture x,y values in closure to fix callback reference issue
(function (currentX, currentY, currentGem) {
tween(currentGem, {
y: 400 + currentY * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 500 + columnNewGems[currentX] * 50,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Mark gem as no longer falling when animation completes
if (grid[currentX] && grid[currentX][currentY]) {
grid[currentX][currentY].isFalling = false;
}
}
});
})(x, y, grid[x][y]);
}
}
}
// Check for new matches after a delay
LK.setTimeout(function () {
checkForMatches();
}, 600);
}
function updateScore() {
scoreTxt.setText('Score: ' + score);
// Update multiplier based on score
var newMultiplier = 1;
if (score >= 2500) newMultiplier = 5;else if (score >= 1000) newMultiplier = 4;else if (score >= 500) newMultiplier = 3;else if (score >= 100) newMultiplier = 2;
if (newMultiplier !== multiplier) {
multiplier = newMultiplier;
multiplierTxt.setText('Multiplier: x' + multiplier);
LK.effects.flashScreen(0x00ff00, 500);
}
// Win condition
if (score >= 5000) {
LK.showYouWin();
}
}
// Initialize the game
initializeGrid();
updateScore();
game.update = function () {
// Game loop - handle any continuous updates here
}; ===================================================================
--- original.js
+++ change.js
@@ -467,20 +467,23 @@
// Start gem above the screen with proper spacing to avoid overlaps
var startY = 400 - columnNewGems[x] * CELL_SIZE;
grid[x][y].y = startY;
grid[x][y].isFalling = true; // Mark as falling to prevent interaction
- tween(grid[x][y], {
- y: 400 + y * CELL_SIZE + CELL_SIZE / 2
- }, {
- duration: 500 + columnNewGems[x] * 50,
- easing: tween.bounceOut,
- onFinish: function onFinish() {
- // Mark gem as no longer falling when animation completes
- if (grid[x][y]) {
- grid[x][y].isFalling = false;
+ // Capture x,y values in closure to fix callback reference issue
+ (function (currentX, currentY, currentGem) {
+ tween(currentGem, {
+ y: 400 + currentY * CELL_SIZE + CELL_SIZE / 2
+ }, {
+ duration: 500 + columnNewGems[currentX] * 50,
+ easing: tween.bounceOut,
+ onFinish: function onFinish() {
+ // Mark gem as no longer falling when animation completes
+ if (grid[currentX] && grid[currentX][currentY]) {
+ grid[currentX][currentY].isFalling = false;
+ }
}
- }
- });
+ });
+ })(x, y, grid[x][y]);
}
}
}
// Check for new matches after a delay
red smiley ball. In-Game asset. 2d. High contrast. No shadows
Blue smiley ball. In-Game asset. 2d. High contrast. No shadows
Green smiley face. In-Game asset. 2d. High contrast. No shadows
Orange smiley ball. In-Game asset. 2d. High contrast. No shadows
Purple smiley ball. In-Game asset. 2d. High contrast. No shadows
Yellow smiley ball. In-Game asset. 2d. High contrast. No shadows
Bomba. In-Game asset. 2d. High contrast. No shadows
Star. In-Game asset. 2d. High contrast. No shadows
Spaceship. In-Game asset. 2d. High contrast. No shadows
A UFO with aliens inside. In-Game asset. 2d. High contrast. No shadows
Red smiley face. In-Game asset. 2d. High contrast. No shadows
Green smiley ball. In-Game asset. 2d. High contrast. No shadows
Male Cyber Character. In-Game asset. 2d. High contrast. No shadows
Vertical rocket. In-Game asset. 2d. High contrast. No shadows