Code edit (9 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
Entegre bir AI (örneğin Cursor, GitHub Copilot veya IDE içi asistanlar) kodu zaten "görebildiği" ve bağlama hakim olduğu için, prompt'u kopyala-yapıştır mantığından çıkarıp doğrudan yerinde düzenleme (refactoring) talimatlarına dönüştürmemiz gerekir. Bu durumda prompt, kodu tanıtmak yerine nelerin değişmesi gerektiğine odaklanmalıdır. İşte entegre AI sistemleri için optimize edilmiş prompt: 📋 Entegre AI İçin Prompt Context: You are an expert Game Developer working on the currently open JavaScript file which uses the LK (Lumi/Loom) framework. Objective: Refactor the existing code to implement "Juiciness" (Game Feel), Audio, and Visual improvements without breaking the core logic. Tasks: Visual Overhaul (Square & Unique Designs): Modify the Candy class. Instead of simple colored boxes, create unique "Square" designs. Inside the Candy constructor, generate a unique geometric shape (e.g., a smaller inner square, a cross, or a circle) inside the main container based on the candyType. This ensures the squares are distinguishable by shape, not just color. Use LK.init.shape or standard drawing methods to achieve this procedurally. Animation Polish (Easing): Locate the moveTo and refillBoard functions. Update the tween configurations. Change the easing from linear (default) to something more dynamic: Use Back.Out (or a similar bounce effect) for candies falling/refilling to give them weight. Use Cubic.InOut for the swapCandies animation to make it feel responsive. Slightly adjust the animation duration (e.g., 200ms-300ms) for a snappier feel. Audio Integration: Introduce a sound management logic. Trigger LK.getSound('match').play() (or appropriate method) inside checkAndDestroyMatches when a match occurs. Trigger LK.getSound('swap').play() inside swapCandies. Add a specific sound for "4-match" combos if possible. Action: Directly apply these changes to the code. Ensure all new logic is integrated into the existing Candy class and main game loop functions correctly. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
Code edit (4 edits merged)
Please save this source code
User prompt
hamle kalmadıktan sonra oyunun bitmesi için hamle yapamaya çalışmak gerekiyor şuan. bunun yerine son hamle yapıldıktan sonra eğer düşecek şeker varsa düşmeler gerçekleşir ve oyun sona erer
User prompt
her yer değiştirme işleminden sonra tüm şekerlerin düşmesi beklensin ve muhtemel eşleşmeler kontrol edilsin böylece şekerler havada kalmışken oyun bitmez
User prompt
her yer değiştirme işleminden sonra muhtemel eşleşmeler kontrol edilsin böylece şekerler havada kalmışken oyun bitmez
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'i')' in or related to this line: 'var i = candy.i;' Line Number: 241
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Candy = Container.expand(function (i, j, candyType) {
var self = Container.call(this);
var candyTypes = ["candy1", "candy2", "candy3", "candy4", "candy5", "candy6"];
if (!candyType) {
do {
candyType = candyTypes[Math.floor(Math.random() * candyTypes.length)];
} while (isPotentialMatch(i, j, candyType));
}
self.candyType = candyType;
var candyGraphics = self.attachAsset(candyType, {
anchorX: 0.5,
anchorY: 0.5
});
self.i = i;
self.j = j;
self.isMoving = false;
self.destroyCandy = function () {
self.destroy();
};
self.transformToWhite = function () {
self.removeChild(candyGraphics);
self.candyType = self.candyType + "_white";
candyGraphics = self.attachAsset(self.candyType, {
anchorX: 0.5,
anchorY: 0.5
});
};
self.moveTo = function (newI, newJ, _onComplete) {
self.isMoving = true;
self.i = newI;
self.j = newJ;
tween(self, {
x: newI * candySize + candySize / 2 + marginX,
y: newJ * candySize + candySize / 2 + marginY
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
self.isMoving = false;
if (_onComplete) {
_onComplete();
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
var score = 0;
var scoreMultiplier = 1;
var scoreTxt = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0); // Anchor to the top-right corner
LK.gui.topRight.addChild(scoreTxt);
function updateScore(points) {
score += points * scoreMultiplier;
scoreTxt.setText('Score: ' + score);
}
var board = [];
var boardSize = 9;
var candySize = Math.min(2048, 2732) / (boardSize + 0.5);
var selectedCandy = null;
var marginY = (2732 - boardSize * candySize) / 2;
var marginX = (2048 - boardSize * candySize) / 2;
var isProcessing = false;
function isPotentialMatch(i, j, candyType) {
// Oyun başlangıcında 3'lü eşleşmeleri engelliyoruz
if (i >= 2 && board[i - 1][j] && board[i - 2][j] && board[i - 1][j].candyType === candyType && board[i - 2][j].candyType === candyType) {
return true;
}
if (j >= 2 && board[i][j - 1] && board[i][j - 2] && board[i][j - 1].candyType === candyType && board[i][j - 2].candyType === candyType) {
return true;
}
return false;
}
function initializeBoard() {
for (var i = 0; i < boardSize; i++) {
board[i] = [];
for (var j = 0; j < boardSize; j++) {
var candy = new Candy(i, j);
candy.x = i * candySize + candySize / 2 + marginX;
candy.y = j * candySize + candySize / 2 + marginY;
board[i][j] = candy;
game.addChild(candy);
}
}
}
function swapCandies(candy1, candy2) {
if (!candy1 || !candy2 || isProcessing) {
return;
}
var dx = Math.abs(candy1.i - candy2.i);
var dy = Math.abs(candy1.j - candy2.j);
if (dx === 1 && dy === 1 || dx === 0 && dy === 0) {
return; // Çapraz veya aynı yere tıklamayı engelle
}
isProcessing = true;
LK.getSound('swap').play();
var tempI1 = candy1.i;
var tempJ1 = candy1.j;
var tempI2 = candy2.i;
var tempJ2 = candy2.j;
// Tahtada yerlerini değiştir
board[tempI1][tempJ1] = candy2;
board[tempI2][tempJ2] = candy1;
// Görsel olarak yerlerini değiştir
tween(candy1, {
x: tempI2 * candySize + candySize / 2 + marginX,
y: tempJ2 * candySize + candySize / 2 + marginY
}, {
duration: 250,
easing: tween.cubicInOut
});
tween(candy2, {
x: tempI1 * candySize + candySize / 2 + marginX,
y: tempJ1 * candySize + candySize / 2 + marginY
}, {
duration: 250,
easing: tween.cubicInOut
});
LK.setTimeout(function () {
// Yer değiştiren her iki şekeri de kontrol et
var matchInfo1 = checkAndDestroyMatches(candy1);
var matchInfo2 = checkAndDestroyMatches(candy2);
// Eşleşme yoksa geri döndür
if (!matchInfo1.hasMatch && !matchInfo2.hasMatch) {
board[tempI1][tempJ1] = candy1;
board[tempI2][tempJ2] = candy2;
candy1.moveTo(tempI1, tempJ1);
candy2.moveTo(tempI2, tempJ2);
candy1.i = tempI1;
candy1.j = tempJ1;
candy2.i = tempI2;
candy2.j = tempJ2;
LK.setTimeout(function () {
isProcessing = false;
}, 500);
} else {
if (matchInfo1.hasMatch) {
// candy1 eşleşme sağladı
if (matchInfo1.isFourMatch) {
candy1.transformToWhite();
} else {
board[candy1.i][candy1.j] = null;
candy1.destroyCandy();
}
}
if (matchInfo2.hasMatch) {
// candy2 eşleşme sağladı
if (matchInfo2.isFourMatch) {
candy2.transformToWhite();
} else {
board[candy2.i][candy2.j] = null;
candy2.destroyCandy();
}
}
LK.setTimeout(function () {
processMatches();
}, 300);
}
}, 600);
}
function checkAndDestroyMatches(candy) {
var hasMatch = false;
var isFourMatch = false;
var candiesToDestroy = [];
var i = candy.i;
var j = candy.j;
var matchedCandies = [candy];
// Yatay kontrol
var left = i - 1;
while (left >= 0 && board[left][j] && board[left][j].candyType === candy.candyType) {
matchedCandies.push(board[left][j]);
left--;
}
var right = i + 1;
while (right < boardSize && board[right][j] && board[right][j].candyType === candy.candyType) {
matchedCandies.push(board[right][j]);
right++;
}
if (matchedCandies.length >= 3) {
hasMatch = true;
if (matchedCandies.length === 4) {
isFourMatch = true;
}
candiesToDestroy = candiesToDestroy.concat(matchedCandies.filter(function (c) {
return c !== candy;
}));
}
// Dikey kontrol
matchedCandies = [candy];
var up = j - 1;
while (up >= 0 && board[i][up] && board[i][up].candyType === candy.candyType) {
matchedCandies.push(board[i][up]);
up--;
}
var down = j + 1;
while (down < boardSize && board[i][down] && board[i][down].candyType === candy.candyType) {
matchedCandies.push(board[i][down]);
down++;
}
if (matchedCandies.length >= 3) {
hasMatch = true;
if (matchedCandies.length === 4) {
isFourMatch = true;
}
candiesToDestroy = candiesToDestroy.concat(matchedCandies.filter(function (c) {
return c !== candy;
}));
}
// Eşleşen şekerleri yok et
candiesToDestroy.forEach(function (c) {
board[c.i][c.j] = null;
c.destroyCandy();
});
if (hasMatch) {
LK.getSound('match').play();
if (isFourMatch) {
updateScore(100); // 4-match score
LK.getSound('combo').play();
} else {
updateScore(50); // 3-match score
}
scoreMultiplier++;
} else {
scoreMultiplier = 1; // Reset multiplier if no match
}
return {
hasMatch: hasMatch,
isFourMatch: isFourMatch
};
}
function processMatches() {
refillBoard();
LK.setTimeout(function () {
if (checkAllMatches()) {
LK.setTimeout(function () {
processMatches();
}, 300);
} else {
isProcessing = false;
scoreMultiplier = 1; // Reset multiplier after processing
}
}, 600);
}
function checkAllMatches() {
var foundMatch = false;
for (var i = 0; i < boardSize; i++) {
for (var j = 0; j < boardSize; j++) {
if (board[i][j]) {
var candy = board[i][j];
var candiesToDestroy = [];
var matchedCandies = [candy];
// Yatay kontrol
var left = i - 1;
while (left >= 0 && board[left][j] && board[left][j].candyType === candy.candyType) {
matchedCandies.push(board[left][j]);
left--;
}
var right = i + 1;
while (right < boardSize && board[right][j] && board[right][j].candyType === candy.candyType) {
matchedCandies.push(board[right][j]);
right++;
}
if (matchedCandies.length >= 3) {
foundMatch = true;
candiesToDestroy = candiesToDestroy.concat(matchedCandies);
if (candiesToDestroy.length === 4) {
updateScore(100); // 4-match score
} else if (candiesToDestroy.length >= 3) {
updateScore(50); // 3-match score
}
} else {
// Dikey kontrol
matchedCandies = [candy];
var up = j - 1;
while (up >= 0 && board[i][up] && board[i][up].candyType === candy.candyType) {
matchedCandies.push(board[i][up]);
up--;
}
var down = j + 1;
while (down < boardSize && board[i][down] && board[i][down].candyType === candy.candyType) {
matchedCandies.push(board[i][down]);
down++;
}
if (matchedCandies.length >= 3) {
foundMatch = true;
candiesToDestroy = candiesToDestroy.concat(matchedCandies);
}
}
// Eşleşen şekerleri yok et
if (candiesToDestroy.length >= 3) {
if (candiesToDestroy.length === 4) {
updateScore(100); // 4-match score
} else if (candiesToDestroy.length >= 3) {
updateScore(50); // 3-match score
}
candiesToDestroy.forEach(function (c) {
if (board[c.i][c.j]) {
board[c.i][c.j] = null;
c.destroyCandy();
}
});
}
}
}
}
return foundMatch;
}
function refillBoard() {
for (var i = 0; i < boardSize; i++) {
var emptySpaces = 0;
for (var j = boardSize - 1; j >= 0; j--) {
if (!board[i][j]) {
emptySpaces++;
} else if (emptySpaces > 0) {
board[i][j + emptySpaces] = board[i][j];
board[i][j + emptySpaces].moveTo(i, j + emptySpaces);
board[i][j] = null;
}
}
for (var j = emptySpaces - 1; j >= 0; j--) {
var newCandy = new Candy(i, j);
newCandy.x = i * candySize + candySize / 2 + marginX;
newCandy.y = -candySize * (emptySpaces - j) + candySize / 2 + marginY;
board[i][j] = newCandy;
game.addChild(newCandy);
newCandy.moveTo(i, j);
}
}
}
game.down = function (x, y) {
if (isProcessing) {
return;
}
var i = Math.floor((x - marginX) / candySize);
var j = Math.floor((y - marginY) / candySize);
if (i >= 0 && i < boardSize && j >= 0 && j < boardSize) {
if (selectedCandy) {
var dx = Math.abs(selectedCandy.i - i);
var dy = Math.abs(selectedCandy.j - j);
if (dx === 1 && dy === 0 || dx === 0 && dy === 1) {
swapCandies(selectedCandy, board[i][j]);
}
selectedCandy = null;
} else {
selectedCandy = board[i][j];
}
}
};
initializeBoard();
var resetButton = LK.getAsset('resetButton', {
anchorX: 1,
anchorY: 1,
x: 2048 - 50,
// Positioning the button at the bottom-right corner
y: 2732 - 50
});
LK.gui.bottomRight.addChild(resetButton);
resetButton.down = function () {
LK.showGameOver(); // This will reset the game state
};
game.update = function () {};
; ===================================================================
--- original.js
+++ change.js
@@ -41,9 +41,10 @@
x: newI * candySize + candySize / 2 + marginX,
y: newJ * candySize + candySize / 2 + marginY
}, {
duration: 300,
- onComplete: function onComplete() {
+ easing: tween.bounceOut,
+ onFinish: function onFinish() {
self.isMoving = false;
if (_onComplete) {
_onComplete();
}
@@ -62,46 +63,8 @@
/****
* Game Code
****/
-function destroyRowOrColumn(candy) {
- var i = candy.i;
- var j = candy.j;
- var isRow = false;
- var isColumn = false;
- // Check if the special candy is part of a horizontal match
- for (var x = 0; x < boardSize; x++) {
- if (board[x][j] && board[x][j].candyType === candy.candyType.replace("_white", "")) {
- isRow = true;
- break;
- }
- }
- // Check if the special candy is part of a vertical match
- for (var y = 0; y < boardSize; y++) {
- if (board[i][y] && board[i][y].candyType === candy.candyType.replace("_white", "")) {
- isColumn = true;
- break;
- }
- }
- if (isRow) {
- // Destroy entire row
- for (var x = 0; x < boardSize; x++) {
- if (board[x][j]) {
- board[x][j].destroyCandy();
- board[x][j] = null;
- }
- }
- }
- if (isColumn) {
- // Destroy entire column
- for (var y = 0; y < boardSize; y++) {
- if (board[i][y]) {
- board[i][y].destroyCandy();
- board[i][y] = null;
- }
- }
- }
-}
var score = 0;
var scoreMultiplier = 1;
var scoreTxt = new Text2('Score: 0', {
size: 100,
@@ -151,18 +114,31 @@
if (dx === 1 && dy === 1 || dx === 0 && dy === 0) {
return; // Çapraz veya aynı yere tıklamayı engelle
}
isProcessing = true;
+ LK.getSound('swap').play();
var tempI1 = candy1.i;
var tempJ1 = candy1.j;
var tempI2 = candy2.i;
var tempJ2 = candy2.j;
// Tahtada yerlerini değiştir
board[tempI1][tempJ1] = candy2;
board[tempI2][tempJ2] = candy1;
// Görsel olarak yerlerini değiştir
- candy1.moveTo(tempI2, tempJ2);
- candy2.moveTo(tempI1, tempJ1);
+ tween(candy1, {
+ x: tempI2 * candySize + candySize / 2 + marginX,
+ y: tempJ2 * candySize + candySize / 2 + marginY
+ }, {
+ duration: 250,
+ easing: tween.cubicInOut
+ });
+ tween(candy2, {
+ x: tempI1 * candySize + candySize / 2 + marginX,
+ y: tempJ1 * candySize + candySize / 2 + marginY
+ }, {
+ duration: 250,
+ easing: tween.cubicInOut
+ });
LK.setTimeout(function () {
// Yer değiştiren her iki şekeri de kontrol et
var matchInfo1 = checkAndDestroyMatches(candy1);
var matchInfo2 = checkAndDestroyMatches(candy2);
@@ -200,22 +176,8 @@
}
LK.setTimeout(function () {
processMatches();
}, 300);
- refillBoard(); // Ensure all candies fall into place
- LK.setTimeout(function () {
- // Wait for candies to settle
- if (checkAllMatches()) {
- // Check for any new matches
- processMatches(); // Process any new matches found
- } else {
- isProcessing = false; // Allow new actions if no matches
- if (!checkPossibleMoves()) {
- // Check for possible moves
- LK.showGameOver(); // End the game if no possible moves are found
- }
- }
- }, 600);
}
}, 600);
}
function checkAndDestroyMatches(candy) {
@@ -224,19 +186,16 @@
var candiesToDestroy = [];
var i = candy.i;
var j = candy.j;
var matchedCandies = [candy];
- // Özel şeker olup olmadığını kontrol et (örneğin candy1_white)
- var originalType = candy.candyType.replace("_white", "");
- var isSpecialCandy = candy.candyType.includes("_white");
// Yatay kontrol
var left = i - 1;
- while (left >= 0 && board[left][j] && board[left][j].candyType.replace("_white", "") === originalType) {
+ while (left >= 0 && board[left][j] && board[left][j].candyType === candy.candyType) {
matchedCandies.push(board[left][j]);
left--;
}
var right = i + 1;
- while (right < boardSize && board[right][j] && board[right][j].candyType.replace("_white", "") === originalType) {
+ while (right < boardSize && board[right][j] && board[right][j].candyType === candy.candyType) {
matchedCandies.push(board[right][j]);
right++;
}
if (matchedCandies.length >= 3) {
@@ -250,14 +209,14 @@
}
// Dikey kontrol
matchedCandies = [candy];
var up = j - 1;
- while (up >= 0 && board[i][up] && board[i][up].candyType.replace("_white", "") === originalType) {
+ while (up >= 0 && board[i][up] && board[i][up].candyType === candy.candyType) {
matchedCandies.push(board[i][up]);
up--;
}
var down = j + 1;
- while (down < boardSize && board[i][down] && board[i][down].candyType.replace("_white", "") === originalType) {
+ while (down < boardSize && board[i][down] && board[i][down].candyType === candy.candyType) {
matchedCandies.push(board[i][down]);
down++;
}
if (matchedCandies.length >= 3) {
@@ -268,33 +227,25 @@
candiesToDestroy = candiesToDestroy.concat(matchedCandies.filter(function (c) {
return c !== candy;
}));
}
- // Eğer özel bir şeker (white) kendi rengindeki şekerlerle eşleşirse tüm satır veya sütun silinsin
- if (isSpecialCandy && hasMatch) {
- if (left >= 0 || right < boardSize) {
- // Yatay eşleşme varsa satırı temizle
- for (var x = 0; x < boardSize; x++) {
- if (board[x][j]) {
- board[x][j].destroyCandy();
- board[x][j] = null;
- }
- }
- } else if (up >= 0 || down < boardSize) {
- // Dikey eşleşme varsa sütunu temizle
- for (var y = 0; y < boardSize; y++) {
- if (board[i][y]) {
- board[i][y].destroyCandy();
- board[i][y] = null;
- }
- }
- }
- }
- // Normal eşleşen şekerleri yok et
+ // Eşleşen şekerleri yok et
candiesToDestroy.forEach(function (c) {
board[c.i][c.j] = null;
c.destroyCandy();
});
+ if (hasMatch) {
+ LK.getSound('match').play();
+ if (isFourMatch) {
+ updateScore(100); // 4-match score
+ LK.getSound('combo').play();
+ } else {
+ updateScore(50); // 3-match score
+ }
+ scoreMultiplier++;
+ } else {
+ scoreMultiplier = 1; // Reset multiplier if no match
+ }
return {
hasMatch: hasMatch,
isFourMatch: isFourMatch
};
@@ -308,14 +259,8 @@
}, 300);
} else {
isProcessing = false;
scoreMultiplier = 1; // Reset multiplier after processing
- // 💥 Hamle olup olmadığını hemen kontrol et
- LK.setTimeout(function () {
- if (!checkPossibleMoves()) {
- LK.showGameOver(); // Hamle kalmadıysa oyunu bitir
- }
- }, 300);
}
}, 600);
}
function checkAllMatches() {
@@ -394,12 +339,14 @@
board[i][j] = null;
}
}
for (var j = emptySpaces - 1; j >= 0; j--) {
- if (j < boardSize - emptySpaces) {
- // Only move existing candies down, do not spawn new ones
- board[i][j] = null;
- }
+ var newCandy = new Candy(i, j);
+ newCandy.x = i * candySize + candySize / 2 + marginX;
+ newCandy.y = -candySize * (emptySpaces - j) + candySize / 2 + marginY;
+ board[i][j] = newCandy;
+ game.addChild(newCandy);
+ newCandy.moveTo(i, j);
}
}
}
game.down = function (x, y) {
@@ -432,29 +379,6 @@
LK.gui.bottomRight.addChild(resetButton);
resetButton.down = function () {
LK.showGameOver(); // This will reset the game state
};
-game.update = function () {
- if (!checkPossibleMoves()) {
- LK.showGameOver(); // End the game if no possible moves are found
- }
-};
-;
-function checkPossibleMoves() {
- for (var i = 0; i < boardSize; i++) {
- for (var j = 0; j < boardSize - 1; j++) {
- if (board[i][j] && board[i][j + 1] && board[i][j].candyType === board[i][j + 1].candyType) {
- // Check potential matches around the pair
- if (i > 0 && j > 0 && board[i - 1][j - 1] && board[i - 1][j - 1].candyType === board[i][j].candyType || j > 1 && board[i][j - 2] && board[i][j - 2].candyType === board[i][j].candyType || i < boardSize - 1 && j > 0 && board[i + 1][j - 1] && board[i + 1][j - 1].candyType === board[i][j].candyType || i > 0 && j < boardSize - 2 && board[i - 1][j + 2] && board[i - 1][j + 2].candyType === board[i][j].candyType || j < boardSize - 3 && board[i][j + 2] && board[i][j + 2].candyType === board[i][j].candyType || i < boardSize - 1 && j < boardSize - 2 && board[i + 1][j + 2] && board[i + 1][j + 2].candyType === board[i][j].candyType) {
- return true; // Found a possible move
- }
- }
- if (i < boardSize - 1 && board[i][j] && board[i + 1][j] && board[i][j].candyType === board[i + 1][j].candyType) {
- // Check potential matches around the pair
- if (i > 1 && board[i - 2][j] && board[i - 2][j].candyType === board[i][j].candyType || i > 0 && j > 0 && board[i - 1][j - 1] && board[i - 1][j - 1].candyType === board[i][j].candyType || i > 0 && j < boardSize - 1 && board[i - 1][j + 1] && board[i - 1][j + 1].candyType === board[i][j].candyType || i < boardSize - 2 && j > 0 && board[i + 2][j - 1] && board[i + 2][j - 1].candyType === board[i][j].candyType || i < boardSize - 2 && j < boardSize - 1 && board[i + 2][j + 1] && board[i + 2][j + 1].candyType === board[i][j].candyType || i < boardSize - 3 && board[i + 3][j] && board[i + 3][j].candyType === board[i][j].candyType) {
- return true; // Found a possible move
- }
- }
- }
- }
- return false; // No possible moves found
-}
\ No newline at end of file
+game.update = function () {};
+;
\ No newline at end of file