/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Tile class: represents a single tile on the board var Tile = Container.expand(function () { var self = Container.call(this); // Properties self.value = 2; // Default value self.row = 0; self.col = 0; self.bg = null; self.label = null; // Initialize tile graphics self.init = function (value, row, col) { self.value = value; self.row = row; self.col = col; // Remove previous children if any while (self.children.length > 0) { self.removeChild(self.children[0]); } // Use image asset for each value (renamed assets) self.bg = self.attachAsset('tile_' + self.value, { width: tileSize, height: tileSize, anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.bg); }; // Update value and re-render self.setValue = function (newValue) { self.value = newValue; self.init(self.value, self.row, self.col); }; // Animate merge self.animateMerge = function () { self.scale.set(1.2, 1.2); tween(self.scale, { x: 1, y: 1 }, { duration: 120, easing: tween.easeOut }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0xbbada0 }); /**** * Game Code ****/ // blue // light blue // deep gold // gold // yellow // red // red-orange // dark orange // orange // light beige // very light beige // Board settings var boardSize = 4; var tileSize = 320; var tileSpacing = 32; var boardPixelSize = tileSize * boardSize + tileSpacing * (boardSize + 1); var boardOffsetX = (2048 - boardPixelSize) / 2; var boardOffsetY = (2732 - boardPixelSize) / 2 + 80; // Board state: 2D array of tiles or null var board = []; // Tiles container var tilesContainer = new Container(); game.addChild(tilesContainer); // Score var score = 0; var scoreTxt = new Text2('0', { size: 100, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Helper: get position for a tile function getTilePos(row, col) { return { x: boardOffsetX + tileSpacing + col * (tileSize + tileSpacing) + tileSize / 2, y: boardOffsetY + tileSpacing + row * (tileSize + tileSpacing) + tileSize / 2 }; } // Helper: spawn a new tile at a random empty cell function spawnRandomTile() { var empty = []; for (var r = 0; r < boardSize; r++) { for (var c = 0; c < boardSize; c++) { if (!board[r][c]) empty.push({ r: r, c: c }); } } if (empty.length === 0) return false; var idx = Math.floor(Math.random() * empty.length); var pos = empty[idx]; var value = Math.random() < 0.9 ? 2 : 4; var tile = new Tile(); tile.init(value, pos.r, pos.c); var p = getTilePos(pos.r, pos.c); tile.x = p.x; tile.y = p.y; tilesContainer.addChild(tile); board[pos.r][pos.c] = tile; return true; } // Helper: reset board function resetBoard() { // Remove all tiles for (var r = 0; r < boardSize; r++) { for (var c = 0; c < boardSize; c++) { if (board[r][c]) { board[r][c].destroy(); board[r][c] = null; } } } // Spawn two tiles spawnRandomTile(); spawnRandomTile(); } // Helper: update score function setScore(val) { score = val; scoreTxt.setText(score); LK.setScore(score); } // Helper: check for win function checkWin() { for (var r = 0; r < boardSize; r++) { for (var c = 0; c < boardSize; c++) { if (board[r][c] && board[r][c].value === 2048) { LK.showYouWin(); return true; } } } return false; } // Helper: check for game over function checkGameOver() { // If any empty cell, not over for (var r = 0; r < boardSize; r++) { for (var c = 0; c < boardSize; c++) { if (!board[r][c]) return false; } } // If any merge possible, not over for (var r = 0; r < boardSize; r++) { for (var c = 0; c < boardSize; c++) { var v = board[r][c].value; if (r > 0 && board[r - 1][c].value === v) return false; if (r < boardSize - 1 && board[r + 1][c].value === v) return false; if (c > 0 && board[r][c - 1].value === v) return false; if (c < boardSize - 1 && board[r][c + 1].value === v) return false; } } LK.showGameOver(); return true; } // Helper: move/merge logic function moveBoard(dir) { // dir: 'up', 'down', 'left', 'right' var moved = false; var merged = []; for (var r = 0; r < boardSize; r++) { merged[r] = []; for (var c = 0; c < boardSize; c++) merged[r][c] = false; } function traverseRows() { return dir === 'up' ? [0, 1, 2, 3] : dir === 'down' ? [3, 2, 1, 0] : [0, 1, 2, 3]; } function traverseCols() { return dir === 'left' ? [0, 1, 2, 3] : dir === 'right' ? [3, 2, 1, 0] : [0, 1, 2, 3]; } var dRow = dir === 'up' ? -1 : dir === 'down' ? 1 : 0; var dCol = dir === 'left' ? -1 : dir === 'right' ? 1 : 0; var orderRows = traverseRows(); var orderCols = traverseCols(); if (dir === 'up' || dir === 'down') { for (var c = 0; c < boardSize; c++) { for (var i = 0; i < boardSize; i++) { var r = orderRows[i]; if (!board[r][c]) continue; var nr = r; while (true) { var tr = nr + dRow; if (tr < 0 || tr >= boardSize) break; if (!board[tr][c]) { board[tr][c] = board[nr][c]; board[nr][c] = null; board[tr][c].row = tr; nr = tr; moved = true; } else if (board[tr][c].value === board[nr][c].value && !merged[tr][c] && !merged[nr][c]) { board[tr][c].setValue(board[tr][c].value * 2); board[tr][c].animateMerge(); setScore(score + board[tr][c].value); tilesContainer.removeChild(board[nr][c]); board[nr][c].destroy(); board[nr][c] = null; merged[tr][c] = true; moved = true; break; } else { break; } } } } } else { for (var r = 0; r < boardSize; r++) { for (var i = 0; i < boardSize; i++) { var c = orderCols[i]; if (!board[r][c]) continue; var nc = c; while (true) { var tc = nc + dCol; if (tc < 0 || tc >= boardSize) break; if (!board[r][tc]) { board[r][tc] = board[r][nc]; board[r][nc] = null; board[r][tc].col = tc; nc = tc; moved = true; } else if (board[r][tc].value === board[r][nc].value && !merged[r][tc] && !merged[r][nc]) { board[r][tc].setValue(board[r][tc].value * 2); board[r][tc].animateMerge(); setScore(score + board[r][tc].value); tilesContainer.removeChild(board[r][nc]); board[r][nc].destroy(); board[r][nc] = null; merged[r][tc] = true; moved = true; break; } else { break; } } } } } // Animate all tiles to their new positions for (var r = 0; r < boardSize; r++) { for (var c = 0; c < boardSize; c++) { if (board[r][c]) { var p = getTilePos(r, c); tween(board[r][c], { x: p.x, y: p.y }, { duration: 80, easing: tween.easeOut }); } } } if (moved) { LK.getSound('move').play(); LK.getSound('move').play(); LK.setTimeout(function () { spawnRandomTile(); checkWin(); checkGameOver(); }, 100); } else { // If no move was made, check if game is over (no moves left) checkGameOver(); } } // Draw board background // Initialize board array for (var r = 0; r < boardSize; r++) { board[r] = []; for (var c = 0; c < boardSize; c++) { board[r][c] = null; } } // Start game setScore(0); resetBoard(); // Touch/drag controls var dragStart = null; var dragEnd = null; var dragThreshold = 40; // px game.down = function (x, y, obj) { dragStart = { x: x, y: y }; dragEnd = null; }; game.move = function (x, y, obj) { if (!dragStart) return; dragEnd = { x: x, y: y }; }; game.up = function (x, y, obj) { if (!dragStart || !dragEnd) { dragStart = null; dragEnd = null; return; } var dx = dragEnd.x - dragStart.x; var dy = dragEnd.y - dragStart.y; if (Math.abs(dx) < dragThreshold && Math.abs(dy) < dragThreshold) { dragStart = null; dragEnd = null; return; } if (Math.abs(dx) > Math.abs(dy)) { if (dx > 0) { moveBoard('right'); } else { moveBoard('left'); } } else { if (dy > 0) { moveBoard('down'); } else { moveBoard('up'); } } dragStart = null; dragEnd = null; }; // Reset game on game over or win LK.on('gameover', function () { setScore(0); resetBoard(); }); LK.on('youwin', function () { setScore(0); resetBoard(); });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Tile class: represents a single tile on the board
var Tile = Container.expand(function () {
var self = Container.call(this);
// Properties
self.value = 2; // Default value
self.row = 0;
self.col = 0;
self.bg = null;
self.label = null;
// Initialize tile graphics
self.init = function (value, row, col) {
self.value = value;
self.row = row;
self.col = col;
// Remove previous children if any
while (self.children.length > 0) {
self.removeChild(self.children[0]);
}
// Use image asset for each value (renamed assets)
self.bg = self.attachAsset('tile_' + self.value, {
width: tileSize,
height: tileSize,
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.bg);
};
// Update value and re-render
self.setValue = function (newValue) {
self.value = newValue;
self.init(self.value, self.row, self.col);
};
// Animate merge
self.animateMerge = function () {
self.scale.set(1.2, 1.2);
tween(self.scale, {
x: 1,
y: 1
}, {
duration: 120,
easing: tween.easeOut
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xbbada0
});
/****
* Game Code
****/
// blue
// light blue
// deep gold
// gold
// yellow
// red
// red-orange
// dark orange
// orange
// light beige
// very light beige
// Board settings
var boardSize = 4;
var tileSize = 320;
var tileSpacing = 32;
var boardPixelSize = tileSize * boardSize + tileSpacing * (boardSize + 1);
var boardOffsetX = (2048 - boardPixelSize) / 2;
var boardOffsetY = (2732 - boardPixelSize) / 2 + 80;
// Board state: 2D array of tiles or null
var board = [];
// Tiles container
var tilesContainer = new Container();
game.addChild(tilesContainer);
// Score
var score = 0;
var scoreTxt = new Text2('0', {
size: 100,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// Helper: get position for a tile
function getTilePos(row, col) {
return {
x: boardOffsetX + tileSpacing + col * (tileSize + tileSpacing) + tileSize / 2,
y: boardOffsetY + tileSpacing + row * (tileSize + tileSpacing) + tileSize / 2
};
}
// Helper: spawn a new tile at a random empty cell
function spawnRandomTile() {
var empty = [];
for (var r = 0; r < boardSize; r++) {
for (var c = 0; c < boardSize; c++) {
if (!board[r][c]) empty.push({
r: r,
c: c
});
}
}
if (empty.length === 0) return false;
var idx = Math.floor(Math.random() * empty.length);
var pos = empty[idx];
var value = Math.random() < 0.9 ? 2 : 4;
var tile = new Tile();
tile.init(value, pos.r, pos.c);
var p = getTilePos(pos.r, pos.c);
tile.x = p.x;
tile.y = p.y;
tilesContainer.addChild(tile);
board[pos.r][pos.c] = tile;
return true;
}
// Helper: reset board
function resetBoard() {
// Remove all tiles
for (var r = 0; r < boardSize; r++) {
for (var c = 0; c < boardSize; c++) {
if (board[r][c]) {
board[r][c].destroy();
board[r][c] = null;
}
}
}
// Spawn two tiles
spawnRandomTile();
spawnRandomTile();
}
// Helper: update score
function setScore(val) {
score = val;
scoreTxt.setText(score);
LK.setScore(score);
}
// Helper: check for win
function checkWin() {
for (var r = 0; r < boardSize; r++) {
for (var c = 0; c < boardSize; c++) {
if (board[r][c] && board[r][c].value === 2048) {
LK.showYouWin();
return true;
}
}
}
return false;
}
// Helper: check for game over
function checkGameOver() {
// If any empty cell, not over
for (var r = 0; r < boardSize; r++) {
for (var c = 0; c < boardSize; c++) {
if (!board[r][c]) return false;
}
}
// If any merge possible, not over
for (var r = 0; r < boardSize; r++) {
for (var c = 0; c < boardSize; c++) {
var v = board[r][c].value;
if (r > 0 && board[r - 1][c].value === v) return false;
if (r < boardSize - 1 && board[r + 1][c].value === v) return false;
if (c > 0 && board[r][c - 1].value === v) return false;
if (c < boardSize - 1 && board[r][c + 1].value === v) return false;
}
}
LK.showGameOver();
return true;
}
// Helper: move/merge logic
function moveBoard(dir) {
// dir: 'up', 'down', 'left', 'right'
var moved = false;
var merged = [];
for (var r = 0; r < boardSize; r++) {
merged[r] = [];
for (var c = 0; c < boardSize; c++) merged[r][c] = false;
}
function traverseRows() {
return dir === 'up' ? [0, 1, 2, 3] : dir === 'down' ? [3, 2, 1, 0] : [0, 1, 2, 3];
}
function traverseCols() {
return dir === 'left' ? [0, 1, 2, 3] : dir === 'right' ? [3, 2, 1, 0] : [0, 1, 2, 3];
}
var dRow = dir === 'up' ? -1 : dir === 'down' ? 1 : 0;
var dCol = dir === 'left' ? -1 : dir === 'right' ? 1 : 0;
var orderRows = traverseRows();
var orderCols = traverseCols();
if (dir === 'up' || dir === 'down') {
for (var c = 0; c < boardSize; c++) {
for (var i = 0; i < boardSize; i++) {
var r = orderRows[i];
if (!board[r][c]) continue;
var nr = r;
while (true) {
var tr = nr + dRow;
if (tr < 0 || tr >= boardSize) break;
if (!board[tr][c]) {
board[tr][c] = board[nr][c];
board[nr][c] = null;
board[tr][c].row = tr;
nr = tr;
moved = true;
} else if (board[tr][c].value === board[nr][c].value && !merged[tr][c] && !merged[nr][c]) {
board[tr][c].setValue(board[tr][c].value * 2);
board[tr][c].animateMerge();
setScore(score + board[tr][c].value);
tilesContainer.removeChild(board[nr][c]);
board[nr][c].destroy();
board[nr][c] = null;
merged[tr][c] = true;
moved = true;
break;
} else {
break;
}
}
}
}
} else {
for (var r = 0; r < boardSize; r++) {
for (var i = 0; i < boardSize; i++) {
var c = orderCols[i];
if (!board[r][c]) continue;
var nc = c;
while (true) {
var tc = nc + dCol;
if (tc < 0 || tc >= boardSize) break;
if (!board[r][tc]) {
board[r][tc] = board[r][nc];
board[r][nc] = null;
board[r][tc].col = tc;
nc = tc;
moved = true;
} else if (board[r][tc].value === board[r][nc].value && !merged[r][tc] && !merged[r][nc]) {
board[r][tc].setValue(board[r][tc].value * 2);
board[r][tc].animateMerge();
setScore(score + board[r][tc].value);
tilesContainer.removeChild(board[r][nc]);
board[r][nc].destroy();
board[r][nc] = null;
merged[r][tc] = true;
moved = true;
break;
} else {
break;
}
}
}
}
}
// Animate all tiles to their new positions
for (var r = 0; r < boardSize; r++) {
for (var c = 0; c < boardSize; c++) {
if (board[r][c]) {
var p = getTilePos(r, c);
tween(board[r][c], {
x: p.x,
y: p.y
}, {
duration: 80,
easing: tween.easeOut
});
}
}
}
if (moved) {
LK.getSound('move').play();
LK.getSound('move').play();
LK.setTimeout(function () {
spawnRandomTile();
checkWin();
checkGameOver();
}, 100);
} else {
// If no move was made, check if game is over (no moves left)
checkGameOver();
}
}
// Draw board background
// Initialize board array
for (var r = 0; r < boardSize; r++) {
board[r] = [];
for (var c = 0; c < boardSize; c++) {
board[r][c] = null;
}
}
// Start game
setScore(0);
resetBoard();
// Touch/drag controls
var dragStart = null;
var dragEnd = null;
var dragThreshold = 40; // px
game.down = function (x, y, obj) {
dragStart = {
x: x,
y: y
};
dragEnd = null;
};
game.move = function (x, y, obj) {
if (!dragStart) return;
dragEnd = {
x: x,
y: y
};
};
game.up = function (x, y, obj) {
if (!dragStart || !dragEnd) {
dragStart = null;
dragEnd = null;
return;
}
var dx = dragEnd.x - dragStart.x;
var dy = dragEnd.y - dragStart.y;
if (Math.abs(dx) < dragThreshold && Math.abs(dy) < dragThreshold) {
dragStart = null;
dragEnd = null;
return;
}
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 0) {
moveBoard('right');
} else {
moveBoard('left');
}
} else {
if (dy > 0) {
moveBoard('down');
} else {
moveBoard('up');
}
}
dragStart = null;
dragEnd = null;
};
// Reset game on game over or win
LK.on('gameover', function () {
setScore(0);
resetBoard();
});
LK.on('youwin', function () {
setScore(0);
resetBoard();
});