User prompt
There should be no point limit, the game should continue until the moves are finished.
User prompt
Increase move rights to 20
User prompt
If the candies that explode after using the move right explode, you will gain 1 move right.
User prompt
If newcomers automatically explode, give them +1 move
User prompt
If the candies falling from above explode, you gain 1 move.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'row')' in or related to this line: 'var pos1 = getBoardPos(c1.row, c1.col);' Line Number: 204
User prompt
When the move is over, the game is over.
User prompt
Wrong moves take away move points
User prompt
Four-pack candy blast gives 1.5 points, five-pack candy blast gives 2 points, six-pack candy blast gives 4 times the points.
User prompt
Please fix the bug: 'TypeError: Cannot set properties of null (setting 'isMatched')' in or related to this line: 'board[r][c].isMatched = false;' Line Number: 261
User prompt
When the moves are finished, a button should appear asking if you want to start again and if you click it, it will start again.
User prompt
Don't let the game end before the moves are finished
User prompt
Remove target score and write best score and current score instead
User prompt
The more candies explode, the more points you earn.
User prompt
When a wrong move is made, the wrong sound should be heard every time.
User prompt
When the candies explode, make the sg_crash sound every time
User prompt
Grow and finish sg assets
User prompt
add an asset between the sweets and the background
User prompt
Apply sg_bg asset as background behind sg assets
User prompt
set bg asset as background
User prompt
Doesn't go to part 2
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Candy class: represents a single candy on the board var Candy = Container.expand(function () { var self = Container.call(this); // Properties self.type = 0; // 0-6, for 7 types self.row = 0; self.col = 0; self.isMatched = false; // Attach asset for candy, anchor center self.candyAsset = null; // Set candy type and update asset self.setType = function (type) { self.type = type; // Remove previous asset if exists if (self.candyAsset) { self.removeChild(self.candyAsset); } // Assign each candy type to a unique asset for visual distinction var assetIds = ['Sg1', // type 0 'Sg2', // type 1 'Sg3', // type 2 'Sg4', // type 3 'Sg5', // type 4 'Sg6', // type 5 'Sg7' // type 6 ]; self.candyAsset = self.attachAsset(assetIds[type], { anchorX: 0.5, anchorY: 0.5 }); }; // Animate pop (match) self.pop = function (_onFinish) { tween(self, { scaleX: 1.3, scaleY: 1.3, alpha: 0 }, { duration: 250, easing: tween.easeIn, onFinish: function onFinish() { self.alpha = 1; self.scaleX = 1; self.scaleY = 1; if (_onFinish) _onFinish(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x222244 }); /**** * Game Code ****/ // --- Game Constants --- var boardCols = 7; var boardRows = 9; var candyTypes = 7; var candySize = 200; // px, will be scaled to fit var boardPadding = 0; // No padding between candies var moveLimit = 10; var targetScore = 1800; // --- Game State --- var board = []; // 2D array [row][col] of Candy var candies = []; // Flat array of all Candy objects var selectedCandy = null; var swappingCandy = null; var isSwapping = false; var isAnimating = false; var movesLeft = moveLimit; var score = 0; var level = storage.level || 1; // --- UI Elements --- var scoreTxt = new Text2('0', { size: 90, fill: "#fff" }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); var movesTxt = new Text2('Moves: ' + movesLeft, { size: 70, fill: "#fff" }); movesTxt.anchor.set(0.5, 0); LK.gui.top.addChild(movesTxt); movesTxt.y = 110; var targetTxt = new Text2('Target: ' + targetScore, { size: 60, fill: "#fff" }); targetTxt.anchor.set(0.5, 0); LK.gui.top.addChild(targetTxt); targetTxt.y = 190; // --- Board Positioning --- // Add Sg_bg asset as a background layer, scaled to cover the game area var sgBgAsset = LK.getAsset('Sg_bg', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(sgBgAsset); // Add Bg asset as background, scaled to cover the game area var bgAsset = LK.getAsset('Bg', { anchorX: 0, anchorY: 0, x: 0, y: 0, width: 2048, height: 2732 }); game.addChild(bgAsset); var boardWidth = boardCols * candySize; var boardHeight = boardRows * candySize; var boardOffsetX = Math.floor((2048 - boardWidth) / 2); var boardOffsetY = Math.floor((2732 - boardHeight) / 2) + 60; // --- Helper Functions --- // Get board position (x, y) for a given row, col function getBoardPos(row, col) { return { x: boardOffsetX + col * candySize + candySize / 2, y: boardOffsetY + row * candySize + candySize / 2 }; } // Get candy at (row, col) function getCandy(row, col) { if (row < 0 || row >= boardRows || col < 0 || col >= boardCols) return null; return board[row][col]; } // Swap two candies in board and update their row/col function swapCandies(c1, c2) { if (!c1 || !c2) { // Defensive: do nothing if either candy is null or undefined return; } var r1 = c1.row, c1c = c1.col, r2 = c2.row, c2c = c2.col; board[r1][c1c] = c2; board[r2][c2c] = c1; c1.row = r2; c1.col = c2c; c2.row = r1; c2.col = c1c; } // Animate swap between two candies function animateSwap(c1, c2, _onFinish2) { isAnimating = true; var pos1 = getBoardPos(c1.row, c1.col); var pos2 = getBoardPos(c2.row, c2.col); tween(c1, { x: pos2.x, y: pos2.y }, { duration: 180, easing: tween.cubicInOut }); tween(c2, { x: pos1.x, y: pos1.y }, { duration: 180, easing: tween.cubicInOut, onFinish: function onFinish() { isAnimating = false; if (_onFinish2) _onFinish2(); } }); } // Animate candy falling to new position function animateMoveTo(candy, newRow, newCol, onFinish) { var pos = getBoardPos(newRow, newCol); tween(candy, { x: pos.x, y: pos.y }, { duration: 180, easing: tween.cubicInOut, onFinish: onFinish }); } // Deselect all candies function deselectAll() { if (selectedCandy) { tween(selectedCandy, { scaleX: 1, scaleY: 1 }, { duration: 100 }); selectedCandy = null; } } // Check if two candies are adjacent function areAdjacent(c1, c2) { return Math.abs(c1.row - c2.row) + Math.abs(c1.col - c2.col) === 1; } // Find all matches on the board, mark candies as isMatched function findMatches() { var found = false; // Clear previous matches for (var r = 0; r < boardRows; r++) { for (var c = 0; c < boardCols; c++) { board[r][c].isMatched = false; } } // Horizontal matches for (var r = 0; r < boardRows; r++) { var matchLen = 1; for (var c = 1; c < boardCols; c++) { if (board[r][c].type === board[r][c - 1].type) { matchLen++; } else { if (matchLen >= 3) { for (var k = 0; k < matchLen; k++) { board[r][c - 1 - k].isMatched = true; } found = true; } matchLen = 1; } } if (matchLen >= 3) { for (var k = 0; k < matchLen; k++) { board[r][boardCols - 1 - k].isMatched = true; } found = true; } } // Vertical matches for (var c = 0; c < boardCols; c++) { var matchLen = 1; for (var r = 1; r < boardRows; r++) { if (board[r][c].type === board[r - 1][c].type) { matchLen++; } else { if (matchLen >= 3) { for (var k = 0; k < matchLen; k++) { board[r - 1 - k][c].isMatched = true; } found = true; } matchLen = 1; } } if (matchLen >= 3) { for (var k = 0; k < matchLen; k++) { board[boardRows - 1 - k][c].isMatched = true; } found = true; } } return found; } // Remove matched candies, return number removed function removeMatches(onFinish) { var removed = 0; var toPop = []; for (var r = 0; r < boardRows; r++) { for (var c = 0; c < boardCols; c++) { var candy = board[r][c]; if (candy.isMatched) { toPop.push(candy); removed++; } } } if (removed === 0) { if (onFinish) onFinish(); return; } var popped = 0; for (var i = 0; i < toPop.length; i++) { toPop[i].pop(function () { popped++; if (popped === toPop.length) { for (var j = 0; j < toPop.length; j++) { var c = toPop[j]; game.removeChild(c); candies.splice(candies.indexOf(c), 1); board[c.row][c.col] = null; } if (onFinish) onFinish(removed); } }); } } // Drop candies down to fill empty spaces, return true if any moved function dropCandies(onFinish) { var moved = false; var moves = []; for (var c = 0; c < boardCols; c++) { for (var r = boardRows - 1; r >= 0; r--) { if (board[r][c] === null) { // Find first non-null above for (var k = r - 1; k >= 0; k--) { if (board[k][c]) { var candy = board[k][c]; board[r][c] = candy; board[k][c] = null; var oldRow = candy.row; candy.row = r; moves.push({ candy: candy, from: oldRow, to: r, col: c }); break; } } } } } if (moves.length === 0) { if (onFinish) onFinish(false); return; } var finished = 0; for (var i = 0; i < moves.length; i++) { var move = moves[i]; animateMoveTo(move.candy, move.to, move.col, function () { finished++; if (finished === moves.length) { if (onFinish) onFinish(true); } }); } } // Fill empty spaces at the top with new candies function fillBoard(onFinish) { var filled = 0; var toFill = []; for (var c = 0; c < boardCols; c++) { for (var r = 0; r < boardRows; r++) { if (board[r][c] === null) { var candy = new Candy(); var type = Math.floor(Math.random() * candyTypes); candy.setType(type); candy.row = r; candy.col = c; var pos = getBoardPos(r, c); candy.x = pos.x; candy.y = pos.y - 400; // Drop from above game.addChild(candy); candies.push(candy); board[r][c] = candy; toFill.push(candy); } } } if (toFill.length === 0) { if (onFinish) onFinish(); return; } var finished = 0; for (var i = 0; i < toFill.length; i++) { var candy = toFill[i]; var pos = getBoardPos(candy.row, candy.col); animateMoveTo(candy, candy.row, candy.col, function () { finished++; if (finished === toFill.length) { if (onFinish) onFinish(); } }); } } // Check if the board has any possible moves (for future: shuffle if not) function hasPossibleMoves() { // For MVP, skip shuffle, always assume possible moves return true; } // Update UI function updateUI() { scoreTxt.setText(score); movesTxt.setText('Moves: ' + movesLeft); targetTxt.setText('Target: ' + targetScore); } // Handle end of turn: check for matches, drop, fill, repeat as needed function resolveBoard(afterResolve) { if (findMatches()) { removeMatches(function (removed) { score += removed * 100; updateUI(); dropCandies(function () { fillBoard(function () { resolveBoard(afterResolve); }); }); }); } else { if (afterResolve) afterResolve(); } } // Handle win/lose function checkEnd() { if (score >= targetScore) { if (level === 1) { // Show win for part 1, but do NOT advance to part 2 LK.showYouWin(); return true; } else { storage.level = level + 1; LK.showYouWin(); return true; } } if (movesLeft <= 0) { LK.showGameOver(); return true; } return false; } // --- Board Initialization --- function createBoard() { // Clear previous for (var i = 0; i < candies.length; i++) { game.removeChild(candies[i]); } candies = []; board = []; for (var r = 0; r < boardRows; r++) { board[r] = []; for (var c = 0; c < boardCols; c++) { var candy = new Candy(); var type = Math.floor(Math.random() * candyTypes); candy.setType(type); candy.row = r; candy.col = c; var pos = getBoardPos(r, c); candy.x = pos.x; candy.y = pos.y; game.addChild(candy); candies.push(candy); board[r][c] = candy; } } // Remove any initial matches while (findMatches()) { for (var r = 0; r < boardRows; r++) { for (var c = 0; c < boardCols; c++) { if (board[r][c].isMatched) { var newType; do { newType = Math.floor(Math.random() * candyTypes); } while (r > 0 && board[r - 1][c].type === newType || c > 0 && board[r][c - 1].type === newType); board[r][c].setType(newType); board[r][c].isMatched = false; } } } } } // --- Input Handling --- // Find candy at (x, y) in game coordinates function findCandyAt(x, y) { for (var i = 0; i < candies.length; i++) { var c = candies[i]; var dx = x - c.x; var dy = y - c.y; if (Math.abs(dx) < candySize / 2 && Math.abs(dy) < candySize / 2) { return c; } } return null; } // Handle tap or drag game.down = function (x, y, obj) { if (isAnimating) return; var c = findCandyAt(x, y); if (!c) { deselectAll(); return; } if (!selectedCandy) { selectedCandy = c; tween(selectedCandy, { scaleX: 1.15, scaleY: 1.15 }, { duration: 100 }); } else if (selectedCandy === c) { deselectAll(); } else if (areAdjacent(selectedCandy, c)) { // Swap attempt isSwapping = true; swappingCandy = c; // Animate swap animateSwap(selectedCandy, swappingCandy, function () { swapCandies(selectedCandy, swappingCandy); // Check if swap creates a match if (findMatches()) { movesLeft--; updateUI(); resolveBoard(function () { deselectAll(); isSwapping = false; swappingCandy = null; checkEnd(); }); } else { // No match, swap back but do NOT decrement moves animateSwap(selectedCandy, swappingCandy, function () { swapCandies(selectedCandy, swappingCandy); deselectAll(); isSwapping = false; swappingCandy = null; checkEnd(); }); } }); } else { // Select new candy tween(selectedCandy, { scaleX: 1, scaleY: 1 }, { duration: 100 }); selectedCandy = c; tween(selectedCandy, { scaleX: 1.15, scaleY: 1.15 }, { duration: 100 }); } }; // Drag to swap game.move = function (x, y, obj) { if (isAnimating || !selectedCandy) return; var c = findCandyAt(x, y); if (c && c !== selectedCandy && areAdjacent(selectedCandy, c)) { game.down(x, y, obj); } }; game.up = function (x, y, obj) { // No-op for now }; // --- Game Start --- function startGame() { level = storage.level || 1; score = 0; if (level === 2) { movesLeft = 10; targetScore = 2500; } else { movesLeft = moveLimit; targetScore = 1800; } updateUI(); createBoard(); deselectAll(); isAnimating = false; isSwapping = false; swappingCandy = null; selectedCandy = null; // Start Fnt music LK.playMusic('Fnt'); // Remove any matches at start resolveBoard(); } startGame(); // --- Game Tick --- game.update = function () { // No per-frame logic needed for MVP };
===================================================================
--- original.js
+++ change.js
@@ -112,29 +112,29 @@
});
targetTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(targetTxt);
targetTxt.y = 190;
-// --- Board Positioning ---
-// Add Bg asset as background, scaled to cover the game area
-var bgAsset = LK.getAsset('Bg', {
+// --- Board Positioning ---
+// Add Sg_bg asset as a background layer, scaled to cover the game area
+var sgBgAsset = LK.getAsset('Sg_bg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
-game.addChild(bgAsset);
-// Add Sg_bg asset as a layer between background and sweets
-var sgBgAsset = LK.getAsset('Sg_bg', {
+game.addChild(sgBgAsset);
+// Add Bg asset as background, scaled to cover the game area
+var bgAsset = LK.getAsset('Bg', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732
});
-game.addChild(sgBgAsset);
+game.addChild(bgAsset);
var boardWidth = boardCols * candySize;
var boardHeight = boardRows * candySize;
var boardOffsetX = Math.floor((2048 - boardWidth) / 2);
var boardOffsetY = Math.floor((2732 - boardHeight) / 2) + 60;