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) {
compactedGems.push(grid[x][y]);
grid[x][y] = null;
}
}
// Place compacted gems at the bottom of the column
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++;
gem.fallTo(newY, function () {
fallPromises--;
if (fallPromises === 0) {
fillEmptySpaces();
}
});
} else {
// Gem doesn't need to move
grid[x][newY] = gem;
}
}
}
if (!needsCascade) {
fillEmptySpaces();
} else {
LK.getSound('cascade').play();
}
}
function fillEmptySpaces() {
var newGemsCreated = 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++;
// Start gem above the screen and animate it falling
var startY = 400 - newGemsCreated * CELL_SIZE;
grid[x][y].y = startY;
tween(grid[x][y], {
y: 400 + y * CELL_SIZE + CELL_SIZE / 2
}, {
duration: 500 + newGemsCreated * 50,
easing: tween.bounceOut
});
}
}
}
// 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
@@ -408,46 +408,36 @@
var needsCascade = false;
var fallPromises = 0;
// Process each column from left to right
for (var x = 0; x < GRID_SIZE; x++) {
- var gemsToMove = [];
- var targetPositions = [];
- // Find all gems that need to fall in this column
- for (var y = GRID_SIZE - 1; y >= 0; y--) {
+ // 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) {
- // Find the lowest available position for this gem
- var targetY = y;
- while (targetY + 1 < GRID_SIZE && grid[x][targetY + 1] === null) {
- targetY++;
- }
- // If gem needs to move down
- if (targetY !== y) {
- gemsToMove.push({
- gem: grid[x][y],
- fromY: y,
- toY: targetY
- });
- needsCascade = true;
- }
+ compactedGems.push(grid[x][y]);
+ grid[x][y] = null;
}
}
- // Move gems to their new positions
- for (var i = 0; i < gemsToMove.length; i++) {
- var moveData = gemsToMove[i];
- var gem = moveData.gem;
- var fromY = moveData.fromY;
- var toY = moveData.toY;
- // Update grid array
- grid[x][fromY] = null;
- grid[x][toY] = gem;
- // Animate the fall
- fallPromises++;
- gem.fallTo(toY, function () {
- fallPromises--;
- if (fallPromises === 0) {
- fillEmptySpaces();
- }
- });
+ // Place compacted gems at the bottom of the column
+ 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++;
+ gem.fallTo(newY, function () {
+ fallPromises--;
+ if (fallPromises === 0) {
+ fillEmptySpaces();
+ }
+ });
+ } else {
+ // Gem doesn't need to move
+ grid[x][newY] = gem;
+ }
}
}
if (!needsCascade) {
fillEmptySpaces();
@@ -455,18 +445,21 @@
LK.getSound('cascade').play();
}
}
function fillEmptySpaces() {
+ var newGemsCreated = 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);
- // Animate gem falling from top
- grid[x][y].y = -200;
+ newGemsCreated++;
+ // Start gem above the screen and animate it falling
+ var startY = 400 - newGemsCreated * CELL_SIZE;
+ grid[x][y].y = startY;
tween(grid[x][y], {
y: 400 + y * CELL_SIZE + CELL_SIZE / 2
}, {
- duration: 500,
+ duration: 500 + newGemsCreated * 50,
easing: tween.bounceOut
});
}
}
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