User prompt
When you finish part 1, move on to part 2.
User prompt
If the target score is reached in the first section, move on to the second section and have 10 moves and the target score is 2500.
User prompt
Let's give 10 moves for the first section. Let's give the target score as 1800.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'row')' in or related to this line: 'var r1 = c1.row,' Line Number: 152
User prompt
fnt music starts when game starts
User prompt
eliminate the spaces between the candies
User prompt
finish the sugars
User prompt
If you make a wrong move, your right to move will be reduced.
User prompt
assign candies to assets
Code edit (1 edits merged)
Please save this source code
User prompt
Candy Match Mania
Initial prompt
There will be 7 different candies and we will need to bring at least 3 of these candies together and explode them, and we will have a certain number of moves.
/**** * 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 --- 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, then advance to part 2 on next game start storage.level = 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
@@ -400,23 +400,11 @@
// Handle win/lose
function checkEnd() {
if (score >= targetScore) {
if (level === 1) {
- // Advance to section 2
- level = 2;
+ // Show win for part 1, then advance to part 2 on next game start
storage.level = 2;
- score = 0;
- movesLeft = 10;
- targetScore = 2500;
- updateUI();
- createBoard();
- deselectAll();
- isAnimating = false;
- isSwapping = false;
- swappingCandy = null;
- selectedCandy = null;
- // Remove any matches at start
- resolveBoard();
+ LK.showYouWin();
return true;
} else {
storage.level = level + 1;
LK.showYouWin();