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 --- // --- Level and Point Display --- var levelText = new Text2('Level: 1', { size: 90, fill: 0xFFFFFF }); levelText.anchor.set(0, 0); // Top left, but avoid platform menu levelText.x = 120; levelText.y = 20; LK.gui.top.addChild(levelText); var pointText = new Text2('Points: 0', { size: 90, fill: 0xFFFFFF }); pointText.anchor.set(1, 0); // Top right pointText.x = LK.gui.top.width - 40; pointText.y = 20; LK.gui.top.addChild(pointText); // --- Multi-layer/level support --- var gridRows = 3; var gridCols = 3; var tileTypes = ['blue', 'green', 'orange', 'purple', 'red', 'yellow']; var tileSize = 180; var gridOffsetX = (2048 - gridCols * tileSize) / 2 + tileSize / 2; var gridOffsetY = 400; var selectedTile = null; var draggingTile = null; // Layer/level variables var currentLayer = 1; var maxLayers = 1; var tileLayers = []; // Array of tileGrid arrays, one per layer function createLayer(layerNum) { var tileGrid = []; // --- Ensure each color's tile count is a multiple of 3 --- var totalTiles = gridRows * gridCols; var colorCount = tileTypes.length; var baseCount = Math.floor(totalTiles / colorCount / 3) * 3; // base multiple of 3 per color var colorCounts = []; var remaining = totalTiles; for (var i = 0; i < colorCount; i++) { colorCounts[i] = baseCount; remaining -= baseCount; } // Distribute remaining tiles, always in multiples of 3 for (var i = 0; remaining > 0 && i < colorCount; i++) { if (remaining >= 3) { colorCounts[i] += 3; remaining -= 3; } } // Build a pool of tile types var tilePool = []; for (var i = 0; i < colorCount; i++) { for (var j = 0; j < colorCounts[i]; j++) { tilePool.push(tileTypes[i]); } } // Shuffle tilePool for (var i = tilePool.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = tilePool[i]; tilePool[i] = tilePool[j]; tilePool[j] = temp; } for (var row = 0; row < gridRows; row++) { tileGrid[row] = []; var _loop = function _loop() { tile = new Tile(); // Pop from shuffled pool type = tilePool.pop(); tile.setType(type); tile.x = gridOffsetX + col * tileSize; tile.y = gridOffsetY + row * tileSize; tile.row = row; tile.col = col; tile.layer = layerNum; tile.visible = layerNum === currentLayer; tileGrid[row][col] = tile; game.addChild(tile); tile.setVisible = function (vis) { this.tileAsset.alpha = vis ? 1.0 : 0.0; this.visible = vis; }; tile.setVisible(layerNum === currentLayer); }, tile, type; for (var col = 0; col < gridCols; col++) { _loop(); } } return tileGrid; } // Initialize first layer tileLayers = []; tileLayers.push(createLayer(1)); maxLayers = 1; currentLayer = 1; // Helper to get current layer's grid function getCurrentGrid() { return tileLayers[currentLayer - 1]; } // --- Bottom bar setup --- var bottomBar = new BottomBar(); bottomBar.x = (2048 - tileSize * 5) / 2; bottomBar.y = 2732 - 250; game.addChild(bottomBar); // --- Click-to-add-bar logic --- game.down = function (x, y, obj) { // Find tile under pointer var tileGrid = getCurrentGrid(); 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) { // Add to bottom bar if not already full if (bottomBar.tiles.length < 5) { bottomBar.addTile(tile.tileType); LK.getSound('pop').play(); // Remove from grid game.removeChild(tile); tileGrid[row][col] = null; } return; } } } }; game.move = function (x, y, obj) { // No drag logic needed }; game.up = function (x, y, obj) { // No drag logic needed }; // --- Matching logic in bottom bar --- function isLayerCleared(layerNum) { var tileGrid = tileLayers[layerNum - 1]; for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { if (tileGrid[row][col]) return false; } } return true; } 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); pointText.setText('Points: ' + LK.getScore()); break; } } } // --- Layer progression logic --- if (isLayerCleared(currentLayer)) { // If more layers exist, go to next if (currentLayer < maxLayers) { // Hide previous layer's tiles var prevGrid = tileLayers[currentLayer - 1]; for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { if (prevGrid[row] && prevGrid[row][col]) prevGrid[row][col].setVisible(false); } } currentLayer++; levelText.setText('Level: ' + currentLayer); // Show new layer's tiles var newGrid = tileLayers[currentLayer - 1]; for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { if (newGrid[row][col]) newGrid[row][col].setVisible(true); } } } else { // Add a new layer (increase difficulty) // Make the game harder by increasing grid size every level, up to a reasonable max if (gridRows < 7) gridRows++; if (gridCols < 7) gridCols++; maxLayers++; // Recalculate grid offsets for new grid size tileSize = 180; gridOffsetX = (2048 - gridCols * tileSize) / 2 + tileSize / 2; gridOffsetY = 400; var newLayerGrid = createLayer(maxLayers); tileLayers.push(newLayerGrid); // Hide previous layer's tiles var prevGrid = tileLayers[currentLayer - 1]; for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { if (prevGrid[row] && prevGrid[row][col]) prevGrid[row][col].setVisible(false); } } currentLayer = maxLayers; levelText.setText('Level: ' + currentLayer); // Show new layer's tiles var newGrid = tileLayers[currentLayer - 1]; for (var row = 0; row < gridRows; row++) { for (var col = 0; col < gridCols; col++) { if (newGrid[row][col]) newGrid[row][col].setVisible(true); } } } } };
/****
* 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 ---
// --- Level and Point Display ---
var levelText = new Text2('Level: 1', {
size: 90,
fill: 0xFFFFFF
});
levelText.anchor.set(0, 0); // Top left, but avoid platform menu
levelText.x = 120;
levelText.y = 20;
LK.gui.top.addChild(levelText);
var pointText = new Text2('Points: 0', {
size: 90,
fill: 0xFFFFFF
});
pointText.anchor.set(1, 0); // Top right
pointText.x = LK.gui.top.width - 40;
pointText.y = 20;
LK.gui.top.addChild(pointText);
// --- Multi-layer/level support ---
var gridRows = 3;
var gridCols = 3;
var tileTypes = ['blue', 'green', 'orange', 'purple', 'red', 'yellow'];
var tileSize = 180;
var gridOffsetX = (2048 - gridCols * tileSize) / 2 + tileSize / 2;
var gridOffsetY = 400;
var selectedTile = null;
var draggingTile = null;
// Layer/level variables
var currentLayer = 1;
var maxLayers = 1;
var tileLayers = []; // Array of tileGrid arrays, one per layer
function createLayer(layerNum) {
var tileGrid = [];
// --- Ensure each color's tile count is a multiple of 3 ---
var totalTiles = gridRows * gridCols;
var colorCount = tileTypes.length;
var baseCount = Math.floor(totalTiles / colorCount / 3) * 3; // base multiple of 3 per color
var colorCounts = [];
var remaining = totalTiles;
for (var i = 0; i < colorCount; i++) {
colorCounts[i] = baseCount;
remaining -= baseCount;
}
// Distribute remaining tiles, always in multiples of 3
for (var i = 0; remaining > 0 && i < colorCount; i++) {
if (remaining >= 3) {
colorCounts[i] += 3;
remaining -= 3;
}
}
// Build a pool of tile types
var tilePool = [];
for (var i = 0; i < colorCount; i++) {
for (var j = 0; j < colorCounts[i]; j++) {
tilePool.push(tileTypes[i]);
}
}
// Shuffle tilePool
for (var i = tilePool.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = tilePool[i];
tilePool[i] = tilePool[j];
tilePool[j] = temp;
}
for (var row = 0; row < gridRows; row++) {
tileGrid[row] = [];
var _loop = function _loop() {
tile = new Tile();
// Pop from shuffled pool
type = tilePool.pop();
tile.setType(type);
tile.x = gridOffsetX + col * tileSize;
tile.y = gridOffsetY + row * tileSize;
tile.row = row;
tile.col = col;
tile.layer = layerNum;
tile.visible = layerNum === currentLayer;
tileGrid[row][col] = tile;
game.addChild(tile);
tile.setVisible = function (vis) {
this.tileAsset.alpha = vis ? 1.0 : 0.0;
this.visible = vis;
};
tile.setVisible(layerNum === currentLayer);
},
tile,
type;
for (var col = 0; col < gridCols; col++) {
_loop();
}
}
return tileGrid;
}
// Initialize first layer
tileLayers = [];
tileLayers.push(createLayer(1));
maxLayers = 1;
currentLayer = 1;
// Helper to get current layer's grid
function getCurrentGrid() {
return tileLayers[currentLayer - 1];
}
// --- Bottom bar setup ---
var bottomBar = new BottomBar();
bottomBar.x = (2048 - tileSize * 5) / 2;
bottomBar.y = 2732 - 250;
game.addChild(bottomBar);
// --- Click-to-add-bar logic ---
game.down = function (x, y, obj) {
// Find tile under pointer
var tileGrid = getCurrentGrid();
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) {
// Add to bottom bar if not already full
if (bottomBar.tiles.length < 5) {
bottomBar.addTile(tile.tileType);
LK.getSound('pop').play();
// Remove from grid
game.removeChild(tile);
tileGrid[row][col] = null;
}
return;
}
}
}
};
game.move = function (x, y, obj) {
// No drag logic needed
};
game.up = function (x, y, obj) {
// No drag logic needed
};
// --- Matching logic in bottom bar ---
function isLayerCleared(layerNum) {
var tileGrid = tileLayers[layerNum - 1];
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
if (tileGrid[row][col]) return false;
}
}
return true;
}
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);
pointText.setText('Points: ' + LK.getScore());
break;
}
}
}
// --- Layer progression logic ---
if (isLayerCleared(currentLayer)) {
// If more layers exist, go to next
if (currentLayer < maxLayers) {
// Hide previous layer's tiles
var prevGrid = tileLayers[currentLayer - 1];
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
if (prevGrid[row] && prevGrid[row][col]) prevGrid[row][col].setVisible(false);
}
}
currentLayer++;
levelText.setText('Level: ' + currentLayer);
// Show new layer's tiles
var newGrid = tileLayers[currentLayer - 1];
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
if (newGrid[row][col]) newGrid[row][col].setVisible(true);
}
}
} else {
// Add a new layer (increase difficulty)
// Make the game harder by increasing grid size every level, up to a reasonable max
if (gridRows < 7) gridRows++;
if (gridCols < 7) gridCols++;
maxLayers++;
// Recalculate grid offsets for new grid size
tileSize = 180;
gridOffsetX = (2048 - gridCols * tileSize) / 2 + tileSize / 2;
gridOffsetY = 400;
var newLayerGrid = createLayer(maxLayers);
tileLayers.push(newLayerGrid);
// Hide previous layer's tiles
var prevGrid = tileLayers[currentLayer - 1];
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
if (prevGrid[row] && prevGrid[row][col]) prevGrid[row][col].setVisible(false);
}
}
currentLayer = maxLayers;
levelText.setText('Level: ' + currentLayer);
// Show new layer's tiles
var newGrid = tileLayers[currentLayer - 1];
for (var row = 0; row < gridRows; row++) {
for (var col = 0; col < gridCols; col++) {
if (newGrid[row][col]) newGrid[row][col].setVisible(true);
}
}
}
}
};