/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Tile class var TLTile = Container.expand(function () { var self = Container.call(this); // Properties self.levelIdx = 0; // 0-5 self.gridX = 0; self.gridY = 0; self.asset = null; // Set tile level and update asset self.setLevel = function (levelIdx) { self.levelIdx = levelIdx; if (self.asset) { self.removeChild(self.asset); self.asset.destroy(); } var assetId = TL_LEVELS[levelIdx].asset; self.asset = self.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); }; // Animate merge pop self.mergePop = function () { tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 80, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 80, easing: tween.easeIn }); } }); }; // Animate spawn self.spawnPop = function () { self.scaleX = self.scaleY = 0.2; tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.bounceOut }); }; // Animate move to (x, y) in px self.moveTo = function (x, y, onFinish) { tween(self, { x: x, y: y }, { duration: 120, easing: tween.cubicOut, onFinish: onFinish }); }; // Animate coin pop at this tile self.coinPop = function (amount) { var coin = LK.getAsset('coinpop', { anchorX: 0.5, anchorY: 0.5, x: self.x, y: self.y - 60 }); coin.alpha = 0.9; game.addChild(coin); var txt = new Text2('+' + amount, { size: 60, fill: '#fff700', font: "Alfa Slab One" }); txt.anchor.set(0.5, 0.5); txt.x = self.x; txt.y = self.y - 60; game.addChild(txt); tween(coin, { y: coin.y - 80, alpha: 0 }, { duration: 600, easing: tween.linear }); tween(txt, { y: txt.y - 80, alpha: 0 }, { duration: 600, easing: tween.linear, onFinish: function onFinish() { coin.destroy(); txt.destroy(); } }); }; // Set grid position (not pixel position) self.setGrid = function (gx, gy) { self.gridX = gx; self.gridY = gy; var pos = getTilePixelPos(gx, gy); self.x = pos.x; self.y = pos.y; }; // For drag highlight self.setHighlight = function (on) { if (on) { self.asset.alpha = 0.7; } else { self.asset.alpha = 1; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xf7f7f7 }); /**** * Game Code ****/ // --- General background image --- /* We use 6 TL tile images, one for each denomination. Asset IDs: 'tile5', 'tile10', 'tile20', 'tile50', 'tile100', 'tile200' Each tile is a square, 300x300 px. */ /* Coin pop effect */ // TL tile levels and their properties var generalBg = LK.getAsset('generalBg', { width: 2048, height: 2732, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 }); generalBg.alpha = 1; game.addChild(generalBg); // --- Grid setup --- var TL_LEVELS = [{ value: 5, asset: 'tile5', donation: 5, color: 0xf7d13d // yellow }, { value: 10, asset: 'tile10', donation: 10, color: 0xf7a13d // orange }, { value: 20, asset: 'tile20', donation: 20, color: 0xf76d3d // red-orange }, { value: 50, asset: 'tile50', donation: 50, color: 0x3db8f7 // blue }, { value: 100, asset: 'tile100', donation: 100, color: 0x44de83 // green }, { value: 200, asset: 'tile200', donation: 200, color: 0xb8b031 // gold }]; // Helper: get next level index, or null if max function getNextLevelIndex(levelIdx) { if (levelIdx < TL_LEVELS.length - 1) return levelIdx + 1; return null; } var GRID_SIZE = 4; // 4x4 var TILE_SIZE = 320; // px, including margin var TILE_MARGIN = 20; // px var gridOriginX = Math.floor((2048 - (GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN)) / 2); var gridOriginY = 700; // 2D array of tiles (null or TLTile) // --- Grid background highlight --- // Use a dedicated grid background asset to avoid name conflict with 200 TL asset var gridAsset = LK.getAsset('gridBg', { width: GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN + 40, height: GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN + 40, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: gridOriginY + (GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN) / 2 }); gridAsset.alpha = 1; game.addChild(gridAsset); var grid = []; for (var i = 0; i < GRID_SIZE; ++i) { grid[i] = []; for (var j = 0; j < GRID_SIZE; ++j) grid[i][j] = null; } // Helper: get pixel position for grid cell function getTilePixelPos(gx, gy) { return { x: gridOriginX + gx * (TILE_SIZE + TILE_MARGIN) + TILE_SIZE / 2, y: gridOriginY + gy * (TILE_SIZE + TILE_MARGIN) + TILE_SIZE / 2 }; } // --- Score and donation --- // --- Donation Frame --- var donationFrame = LK.getAsset('tile200', { width: 600, height: 120, anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 0 }); donationFrame.alpha = 0.18; LK.gui.top.addChild(donationFrame); // Use persistent storage for donation (money) var donation = storage.donation || 0; var donationTxt = new Text2('Sermaye: ' + donation + ' TL', { size: 90, fill: '#1a1a1a', font: "Alfa Slab One" }); donationTxt.anchor.set(0.5, 0); donationTxt.y = 20; LK.gui.top.addChild(donationTxt); // --- Draw a line for where we put the money --- // We'll use a very thin, wide box as a line, just below the grid var lineY = gridOriginY + GRID_SIZE * (TILE_SIZE + TILE_MARGIN) + 40; var line = LK.getAsset('box', { width: 1200, height: 12, color: 0x1a1a1a, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: lineY }); line.alpha = 0.18; game.addChild(line); // --- Next tile preview --- var nextLevelIdx = 0; function randomLevelIdx() { // --- Level Bar UI --- // Draw a horizontal bar of all TL tile levels at the bottom of the game area var levelBarTiles = []; var levelBarLabels = []; var levelBarTileSize = 120; var levelBarSpacing = 32; var totalBarWidth = TL_LEVELS.length * levelBarTileSize + (TL_LEVELS.length - 1) * levelBarSpacing; var barStartX = Math.floor((2048 - totalBarWidth) / 2) + levelBarTileSize / 2; var levelBarY = 2732 - 320 - levelBarTileSize / 2; // Move up: 320px margin from bottom, centered on tile (2x more up) for (var i = 0; i < TL_LEVELS.length; ++i) { // Draw colored slot behind the tile var slot = LK.getAsset('coinpop', { width: levelBarTileSize + 24, height: levelBarTileSize + 24, color: TL_LEVELS[i].color, anchorX: 0.5, anchorY: 0.5, x: barStartX + i * (levelBarTileSize + levelBarSpacing), y: levelBarY }); slot.alpha = 0.32; game.addChild(slot); var tileAsset = LK.getAsset(TL_LEVELS[i].asset, { width: levelBarTileSize, height: levelBarTileSize, anchorX: 0.5, anchorY: 0.5, x: barStartX + i * (levelBarTileSize + levelBarSpacing), y: levelBarY }); tileAsset.alpha = 0.92; game.addChild(tileAsset); levelBarTiles.push(tileAsset); var label = new Text2(TL_LEVELS[i].value + " TL", { size: 38, fill: 0x1A1A1A, font: "Alfa Slab One" }); label.anchor.set(0.5, 0); label.x = tileAsset.x; label.y = tileAsset.y + levelBarTileSize / 2 + 6; game.addChild(label); levelBarLabels.push(label); } // Only 5TL, 10TL, 20TL as next tile (0,1,2) return Math.floor(Math.random() * 3); } nextLevelIdx = randomLevelIdx(); // Place next tile preview and label 2x further up (closer to Sermaye text) var nextTilePreviewY = donationTxt.y + donationTxt.height + 180; var nextTilePreview = LK.getAsset(TL_LEVELS[nextLevelIdx].asset, { anchorX: 0.5, anchorY: 0.0, x: 2048 / 2, // centered horizontally y: nextTilePreviewY // 2x further up below Sermaye text }); var nextTileTxt = new Text2('Next', { size: 60, fill: '#1a1a1a', font: "Alfa Slab One" }); nextTileTxt.anchor.set(0.5, 1); nextTileTxt.x = 2048 / 2; nextTileTxt.y = nextTilePreview.y - 10; // above the preview image, with a small gap game.addChild(nextTilePreview); game.addChild(nextTileTxt); // --- Restart Button --- // Use a custom asset for the restart button, top right, larger size (like pause button), margin 30 from top/right var restartBtn = LK.getAsset('restartBtn', { width: 360, height: 180, anchorX: 1, anchorY: 0, x: 2048 - 30, y: 30 }); restartBtn.alpha = 0.85; game.addChild(restartBtn); // Button interaction restartBtn.interactive = true; restartBtn.down = function (x, y, obj) { // Call LK reset (will restart the game) LK.showGameOver(); }; // --- Custom Tab Button removed --- // Tab popup container (hidden by default) var tabPopup = new Container(); tabPopup.visible = false; tabPopup.width = 1820; tabPopup.height = 1800; // Center the popup in the game area tabPopup.x = (2048 - 1820) / 2; tabPopup.y = (2732 - 1800) / 2; // Add a background to the popup var tabBg = LK.getAsset('generalBg2', { width: 1820, height: 1800, anchorX: 0, anchorY: 0, x: 0, y: 0 }); tabBg.alpha = 0.98; tabPopup.addChild(tabBg); // Add a close button to the popup (top right of popup) var closeBtn = LK.getAsset('shop3', { width: 120, height: 120, anchorX: 1, anchorY: 0, x: 1820 - 20, y: 20 }); closeBtn.alpha = 0.95; closeBtn.interactive = true; closeBtn.down = function () { tabPopup.visible = false; isMarketOpen = false; }; tabPopup.addChild(closeBtn); // Add a label to the popup var tabPopupLabel = new Text2('Tab Content', { size: 90, fill: '#1a1a1a', font: "Alfa Slab One" }); tabPopupLabel.anchor.set(0.5, 0); tabPopupLabel.x = 1820 / 2; tabPopupLabel.y = 60; tabPopup.addChild(tabPopupLabel); // --- 3x3 grid of squares with assets game1 to game9 --- var tabGridRows = 3; var tabGridCols = 3; var tabCellSize = 400; // px, fits 3x3 in 1820x1800 with margin var tabCellMargin = 40; var tabGridOriginX = Math.floor((1820 - (tabGridCols * tabCellSize + (tabGridCols - 1) * tabCellMargin)) / 2); var tabGridOriginY = 220; // below the label // Store references to tab squares for later use if needed var tabSquares = []; for (var row = 0; row < tabGridRows; ++row) { for (var col = 0; col < tabGridCols; ++col) { var idx = row * tabGridCols + col + 1; // 1..9 // Draw square background using game1..game9 asset var square = LK.getAsset('game' + idx, { width: tabCellSize, height: tabCellSize, anchorX: 0, anchorY: 0, x: tabGridOriginX + col * (tabCellSize + tabCellMargin), y: tabGridOriginY + row * (tabCellSize + tabCellMargin) }); square.interactive = true; // Add a simple down handler for demonstration (replace with your logic) square.down = function (index) { return function (x, y, obj) { // Flash the square when pressed LK.effects.flashObject(this, 0xffffff, 200); // If this is the game1 button, save and open Merge TL Mania if (index === 1) { // Save the current game as "Merge TL Mania" storage.saveGame && storage.saveGame("Merge TL Mania"); // Open the Merge TL Mania game (if supported by the platform) if (typeof LK.openGame === "function") { LK.openGame("Merge TL Mania"); } } // If this is the game2 button, open the external TLeater game if (index === 2) { // Open the external game in a new tab/window if (typeof window !== "undefined" && typeof window.open === "function") { window.open("https://upit.com/create/-jjol2nG8v/history", "_blank"); } } }; }(idx); tabPopup.addChild(square); tabSquares.push(square); } } // Add the popup to the game game.addChild(tabPopup); // Button interaction to open the tab removed // --- Helper: update next tile preview --- function updateNextTilePreview() { if (nextTilePreview) { nextTilePreview.destroy(); } if (nextTileTxt) { nextTileTxt.destroy(); } var nextTilePreviewY = donationTxt.y + donationTxt.height + 180; nextTilePreview = LK.getAsset(TL_LEVELS[nextLevelIdx].asset, { anchorX: 0.5, anchorY: 0.0, x: 2048 / 2, y: nextTilePreviewY }); nextTileTxt = new Text2('Next', { size: 60, fill: '#1a1a1a', font: "Alfa Slab One" }); nextTileTxt.anchor.set(0.5, 1); nextTileTxt.x = 2048 / 2; nextTileTxt.y = nextTilePreview.y - 10; game.addChild(nextTilePreview); game.addChild(nextTileTxt); } // --- Spawn a new tile at (gx,gy) with levelIdx --- function spawnTile(gx, gy, levelIdx) { var tile = new TLTile(); tile.setLevel(levelIdx); tile.setGrid(gx, gy); tile.spawnPop(); grid[gx][gy] = tile; game.addChild(tile); return tile; } // --- Find empty cells --- function getEmptyCells() { var arr = []; for (var i = 0; i < GRID_SIZE; ++i) { for (var j = 0; j < GRID_SIZE; ++j) { if (!grid[i][j]) arr.push({ gx: i, gy: j }); } } return arr; } // --- Merge logic --- // Returns true if a merge happened function tryMergeAt(gx, gy) { var tile = grid[gx][gy]; if (!tile) return false; var merged = false; // Find all adjacent (left, right, above) same-level tiles var mergeGroup = [{ gx: gx, gy: gy, tile: tile }]; // Left if (gx > 0 && grid[gx - 1][gy] && grid[gx - 1][gy].levelIdx === tile.levelIdx) { mergeGroup.push({ gx: gx - 1, gy: gy, tile: grid[gx - 1][gy] }); } // Right if (gx < GRID_SIZE - 1 && grid[gx + 1][gy] && grid[gx + 1][gy].levelIdx === tile.levelIdx) { mergeGroup.push({ gx: gx + 1, gy: gy, tile: grid[gx + 1][gy] }); } // Above if (gy > 0 && grid[gx][gy - 1] && grid[gx][gy - 1].levelIdx === tile.levelIdx) { mergeGroup.push({ gx: gx, gy: gy - 1, tile: grid[gx][gy - 1] }); } // Only merge if there are at least 2 of the same level (including self) if (mergeGroup.length > 1) { // Find the "main" tile to upgrade (choose the first in mergeGroup) var main = mergeGroup[0]; var nextIdx = getNextLevelIndex(tile.levelIdx); if (nextIdx === null) return false; // Already max, can't merge // Remove all tiles in mergeGroup from grid for (var i = 0; i < mergeGroup.length; ++i) { var g = mergeGroup[i]; grid[g.gx][g.gy] = null; } // Animate all but main tile to move to main, then destroy for (var i = 1; i < mergeGroup.length; ++i) { var g = mergeGroup[i]; g.tile.setHighlight(false); g.tile.moveTo(main.tile.x, main.tile.y, function (t) { return function () { t.destroy(); }; }(g.tile)); } main.tile.setHighlight(false); // Upgrade main tile main.tile.setLevel(nextIdx); main.tile.mergePop(); // Coin pop var donationAmt = TL_LEVELS[nextIdx].donation; main.tile.coinPop(donationAmt); donation += donationAmt; storage.donation = donation; donationTxt.setText('Sermaye: ' + donation + ' TL'); // Place upgraded tile in grid grid[main.gx][main.gy] = main.tile; // Check win: if merged to 200TL if (nextIdx === 5) { // Win if two 200TL tiles merged LK.showYouWin(); return true; } // After merge, try to merge again at main LK.setTimeout(function () { tryMergeAt(main.gx, main.gy); }, 180); merged = true; } return merged; } // --- Drag and drop logic --- var draggingTile = null; var dragOrigin = null; // {gx,gy} var dragOffset = { x: 0, y: 0 }; var dragValid = false; var dragTarget = null; // Helper: get grid cell from px function getGridCellFromPos(x, y) { for (var i = 0; i < GRID_SIZE; ++i) { for (var j = 0; j < GRID_SIZE; ++j) { var pos = getTilePixelPos(i, j); var dx = Math.abs(x - pos.x); var dy = Math.abs(y - pos.y); if (dx < TILE_SIZE / 2 && dy < TILE_SIZE / 2) { return { gx: i, gy: j }; } } } return null; } // --- Game events --- // Place next tile on tap/click // --- Track if market is open globally --- var isMarketOpen = false; game.down = function (x, y, obj) { if (isMarketOpen) return; // Don't allow placing in top 100px if (y < 100) return; // If dragging, ignore if (draggingTile) return; // Only allow placing if empty cell var cell = getGridCellFromPos(x, y); if (!cell) return; if (grid[cell.gx][cell.gy]) return; // Place tile var tile = spawnTile(cell.gx, cell.gy, nextLevelIdx); // Try merge LK.setTimeout(function () { tryMergeAt(cell.gx, cell.gy); // After merge, check if all slots are filled var allFilled = true; for (var i = 0; i < GRID_SIZE; ++i) { for (var j = 0; j < GRID_SIZE; ++j) { if (!grid[i][j]) { allFilled = false; break; } } if (!allFilled) break; } if (allFilled) { LK.showGameOver(); } }, 120); // Next tile nextLevelIdx = randomLevelIdx(); updateNextTilePreview(); }; // --- Drag to move tiles (optional, for more fun) --- game.move = function (x, y, obj) { if (isMarketOpen) return; // If not dragging, check if user is holding on a tile if (!draggingTile && obj && obj.event && obj.event.type === 'pointerdown') { var cell = getGridCellFromPos(x, y); if (!cell) return; var tile = grid[cell.gx][cell.gy]; if (!tile) return; draggingTile = tile; dragOrigin = { gx: cell.gx, gy: cell.gy }; dragOffset.x = tile.x - x; dragOffset.y = tile.y - y; tile.setHighlight(true); } // If dragging if (draggingTile) { draggingTile.x = x + dragOffset.x; draggingTile.y = y + dragOffset.y; // Highlight valid drop var cell = getGridCellFromPos(x, y); if (cell && (!grid[cell.gx][cell.gy] || cell.gx === dragOrigin.gx && cell.gy === dragOrigin.gy)) { dragValid = true; dragTarget = cell; draggingTile.setHighlight(true); } else { dragValid = false; dragTarget = null; draggingTile.setHighlight(false); } } }; game.up = function (x, y, obj) { if (isMarketOpen) return; if (draggingTile) { // Drop if (dragValid && dragTarget && (dragTarget.gx !== dragOrigin.gx || dragTarget.gy !== dragOrigin.gy)) { // Move tile grid[dragOrigin.gx][dragOrigin.gy] = null; grid[dragTarget.gx][dragTarget.gy] = draggingTile; draggingTile.setGrid(dragTarget.gx, dragTarget.gy); draggingTile.setHighlight(false); // Try merge LK.setTimeout(function () { tryMergeAt(dragTarget.gx, dragTarget.gy); }, 120); } else { // Snap back draggingTile.setGrid(dragOrigin.gx, dragOrigin.gy); draggingTile.setHighlight(false); } draggingTile = null; dragOrigin = null; dragValid = false; dragTarget = null; } }; // --- Game update (not used for logic, but required) --- game.update = function () { // No per-frame logic needed }; // --- Start: spawn 2 random tiles --- function startGame() { var empties = getEmptyCells(); for (var i = 0; i < 2; ++i) { if (empties.length === 0) break; var idx = Math.floor(Math.random() * empties.length); var cell = empties[idx]; var lvl = randomLevelIdx(); spawnTile(cell.gx, cell.gy, lvl); empties.splice(idx, 1); } } startGame(); ; // Save this scene as MergeTL and open a new scene named TLeater // Scene change to 'TLeater' would happen here if supported
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Tile class
var TLTile = Container.expand(function () {
var self = Container.call(this);
// Properties
self.levelIdx = 0; // 0-5
self.gridX = 0;
self.gridY = 0;
self.asset = null;
// Set tile level and update asset
self.setLevel = function (levelIdx) {
self.levelIdx = levelIdx;
if (self.asset) {
self.removeChild(self.asset);
self.asset.destroy();
}
var assetId = TL_LEVELS[levelIdx].asset;
self.asset = self.attachAsset(assetId, {
anchorX: 0.5,
anchorY: 0.5
});
};
// Animate merge pop
self.mergePop = function () {
tween(self, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 80,
easing: tween.easeIn
});
}
});
};
// Animate spawn
self.spawnPop = function () {
self.scaleX = self.scaleY = 0.2;
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 120,
easing: tween.bounceOut
});
};
// Animate move to (x, y) in px
self.moveTo = function (x, y, onFinish) {
tween(self, {
x: x,
y: y
}, {
duration: 120,
easing: tween.cubicOut,
onFinish: onFinish
});
};
// Animate coin pop at this tile
self.coinPop = function (amount) {
var coin = LK.getAsset('coinpop', {
anchorX: 0.5,
anchorY: 0.5,
x: self.x,
y: self.y - 60
});
coin.alpha = 0.9;
game.addChild(coin);
var txt = new Text2('+' + amount, {
size: 60,
fill: '#fff700',
font: "Alfa Slab One"
});
txt.anchor.set(0.5, 0.5);
txt.x = self.x;
txt.y = self.y - 60;
game.addChild(txt);
tween(coin, {
y: coin.y - 80,
alpha: 0
}, {
duration: 600,
easing: tween.linear
});
tween(txt, {
y: txt.y - 80,
alpha: 0
}, {
duration: 600,
easing: tween.linear,
onFinish: function onFinish() {
coin.destroy();
txt.destroy();
}
});
};
// Set grid position (not pixel position)
self.setGrid = function (gx, gy) {
self.gridX = gx;
self.gridY = gy;
var pos = getTilePixelPos(gx, gy);
self.x = pos.x;
self.y = pos.y;
};
// For drag highlight
self.setHighlight = function (on) {
if (on) {
self.asset.alpha = 0.7;
} else {
self.asset.alpha = 1;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xf7f7f7
});
/****
* Game Code
****/
// --- General background image ---
/*
We use 6 TL tile images, one for each denomination.
Asset IDs: 'tile5', 'tile10', 'tile20', 'tile50', 'tile100', 'tile200'
Each tile is a square, 300x300 px.
*/
/* Coin pop effect */
// TL tile levels and their properties
var generalBg = LK.getAsset('generalBg', {
width: 2048,
height: 2732,
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
generalBg.alpha = 1;
game.addChild(generalBg);
// --- Grid setup ---
var TL_LEVELS = [{
value: 5,
asset: 'tile5',
donation: 5,
color: 0xf7d13d // yellow
}, {
value: 10,
asset: 'tile10',
donation: 10,
color: 0xf7a13d // orange
}, {
value: 20,
asset: 'tile20',
donation: 20,
color: 0xf76d3d // red-orange
}, {
value: 50,
asset: 'tile50',
donation: 50,
color: 0x3db8f7 // blue
}, {
value: 100,
asset: 'tile100',
donation: 100,
color: 0x44de83 // green
}, {
value: 200,
asset: 'tile200',
donation: 200,
color: 0xb8b031 // gold
}];
// Helper: get next level index, or null if max
function getNextLevelIndex(levelIdx) {
if (levelIdx < TL_LEVELS.length - 1) return levelIdx + 1;
return null;
}
var GRID_SIZE = 4; // 4x4
var TILE_SIZE = 320; // px, including margin
var TILE_MARGIN = 20; // px
var gridOriginX = Math.floor((2048 - (GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN)) / 2);
var gridOriginY = 700;
// 2D array of tiles (null or TLTile)
// --- Grid background highlight ---
// Use a dedicated grid background asset to avoid name conflict with 200 TL asset
var gridAsset = LK.getAsset('gridBg', {
width: GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN + 40,
height: GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN + 40,
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: gridOriginY + (GRID_SIZE * TILE_SIZE + (GRID_SIZE - 1) * TILE_MARGIN) / 2
});
gridAsset.alpha = 1;
game.addChild(gridAsset);
var grid = [];
for (var i = 0; i < GRID_SIZE; ++i) {
grid[i] = [];
for (var j = 0; j < GRID_SIZE; ++j) grid[i][j] = null;
}
// Helper: get pixel position for grid cell
function getTilePixelPos(gx, gy) {
return {
x: gridOriginX + gx * (TILE_SIZE + TILE_MARGIN) + TILE_SIZE / 2,
y: gridOriginY + gy * (TILE_SIZE + TILE_MARGIN) + TILE_SIZE / 2
};
}
// --- Score and donation ---
// --- Donation Frame ---
var donationFrame = LK.getAsset('tile200', {
width: 600,
height: 120,
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 0
});
donationFrame.alpha = 0.18;
LK.gui.top.addChild(donationFrame);
// Use persistent storage for donation (money)
var donation = storage.donation || 0;
var donationTxt = new Text2('Sermaye: ' + donation + ' TL', {
size: 90,
fill: '#1a1a1a',
font: "Alfa Slab One"
});
donationTxt.anchor.set(0.5, 0);
donationTxt.y = 20;
LK.gui.top.addChild(donationTxt);
// --- Draw a line for where we put the money ---
// We'll use a very thin, wide box as a line, just below the grid
var lineY = gridOriginY + GRID_SIZE * (TILE_SIZE + TILE_MARGIN) + 40;
var line = LK.getAsset('box', {
width: 1200,
height: 12,
color: 0x1a1a1a,
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: lineY
});
line.alpha = 0.18;
game.addChild(line);
// --- Next tile preview ---
var nextLevelIdx = 0;
function randomLevelIdx() {
// --- Level Bar UI ---
// Draw a horizontal bar of all TL tile levels at the bottom of the game area
var levelBarTiles = [];
var levelBarLabels = [];
var levelBarTileSize = 120;
var levelBarSpacing = 32;
var totalBarWidth = TL_LEVELS.length * levelBarTileSize + (TL_LEVELS.length - 1) * levelBarSpacing;
var barStartX = Math.floor((2048 - totalBarWidth) / 2) + levelBarTileSize / 2;
var levelBarY = 2732 - 320 - levelBarTileSize / 2; // Move up: 320px margin from bottom, centered on tile (2x more up)
for (var i = 0; i < TL_LEVELS.length; ++i) {
// Draw colored slot behind the tile
var slot = LK.getAsset('coinpop', {
width: levelBarTileSize + 24,
height: levelBarTileSize + 24,
color: TL_LEVELS[i].color,
anchorX: 0.5,
anchorY: 0.5,
x: barStartX + i * (levelBarTileSize + levelBarSpacing),
y: levelBarY
});
slot.alpha = 0.32;
game.addChild(slot);
var tileAsset = LK.getAsset(TL_LEVELS[i].asset, {
width: levelBarTileSize,
height: levelBarTileSize,
anchorX: 0.5,
anchorY: 0.5,
x: barStartX + i * (levelBarTileSize + levelBarSpacing),
y: levelBarY
});
tileAsset.alpha = 0.92;
game.addChild(tileAsset);
levelBarTiles.push(tileAsset);
var label = new Text2(TL_LEVELS[i].value + " TL", {
size: 38,
fill: 0x1A1A1A,
font: "Alfa Slab One"
});
label.anchor.set(0.5, 0);
label.x = tileAsset.x;
label.y = tileAsset.y + levelBarTileSize / 2 + 6;
game.addChild(label);
levelBarLabels.push(label);
}
// Only 5TL, 10TL, 20TL as next tile (0,1,2)
return Math.floor(Math.random() * 3);
}
nextLevelIdx = randomLevelIdx();
// Place next tile preview and label 2x further up (closer to Sermaye text)
var nextTilePreviewY = donationTxt.y + donationTxt.height + 180;
var nextTilePreview = LK.getAsset(TL_LEVELS[nextLevelIdx].asset, {
anchorX: 0.5,
anchorY: 0.0,
x: 2048 / 2,
// centered horizontally
y: nextTilePreviewY // 2x further up below Sermaye text
});
var nextTileTxt = new Text2('Next', {
size: 60,
fill: '#1a1a1a',
font: "Alfa Slab One"
});
nextTileTxt.anchor.set(0.5, 1);
nextTileTxt.x = 2048 / 2;
nextTileTxt.y = nextTilePreview.y - 10; // above the preview image, with a small gap
game.addChild(nextTilePreview);
game.addChild(nextTileTxt);
// --- Restart Button ---
// Use a custom asset for the restart button, top right, larger size (like pause button), margin 30 from top/right
var restartBtn = LK.getAsset('restartBtn', {
width: 360,
height: 180,
anchorX: 1,
anchorY: 0,
x: 2048 - 30,
y: 30
});
restartBtn.alpha = 0.85;
game.addChild(restartBtn);
// Button interaction
restartBtn.interactive = true;
restartBtn.down = function (x, y, obj) {
// Call LK reset (will restart the game)
LK.showGameOver();
};
// --- Custom Tab Button removed ---
// Tab popup container (hidden by default)
var tabPopup = new Container();
tabPopup.visible = false;
tabPopup.width = 1820;
tabPopup.height = 1800;
// Center the popup in the game area
tabPopup.x = (2048 - 1820) / 2;
tabPopup.y = (2732 - 1800) / 2;
// Add a background to the popup
var tabBg = LK.getAsset('generalBg2', {
width: 1820,
height: 1800,
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
tabBg.alpha = 0.98;
tabPopup.addChild(tabBg);
// Add a close button to the popup (top right of popup)
var closeBtn = LK.getAsset('shop3', {
width: 120,
height: 120,
anchorX: 1,
anchorY: 0,
x: 1820 - 20,
y: 20
});
closeBtn.alpha = 0.95;
closeBtn.interactive = true;
closeBtn.down = function () {
tabPopup.visible = false;
isMarketOpen = false;
};
tabPopup.addChild(closeBtn);
// Add a label to the popup
var tabPopupLabel = new Text2('Tab Content', {
size: 90,
fill: '#1a1a1a',
font: "Alfa Slab One"
});
tabPopupLabel.anchor.set(0.5, 0);
tabPopupLabel.x = 1820 / 2;
tabPopupLabel.y = 60;
tabPopup.addChild(tabPopupLabel);
// --- 3x3 grid of squares with assets game1 to game9 ---
var tabGridRows = 3;
var tabGridCols = 3;
var tabCellSize = 400; // px, fits 3x3 in 1820x1800 with margin
var tabCellMargin = 40;
var tabGridOriginX = Math.floor((1820 - (tabGridCols * tabCellSize + (tabGridCols - 1) * tabCellMargin)) / 2);
var tabGridOriginY = 220; // below the label
// Store references to tab squares for later use if needed
var tabSquares = [];
for (var row = 0; row < tabGridRows; ++row) {
for (var col = 0; col < tabGridCols; ++col) {
var idx = row * tabGridCols + col + 1; // 1..9
// Draw square background using game1..game9 asset
var square = LK.getAsset('game' + idx, {
width: tabCellSize,
height: tabCellSize,
anchorX: 0,
anchorY: 0,
x: tabGridOriginX + col * (tabCellSize + tabCellMargin),
y: tabGridOriginY + row * (tabCellSize + tabCellMargin)
});
square.interactive = true;
// Add a simple down handler for demonstration (replace with your logic)
square.down = function (index) {
return function (x, y, obj) {
// Flash the square when pressed
LK.effects.flashObject(this, 0xffffff, 200);
// If this is the game1 button, save and open Merge TL Mania
if (index === 1) {
// Save the current game as "Merge TL Mania"
storage.saveGame && storage.saveGame("Merge TL Mania");
// Open the Merge TL Mania game (if supported by the platform)
if (typeof LK.openGame === "function") {
LK.openGame("Merge TL Mania");
}
}
// If this is the game2 button, open the external TLeater game
if (index === 2) {
// Open the external game in a new tab/window
if (typeof window !== "undefined" && typeof window.open === "function") {
window.open("https://upit.com/create/-jjol2nG8v/history", "_blank");
}
}
};
}(idx);
tabPopup.addChild(square);
tabSquares.push(square);
}
}
// Add the popup to the game
game.addChild(tabPopup);
// Button interaction to open the tab removed
// --- Helper: update next tile preview ---
function updateNextTilePreview() {
if (nextTilePreview) {
nextTilePreview.destroy();
}
if (nextTileTxt) {
nextTileTxt.destroy();
}
var nextTilePreviewY = donationTxt.y + donationTxt.height + 180;
nextTilePreview = LK.getAsset(TL_LEVELS[nextLevelIdx].asset, {
anchorX: 0.5,
anchorY: 0.0,
x: 2048 / 2,
y: nextTilePreviewY
});
nextTileTxt = new Text2('Next', {
size: 60,
fill: '#1a1a1a',
font: "Alfa Slab One"
});
nextTileTxt.anchor.set(0.5, 1);
nextTileTxt.x = 2048 / 2;
nextTileTxt.y = nextTilePreview.y - 10;
game.addChild(nextTilePreview);
game.addChild(nextTileTxt);
}
// --- Spawn a new tile at (gx,gy) with levelIdx ---
function spawnTile(gx, gy, levelIdx) {
var tile = new TLTile();
tile.setLevel(levelIdx);
tile.setGrid(gx, gy);
tile.spawnPop();
grid[gx][gy] = tile;
game.addChild(tile);
return tile;
}
// --- Find empty cells ---
function getEmptyCells() {
var arr = [];
for (var i = 0; i < GRID_SIZE; ++i) {
for (var j = 0; j < GRID_SIZE; ++j) {
if (!grid[i][j]) arr.push({
gx: i,
gy: j
});
}
}
return arr;
}
// --- Merge logic ---
// Returns true if a merge happened
function tryMergeAt(gx, gy) {
var tile = grid[gx][gy];
if (!tile) return false;
var merged = false;
// Find all adjacent (left, right, above) same-level tiles
var mergeGroup = [{
gx: gx,
gy: gy,
tile: tile
}];
// Left
if (gx > 0 && grid[gx - 1][gy] && grid[gx - 1][gy].levelIdx === tile.levelIdx) {
mergeGroup.push({
gx: gx - 1,
gy: gy,
tile: grid[gx - 1][gy]
});
}
// Right
if (gx < GRID_SIZE - 1 && grid[gx + 1][gy] && grid[gx + 1][gy].levelIdx === tile.levelIdx) {
mergeGroup.push({
gx: gx + 1,
gy: gy,
tile: grid[gx + 1][gy]
});
}
// Above
if (gy > 0 && grid[gx][gy - 1] && grid[gx][gy - 1].levelIdx === tile.levelIdx) {
mergeGroup.push({
gx: gx,
gy: gy - 1,
tile: grid[gx][gy - 1]
});
}
// Only merge if there are at least 2 of the same level (including self)
if (mergeGroup.length > 1) {
// Find the "main" tile to upgrade (choose the first in mergeGroup)
var main = mergeGroup[0];
var nextIdx = getNextLevelIndex(tile.levelIdx);
if (nextIdx === null) return false; // Already max, can't merge
// Remove all tiles in mergeGroup from grid
for (var i = 0; i < mergeGroup.length; ++i) {
var g = mergeGroup[i];
grid[g.gx][g.gy] = null;
}
// Animate all but main tile to move to main, then destroy
for (var i = 1; i < mergeGroup.length; ++i) {
var g = mergeGroup[i];
g.tile.setHighlight(false);
g.tile.moveTo(main.tile.x, main.tile.y, function (t) {
return function () {
t.destroy();
};
}(g.tile));
}
main.tile.setHighlight(false);
// Upgrade main tile
main.tile.setLevel(nextIdx);
main.tile.mergePop();
// Coin pop
var donationAmt = TL_LEVELS[nextIdx].donation;
main.tile.coinPop(donationAmt);
donation += donationAmt;
storage.donation = donation;
donationTxt.setText('Sermaye: ' + donation + ' TL');
// Place upgraded tile in grid
grid[main.gx][main.gy] = main.tile;
// Check win: if merged to 200TL
if (nextIdx === 5) {
// Win if two 200TL tiles merged
LK.showYouWin();
return true;
}
// After merge, try to merge again at main
LK.setTimeout(function () {
tryMergeAt(main.gx, main.gy);
}, 180);
merged = true;
}
return merged;
}
// --- Drag and drop logic ---
var draggingTile = null;
var dragOrigin = null; // {gx,gy}
var dragOffset = {
x: 0,
y: 0
};
var dragValid = false;
var dragTarget = null;
// Helper: get grid cell from px
function getGridCellFromPos(x, y) {
for (var i = 0; i < GRID_SIZE; ++i) {
for (var j = 0; j < GRID_SIZE; ++j) {
var pos = getTilePixelPos(i, j);
var dx = Math.abs(x - pos.x);
var dy = Math.abs(y - pos.y);
if (dx < TILE_SIZE / 2 && dy < TILE_SIZE / 2) {
return {
gx: i,
gy: j
};
}
}
}
return null;
}
// --- Game events ---
// Place next tile on tap/click
// --- Track if market is open globally ---
var isMarketOpen = false;
game.down = function (x, y, obj) {
if (isMarketOpen) return;
// Don't allow placing in top 100px
if (y < 100) return;
// If dragging, ignore
if (draggingTile) return;
// Only allow placing if empty cell
var cell = getGridCellFromPos(x, y);
if (!cell) return;
if (grid[cell.gx][cell.gy]) return;
// Place tile
var tile = spawnTile(cell.gx, cell.gy, nextLevelIdx);
// Try merge
LK.setTimeout(function () {
tryMergeAt(cell.gx, cell.gy);
// After merge, check if all slots are filled
var allFilled = true;
for (var i = 0; i < GRID_SIZE; ++i) {
for (var j = 0; j < GRID_SIZE; ++j) {
if (!grid[i][j]) {
allFilled = false;
break;
}
}
if (!allFilled) break;
}
if (allFilled) {
LK.showGameOver();
}
}, 120);
// Next tile
nextLevelIdx = randomLevelIdx();
updateNextTilePreview();
};
// --- Drag to move tiles (optional, for more fun) ---
game.move = function (x, y, obj) {
if (isMarketOpen) return;
// If not dragging, check if user is holding on a tile
if (!draggingTile && obj && obj.event && obj.event.type === 'pointerdown') {
var cell = getGridCellFromPos(x, y);
if (!cell) return;
var tile = grid[cell.gx][cell.gy];
if (!tile) return;
draggingTile = tile;
dragOrigin = {
gx: cell.gx,
gy: cell.gy
};
dragOffset.x = tile.x - x;
dragOffset.y = tile.y - y;
tile.setHighlight(true);
}
// If dragging
if (draggingTile) {
draggingTile.x = x + dragOffset.x;
draggingTile.y = y + dragOffset.y;
// Highlight valid drop
var cell = getGridCellFromPos(x, y);
if (cell && (!grid[cell.gx][cell.gy] || cell.gx === dragOrigin.gx && cell.gy === dragOrigin.gy)) {
dragValid = true;
dragTarget = cell;
draggingTile.setHighlight(true);
} else {
dragValid = false;
dragTarget = null;
draggingTile.setHighlight(false);
}
}
};
game.up = function (x, y, obj) {
if (isMarketOpen) return;
if (draggingTile) {
// Drop
if (dragValid && dragTarget && (dragTarget.gx !== dragOrigin.gx || dragTarget.gy !== dragOrigin.gy)) {
// Move tile
grid[dragOrigin.gx][dragOrigin.gy] = null;
grid[dragTarget.gx][dragTarget.gy] = draggingTile;
draggingTile.setGrid(dragTarget.gx, dragTarget.gy);
draggingTile.setHighlight(false);
// Try merge
LK.setTimeout(function () {
tryMergeAt(dragTarget.gx, dragTarget.gy);
}, 120);
} else {
// Snap back
draggingTile.setGrid(dragOrigin.gx, dragOrigin.gy);
draggingTile.setHighlight(false);
}
draggingTile = null;
dragOrigin = null;
dragValid = false;
dragTarget = null;
}
};
// --- Game update (not used for logic, but required) ---
game.update = function () {
// No per-frame logic needed
};
// --- Start: spawn 2 random tiles ---
function startGame() {
var empties = getEmptyCells();
for (var i = 0; i < 2; ++i) {
if (empties.length === 0) break;
var idx = Math.floor(Math.random() * empties.length);
var cell = empties[idx];
var lvl = randomLevelIdx();
spawnTile(cell.gx, cell.gy, lvl);
empties.splice(idx, 1);
}
}
startGame();
;
// Save this scene as MergeTL and open a new scene named TLeater
// Scene change to 'TLeater' would happen here if supported
white restart button but no have text. In-Game asset. 2d. High contrast. No shadows
round money board. In-Game asset. 2d. High contrast. No shadows
black wallpaper,no text. In-Game asset. 2d. High contrast. No shadows
4x4 grid no emoji no text , dark,black,shadow. In-Game asset. 2d. High contrast. No shadows
360x120 market text black,shadow,white. In-Game asset. 2d. High contrast. No shadows