User prompt
I don't want to drag and drop tiles. I just want to click it to add the bar
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'if (prevGrid[row][col]) {' Line Number: 326
User prompt
Make it harder every level
User prompt
I want to see my level and my point
User prompt
Make the layer system
User prompt
No every color tile need to 3 or it's multiples
User prompt
I can't clear the layer because tiles not matching at the end. Make tile count 3 or it's multiplication
User prompt
I want a multiple layer design. Every level layers gonna increase
User prompt
I want to select tiles and grab to bottom bar to match same shaped tiles
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'row')' in or related to this line: 'var temp = board[tileA.row][tileA.col];' Line Number: 132
Code edit (1 edits merged)
Please save this source code
User prompt
Tile Match Mania
Initial prompt
Make me a basic tile matching game for mobile devices
/**** * Classes ****/ // BottomBar class to hold matched tiles var BottomBar = Container.expand(function () { var self = Container.call(this); self.tiles = []; // Add a tile to the bar self.addTile = function (tileType) { var tile = new Tile(); tile.setType(tileType); tile.x = 100 + self.tiles.length * 200; tile.y = 0; self.addChild(tile); self.tiles.push(tile); }; // Remove all tiles (e.g. after a match) self.clearTiles = function () { for (var i = 0; i < self.tiles.length; i++) { self.tiles[i].destroy(); } self.tiles = []; }; return self; }); // --- Tile grid setup --- // Tile class for draggable/selectable tiles var Tile = Container.expand(function () { var self = Container.call(this); // Properties self.tileType = null; // e.g. 'blue', 'green', etc. self.selected = false; // Attach asset based on type self.setType = function (type) { self.tileType = type; if (self.tileAsset) { self.removeChild(self.tileAsset); } var assetId = 'tile_' + type; self.tileAsset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; // Visual feedback for selection self.setSelected = function (selected) { self.selected = selected; if (self.tileAsset) { self.tileAsset.alpha = selected ? 0.7 : 1.0; } }; // Track last position for drag logic self.lastX = 0; self.lastY = 0; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // --- Tile grid setup --- var gridRows = 6; var gridCols = 6; var tileTypes = ['blue', 'green', 'orange', 'purple', 'red', 'yellow']; var tileGrid = []; var tileSize = 180; var gridOffsetX = (2048 - gridCols * tileSize) / 2 + tileSize / 2; var gridOffsetY = 400; var selectedTile = null; var draggingTile = null; // Create grid of tiles for (var row = 0; row < gridRows; row++) { tileGrid[row] = []; for (var col = 0; col < gridCols; col++) { var tile = new Tile(); var type = tileTypes[Math.floor(Math.random() * tileTypes.length)]; tile.setType(type); tile.x = gridOffsetX + col * tileSize; tile.y = gridOffsetY + row * tileSize; tile.row = row; tile.col = col; tileGrid[row][col] = tile; game.addChild(tile); } } // --- Bottom bar setup --- var bottomBar = new BottomBar(); bottomBar.x = (2048 - tileSize * 5) / 2; bottomBar.y = 2732 - 250; game.addChild(bottomBar); // --- Drag/select logic --- game.down = function (x, y, obj) { // Find tile under pointer for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { var tile = tileGrid[row][col]; if (tile && Math.abs(tile.x - x) < tileSize / 2 && Math.abs(tile.y - y) < tileSize / 2) { selectedTile = tile; tile.setSelected(true); draggingTile = tile; tile.lastX = tile.x; tile.lastY = tile.y; return; } } } }; game.move = function (x, y, obj) { if (draggingTile) { draggingTile.x = x; draggingTile.y = y; } }; game.up = function (x, y, obj) { if (draggingTile) { // Check if released over bottom bar var barY = bottomBar.y; if (y > barY - tileSize / 2) { // Add to bottom bar if not already full if (bottomBar.tiles.length < 5) { bottomBar.addTile(draggingTile.tileType); LK.getSound('pop').play(); // Remove from grid game.removeChild(draggingTile); for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { if (tileGrid[row][col] === draggingTile) { tileGrid[row][col] = null; } } } } else { // Snap back if bar is full draggingTile.x = draggingTile.lastX; draggingTile.y = draggingTile.lastY; } } else { // Snap back to grid draggingTile.x = draggingTile.lastX; draggingTile.y = draggingTile.lastY; } draggingTile.setSelected(false); draggingTile = null; selectedTile = null; } }; // --- Matching logic in bottom bar --- game.update = function () { // Check for match in bottom bar (3+ same type in a row) if (bottomBar.tiles.length >= 3) { var lastType = bottomBar.tiles[0].tileType; var matchCount = 1; for (var i = 1; i < bottomBar.tiles.length; i++) { if (bottomBar.tiles[i].tileType === lastType) { matchCount++; } else { lastType = bottomBar.tiles[i].tileType; matchCount = 1; } if (matchCount >= 3) { // Remove matched tiles for (var j = i - 2; j <= i; j++) { bottomBar.tiles[j].destroy(); } // Remove from array bottomBar.tiles.splice(i - 2, 3); // Add score LK.setScore(LK.getScore() + 10); break; } } } };
===================================================================
--- original.js
+++ change.js
@@ -1,439 +1,180 @@
/****
-* Plugins
-****/
-var tween = LK.import("@upit/tween.v1");
-
-/****
* Classes
****/
-// Tile class
+// BottomBar class to hold matched tiles
+var BottomBar = Container.expand(function () {
+ var self = Container.call(this);
+ self.tiles = [];
+ // Add a tile to the bar
+ self.addTile = function (tileType) {
+ var tile = new Tile();
+ tile.setType(tileType);
+ tile.x = 100 + self.tiles.length * 200;
+ tile.y = 0;
+ self.addChild(tile);
+ self.tiles.push(tile);
+ };
+ // Remove all tiles (e.g. after a match)
+ self.clearTiles = function () {
+ for (var i = 0; i < self.tiles.length; i++) {
+ self.tiles[i].destroy();
+ }
+ self.tiles = [];
+ };
+ return self;
+});
+// --- Tile grid setup ---
+// Tile class for draggable/selectable tiles
var Tile = Container.expand(function () {
var self = Container.call(this);
// Properties
- self.row = 0;
- self.col = 0;
- self.colorId = 0; // 0-5
- self.isMoving = false;
- // Attach asset
- self.setColor = function (colorId) {
- self.colorId = colorId;
+ self.tileType = null; // e.g. 'blue', 'green', etc.
+ self.selected = false;
+ // Attach asset based on type
+ self.setType = function (type) {
+ self.tileType = type;
if (self.tileAsset) {
self.removeChild(self.tileAsset);
}
- var colorNames = ['red', 'blue', 'green', 'yellow', 'purple', 'orange'];
- var assetId = 'tile_' + colorNames[colorId];
+ var assetId = 'tile_' + type;
self.tileAsset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
- // Animate to a new position (row, col)
- self.moveTo = function (row, col, duration, _onFinish) {
- self.row = row;
- self.col = col;
- self.isMoving = true;
- var targetX = boardOffsetX + col * tileSize + tileSize / 2;
- var targetY = boardOffsetY + row * tileSize + tileSize / 2;
- tween(self, {
- x: targetX,
- y: targetY
- }, {
- duration: duration,
- easing: tween.cubicOut,
- onFinish: function onFinish() {
- self.isMoving = false;
- if (_onFinish) _onFinish();
- }
- });
+ // Visual feedback for selection
+ self.setSelected = function (selected) {
+ self.selected = selected;
+ if (self.tileAsset) {
+ self.tileAsset.alpha = selected ? 0.7 : 1.0;
+ }
};
- // Instantly set position
- self.setPosition = function (row, col) {
- self.row = row;
- self.col = col;
- self.x = boardOffsetX + col * tileSize + tileSize / 2;
- self.y = boardOffsetY + row * tileSize + tileSize / 2;
- };
- // Flash when matched
- self.flash = function (_onFinish2) {
- tween(self.tileAsset, {
- alpha: 0
- }, {
- duration: 150,
- easing: tween.linear,
- onFinish: function onFinish() {
- self.tileAsset.alpha = 1;
- if (_onFinish2) _onFinish2();
- }
- });
- };
+ // Track last position for drag logic
+ self.lastX = 0;
+ self.lastY = 0;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
- backgroundColor: 0x222222
+ backgroundColor: 0x000000
});
/****
* Game Code
****/
-// Simple pop sound for matches
-// 6 tile colors for variety
-// --- Board settings ---
-var boardRows = 8;
-var boardCols = 8;
+// --- Tile grid setup ---
+var gridRows = 6;
+var gridCols = 6;
+var tileTypes = ['blue', 'green', 'orange', 'purple', 'red', 'yellow'];
+var tileGrid = [];
var tileSize = 180;
-var boardWidth = boardCols * tileSize;
-var boardHeight = boardRows * tileSize;
-var boardOffsetX = Math.floor((2048 - boardWidth) / 2);
-var boardOffsetY = Math.floor((2732 - boardHeight) / 2);
-// --- Game state ---
-var board = []; // 2D array [row][col] of Tile
-var tiles = []; // Flat array of all Tile objects
+var gridOffsetX = (2048 - gridCols * tileSize) / 2 + tileSize / 2;
+var gridOffsetY = 400;
var selectedTile = null;
-var swappingTile = null;
-var isSwapping = false;
-var isProcessing = false;
-var score = 0;
-var timeLeft = 60; // seconds
-var timerInterval = null;
-var scoreTxt = null;
-var timerTxt = null;
-// --- Utility functions ---
-function randomColorId() {
- return Math.floor(Math.random() * 6);
-}
-// Check if two tiles are adjacent
-function areAdjacent(tileA, tileB) {
- var dr = Math.abs(tileA.row - tileB.row);
- var dc = Math.abs(tileA.col - tileB.col);
- return dr + dc === 1;
-}
-// Swap two tiles in board and animate
-function swapTiles(tileA, tileB, animate, onFinish) {
- // Defensive: Only swap if both tiles are valid
- if (!tileA || !tileB) {
- if (onFinish) onFinish();
- return;
+var draggingTile = null;
+// Create grid of tiles
+for (var row = 0; row < gridRows; row++) {
+ tileGrid[row] = [];
+ for (var col = 0; col < gridCols; col++) {
+ var tile = new Tile();
+ var type = tileTypes[Math.floor(Math.random() * tileTypes.length)];
+ tile.setType(type);
+ tile.x = gridOffsetX + col * tileSize;
+ tile.y = gridOffsetY + row * tileSize;
+ tile.row = row;
+ tile.col = col;
+ tileGrid[row][col] = tile;
+ game.addChild(tile);
}
- // Swap in board array
- var temp = board[tileA.row][tileA.col];
- board[tileA.row][tileA.col] = board[tileB.row][tileB.col];
- board[tileB.row][tileB.col] = temp;
- // Swap row/col
- var tempRow = tileA.row,
- tempCol = tileA.col;
- if (animate) {
- tileA.moveTo(tileB.row, tileB.col, 120);
- tileB.moveTo(tempRow, tempCol, 120, onFinish);
- } else {
- tileA.setPosition(tileB.row, tileB.col);
- tileB.setPosition(tempRow, tempCol);
- if (onFinish) onFinish();
- }
- var trow = tileA.row,
- tcol = tileA.col;
- tileA.row = tileB.row;
- tileA.col = tileB.col;
- tileB.row = tempRow;
- tileB.col = tempCol;
}
-// Find all matches on the board. Returns array of arrays of matched tiles.
-function findAllMatches() {
- var matches = [];
- // Horizontal
- for (var r = 0; r < boardRows; r++) {
- var run = [board[r][0]];
- for (var c = 1; c < boardCols; c++) {
- if (board[r][c].colorId === board[r][c - 1].colorId) {
- run.push(board[r][c]);
- } else {
- if (run.length >= 3) matches.push(run.slice());
- run = [board[r][c]];
+// --- Bottom bar setup ---
+var bottomBar = new BottomBar();
+bottomBar.x = (2048 - tileSize * 5) / 2;
+bottomBar.y = 2732 - 250;
+game.addChild(bottomBar);
+// --- Drag/select logic ---
+game.down = function (x, y, obj) {
+ // Find tile under pointer
+ for (var row = 0; row < gridRows; row++) {
+ for (var col = 0; col < gridCols; col++) {
+ var tile = tileGrid[row][col];
+ if (tile && Math.abs(tile.x - x) < tileSize / 2 && Math.abs(tile.y - y) < tileSize / 2) {
+ selectedTile = tile;
+ tile.setSelected(true);
+ draggingTile = tile;
+ tile.lastX = tile.x;
+ tile.lastY = tile.y;
+ return;
}
}
- if (run.length >= 3) matches.push(run.slice());
}
- // Vertical
- for (var c = 0; c < boardCols; c++) {
- var run = [board[0][c]];
- for (var r = 1; r < boardRows; r++) {
- if (board[r][c].colorId === board[r - 1][c].colorId) {
- run.push(board[r][c]);
- } else {
- if (run.length >= 3) matches.push(run.slice());
- run = [board[r][c]];
- }
- }
- if (run.length >= 3) matches.push(run.slice());
+};
+game.move = function (x, y, obj) {
+ if (draggingTile) {
+ draggingTile.x = x;
+ draggingTile.y = y;
}
- return matches;
-}
-// Remove matched tiles, return array of removed tiles
-function removeMatches(matches, onFinish) {
- var removed = [];
- var toRemove = {};
- for (var i = 0; i < matches.length; i++) {
- for (var j = 0; j < matches[i].length; j++) {
- var t = matches[i][j];
- var key = t.row + ',' + t.col;
- if (!toRemove[key]) {
- toRemove[key] = t;
- removed.push(t);
- }
- }
- }
- var count = removed.length;
- if (count === 0) {
- if (onFinish) onFinish();
- return;
- }
- var finished = 0;
- for (var i = 0; i < removed.length; i++) {
- (function (tile) {
- tile.flash(function () {
- tile.visible = false;
- finished++;
- if (finished === count && onFinish) onFinish();
- });
- })(removed[i]);
- }
- LK.getSound('pop').play();
- score += removed.length * 10;
- scoreTxt.setText(score);
-}
-// Drop tiles to fill empty spaces, return true if any tile moved
-function dropTiles(onFinish) {
- var moved = false;
- var dropCount = 0;
- for (var c = 0; c < boardCols; c++) {
- for (var r = boardRows - 1; r >= 0; r--) {
- if (!board[r][c].visible) {
- // Find nearest above visible tile
- for (var rr = r - 1; rr >= 0; rr--) {
- if (board[rr][c].visible) {
- // Move tile down
- var tile = board[rr][c];
- board[r][c] = tile;
- tile.moveTo(r, c, 120, function () {});
- board[rr][c] = new Tile();
- board[rr][c].setColor(randomColorId());
- board[rr][c].setPosition(rr, c);
- board[rr][c].visible = false;
- game.addChild(board[rr][c]);
- moved = true;
- dropCount++;
- break;
+};
+game.up = function (x, y, obj) {
+ if (draggingTile) {
+ // Check if released over bottom bar
+ var barY = bottomBar.y;
+ if (y > barY - tileSize / 2) {
+ // Add to bottom bar if not already full
+ if (bottomBar.tiles.length < 5) {
+ bottomBar.addTile(draggingTile.tileType);
+ LK.getSound('pop').play();
+ // Remove from grid
+ game.removeChild(draggingTile);
+ for (var row = 0; row < gridRows; row++) {
+ for (var col = 0; col < gridCols; col++) {
+ if (tileGrid[row][col] === draggingTile) {
+ tileGrid[row][col] = null;
+ }
}
}
+ } else {
+ // Snap back if bar is full
+ draggingTile.x = draggingTile.lastX;
+ draggingTile.y = draggingTile.lastY;
}
+ } else {
+ // Snap back to grid
+ draggingTile.x = draggingTile.lastX;
+ draggingTile.y = draggingTile.lastY;
}
- }
- // Animate new tiles for empty spaces at top
- for (var c = 0; c < boardCols; c++) {
- for (var r = 0; r < boardRows; r++) {
- if (!board[r][c].visible) {
- var tile = board[r][c];
- tile.setColor(randomColorId());
- tile.visible = true;
- tile.y = boardOffsetY - tileSize / 2;
- tile.moveTo(r, c, 180, function () {});
- moved = true;
- dropCount++;
- }
- }
- }
- // Wait for all drops to finish
- if (dropCount === 0) {
- if (onFinish) onFinish();
- } else {
- LK.setTimeout(function () {
- if (onFinish) onFinish();
- }, 200);
- }
-}
-// Check if any tile is moving
-function anyTileMoving() {
- for (var i = 0; i < tiles.length; i++) {
- if (tiles[i].isMoving) return true;
- }
- return false;
-}
-// Deselect all tiles
-function deselectTiles() {
- if (selectedTile) {
- tween.stop(selectedTile.tileAsset, {
- scaleX: true,
- scaleY: true
- });
- selectedTile.tileAsset.scaleX = 1;
- selectedTile.tileAsset.scaleY = 1;
+ draggingTile.setSelected(false);
+ draggingTile = null;
selectedTile = null;
}
-}
-// --- Board initialization ---
-function fillBoardNoMatches() {
- // Fill board with random tiles, but avoid initial matches
- for (var r = 0; r < boardRows; r++) {
- board[r] = [];
- for (var c = 0; c < boardCols; c++) {
- var colorId;
- do {
- colorId = randomColorId();
- // Avoid horizontal match
- if (c >= 2 && board[r][c - 1].colorId === colorId && board[r][c - 2].colorId === colorId) continue;
- // Avoid vertical match
- if (r >= 2 && board[r - 1][c].colorId === colorId && board[r - 2][c].colorId === colorId) continue;
- break;
- } while (true);
- var tile = new Tile();
- tile.setColor(colorId);
- tile.setPosition(r, c);
- board[r][c] = tile;
- tiles.push(tile);
- game.addChild(tile);
- }
- }
-}
-// --- GUI ---
-scoreTxt = new Text2('0', {
- size: 100,
- fill: 0xFFFFFF
-});
-scoreTxt.anchor.set(0.5, 0);
-LK.gui.top.addChild(scoreTxt);
-timerTxt = new Text2('60', {
- size: 100,
- fill: 0xFFFFFF
-});
-timerTxt.anchor.set(0.5, 0);
-LK.gui.topRight.addChild(timerTxt);
-// --- Timer ---
-function startTimer() {
- timeLeft = 60;
- timerTxt.setText(timeLeft);
- if (timerInterval) LK.clearInterval(timerInterval);
- timerInterval = LK.setInterval(function () {
- timeLeft--;
- timerTxt.setText(timeLeft);
- if (timeLeft <= 0) {
- LK.clearInterval(timerInterval);
- LK.showGameOver();
- }
- }, 1000);
-}
-// --- Input handling ---
-var dragStartTile = null;
-var dragStartX = 0,
- dragStartY = 0;
-var dragMoved = false;
-function getTileAtPos(x, y) {
- var col = Math.floor((x - boardOffsetX) / tileSize);
- var row = Math.floor((y - boardOffsetY) / tileSize);
- if (row >= 0 && row < boardRows && col >= 0 && col < boardCols) {
- return board[row][col];
- }
- return null;
-}
-game.down = function (x, y, obj) {
- if (isProcessing || anyTileMoving()) return;
- if (x < boardOffsetX || x > boardOffsetX + boardWidth || y < boardOffsetY || y > boardOffsetY + boardHeight) return;
- var tile = getTileAtPos(x, y);
- if (!tile) return;
- dragStartTile = tile;
- dragStartX = x;
- dragStartY = y;
- dragMoved = false;
- deselectTiles();
- selectedTile = tile;
- tween(selectedTile.tileAsset, {
- scaleX: 1.2,
- scaleY: 1.2
- }, {
- duration: 80,
- easing: tween.linear
- });
};
-game.move = function (x, y, obj) {
- if (!dragStartTile || isProcessing || anyTileMoving()) return;
- var dx = x - dragStartX;
- var dy = y - dragStartY;
- if (!dragMoved && (Math.abs(dx) > tileSize / 3 || Math.abs(dy) > tileSize / 3)) {
- // Determine direction
- var dir = null;
- if (Math.abs(dx) > Math.abs(dy)) {
- dir = dx > 0 ? 'right' : 'left';
- } else {
- dir = dy > 0 ? 'down' : 'up';
- }
- var row = dragStartTile.row,
- col = dragStartTile.col;
- var targetRow = row,
- targetCol = col;
- if (dir === 'right') targetCol++;
- if (dir === 'left') targetCol--;
- if (dir === 'down') targetRow++;
- if (dir === 'up') targetRow--;
- if (targetRow >= 0 && targetRow < boardRows && targetCol >= 0 && targetCol < boardCols) {
- var targetTile = board[targetRow][targetCol];
- dragMoved = true;
- isProcessing = true;
- deselectTiles();
- swapTiles(dragStartTile, targetTile, true, function () {
- // After swap, check for matches
- var matches = findAllMatches();
- if (matches.length > 0) {
- processMatches(function () {
- isProcessing = false;
- });
- } else {
- // No match, swap back
- swapTiles(dragStartTile, targetTile, true, function () {
- isProcessing = false;
- });
+// --- Matching logic in bottom bar ---
+game.update = function () {
+ // Check for match in bottom bar (3+ same type in a row)
+ if (bottomBar.tiles.length >= 3) {
+ var lastType = bottomBar.tiles[0].tileType;
+ var matchCount = 1;
+ for (var i = 1; i < bottomBar.tiles.length; i++) {
+ if (bottomBar.tiles[i].tileType === lastType) {
+ matchCount++;
+ } else {
+ lastType = bottomBar.tiles[i].tileType;
+ matchCount = 1;
+ }
+ if (matchCount >= 3) {
+ // Remove matched tiles
+ for (var j = i - 2; j <= i; j++) {
+ bottomBar.tiles[j].destroy();
}
- });
+ // Remove from array
+ bottomBar.tiles.splice(i - 2, 3);
+ // Add score
+ LK.setScore(LK.getScore() + 10);
+ break;
+ }
}
}
-};
-game.up = function (x, y, obj) {
- dragStartTile = null;
- dragMoved = false;
- deselectTiles();
-};
-// --- Match processing loop ---
-function processMatches(onFinish) {
- var matches = findAllMatches();
- if (matches.length === 0) {
- if (onFinish) onFinish();
- return;
- }
- removeMatches(matches, function () {
- dropTiles(function () {
- LK.setTimeout(function () {
- processMatches(onFinish);
- }, 80);
- });
- });
-}
-// --- Game update ---
-game.update = function () {
- // No per-frame logic needed for MVP
-};
-// --- Start game ---
-function startGame() {
- // Reset state
- for (var i = 0; i < tiles.length; i++) {
- tiles[i].destroy();
- }
- tiles = [];
- board = [];
- score = 0;
- scoreTxt.setText(score);
- deselectTiles();
- fillBoardNoMatches();
- startTimer();
-}
-startGame();
\ No newline at end of file
+};
\ No newline at end of file