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);
}
}
}
}
};