/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Block = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.value = getBlockValue(type); var blockGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5 }); function getTextSize(value) { var baseSize = 192; // 50% of cell height var numDigits = value.toString().length; if (numDigits <= 2) return baseSize; if (numDigits === 3) return baseSize * 0.8; if (numDigits === 4) return baseSize * 0.6; return baseSize * 0.5; } var blockText = new Text2(self.value.toString(), { size: getTextSize(self.value), fill: 0xFFFFFF, fontWeight: 'bold', dropShadow: true, dropShadowColor: 0x000000, dropShadowBlur: 4, dropShadowDistance: 2 }); blockText.anchor.set(0.5, 0.5); self.addChild(blockText); self.setType = function (newType) { self.type = newType; self.value = getBlockValue(newType); self.removeChild(blockGraphics); blockGraphics = self.attachAsset(newType, { anchorX: 0.5, anchorY: 0.5 }); blockText.setText(self.value.toString()); blockText.style.fontSize = getTextSize(self.value); }; return self; }); var GridCell = Container.expand(function () { var self = Container.call(this); var cellGraphics = self.attachAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); self.block = null; self.setBlock = function (block) { if (self.block) { self.removeChild(self.block); } self.block = block; if (block) { self.addChild(block); block.x = 0; block.y = 0; } }; self.hasBlock = function () { return self.block !== null; }; self.clearBlock = function () { if (self.block) { self.removeChild(self.block); self.block = null; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2F4F2F }); /**** * Game Code ****/ var GRID_SIZE = 4; var CELL_SIZE = Math.floor(2048 * 0.75 / GRID_SIZE); var CELL_SPACING = CELL_SIZE + 10; var blockTypes = ['wood', 'stone', 'iron', 'gold', 'diamond', 'emerald', 'netherite', 'obsidian', 'bedrock', 'enderite', 'voidstone']; var grid = []; var isMoving = false; var gameOver = false; function getBlockValue(type) { var values = { 'wood': 2, 'stone': 4, 'iron': 8, 'gold': 16, 'diamond': 32, 'emerald': 64, 'netherite': 128, 'obsidian': 256, 'bedrock': 512, 'enderite': 1024, 'voidstone': 2048 }; return values[type] || 2; } function getNextBlockType(currentType) { var index = blockTypes.indexOf(currentType); if (index < blockTypes.length - 1) { return blockTypes[index + 1]; } return currentType; } function getRandomBlockType() { var types = ['wood', 'wood', 'wood', 'stone', 'stone', 'iron']; return types[Math.floor(Math.random() * types.length)]; } // Create grid var gridContainer = new Container(); game.addChild(gridContainer); for (var row = 0; row < GRID_SIZE; row++) { grid[row] = []; for (var col = 0; col < GRID_SIZE; col++) { var cell = new GridCell(); cell.x = col * CELL_SPACING; cell.y = row * CELL_SPACING; gridContainer.addChild(cell); grid[row][col] = cell; } } // Center grid gridContainer.x = (2048 - (GRID_SIZE - 1) * CELL_SPACING) / 2; gridContainer.y = (2732 - (GRID_SIZE - 1) * CELL_SPACING) / 2; // Score display var scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); scoreTxt.y = 100; // Game over text var gameOverTxt = new Text2('Game Over!', { size: 120, fill: 0xFF0000 }); gameOverTxt.anchor.set(0.5, 0.5); gameOverTxt.visible = false; LK.gui.center.addChild(gameOverTxt); function addRandomBlock() { var emptyCells = []; for (var row = 0; row < GRID_SIZE; row++) { for (var col = 0; col < GRID_SIZE; col++) { if (!grid[row][col].hasBlock()) { emptyCells.push({ row: row, col: col }); } } } if (emptyCells.length > 0) { var randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)]; var newBlock = new Block(getRandomBlockType()); grid[randomCell.row][randomCell.col].setBlock(newBlock); // Scale animation newBlock.scaleX = 0; newBlock.scaleY = 0; tween(newBlock, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } } function canMove() { // Check if any moves are possible for (var row = 0; row < GRID_SIZE; row++) { for (var col = 0; col < GRID_SIZE; col++) { if (!grid[row][col].hasBlock()) { return true; } var currentBlock = grid[row][col].block; // Check adjacent cells for possible merges var directions = [{ dr: 0, dc: 1 }, { dr: 0, dc: -1 }, { dr: 1, dc: 0 }, { dr: -1, dc: 0 }]; for (var d = 0; d < directions.length; d++) { var newRow = row + directions[d].dr; var newCol = col + directions[d].dc; if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) { var adjacentCell = grid[newRow][newCol]; if (!adjacentCell.hasBlock() || adjacentCell.block.type === currentBlock.type) { return true; } } } } } return false; } function slideBlocks(direction) { if (isMoving || gameOver) return; var moved = false; var merged = []; // Initialize merged array for (var row = 0; row < GRID_SIZE; row++) { merged[row] = []; for (var col = 0; col < GRID_SIZE; col++) { merged[row][col] = false; } } isMoving = true; if (direction === 'left' || direction === 'right') { for (var row = 0; row < GRID_SIZE; row++) { var line = []; var positions = []; // Extract blocks from row if (direction === 'left') { for (var col = 0; col < GRID_SIZE; col++) { if (grid[row][col].hasBlock()) { line.push(grid[row][col].block); positions.push(col); grid[row][col].clearBlock(); } } } else { for (var col = GRID_SIZE - 1; col >= 0; col--) { if (grid[row][col].hasBlock()) { line.push(grid[row][col].block); positions.push(col); grid[row][col].clearBlock(); } } } // Merge identical adjacent blocks for (var i = 0; i < line.length - 1; i++) { if (line[i] && line[i + 1] && line[i].type === line[i + 1].type) { var nextType = getNextBlockType(line[i].type); line[i].setType(nextType); LK.setScore(LK.getScore() + getBlockValue(nextType)); line[i + 1].destroy(); line[i + 1] = null; moved = true; LK.getSound('merge').play(); } } // Remove null elements line = line.filter(function (block) { return block !== null; }); // Place blocks back if (direction === 'left') { for (var i = 0; i < line.length; i++) { grid[row][i].setBlock(line[i]); if (positions[i] !== i) moved = true; } } else { for (var i = 0; i < line.length; i++) { grid[row][GRID_SIZE - 1 - i].setBlock(line[i]); if (positions[i] !== GRID_SIZE - 1 - i) moved = true; } } } } else { for (var col = 0; col < GRID_SIZE; col++) { var line = []; var positions = []; // Extract blocks from column if (direction === 'up') { for (var row = 0; row < GRID_SIZE; row++) { if (grid[row][col].hasBlock()) { line.push(grid[row][col].block); positions.push(row); grid[row][col].clearBlock(); } } } else { for (var row = GRID_SIZE - 1; row >= 0; row--) { if (grid[row][col].hasBlock()) { line.push(grid[row][col].block); positions.push(row); grid[row][col].clearBlock(); } } } // Merge identical adjacent blocks for (var i = 0; i < line.length - 1; i++) { if (line[i] && line[i + 1] && line[i].type === line[i + 1].type) { var nextType = getNextBlockType(line[i].type); line[i].setType(nextType); LK.setScore(LK.getScore() + getBlockValue(nextType)); line[i + 1].destroy(); line[i + 1] = null; moved = true; LK.getSound('merge').play(); } } // Remove null elements line = line.filter(function (block) { return block !== null; }); // Place blocks back if (direction === 'up') { for (var i = 0; i < line.length; i++) { grid[i][col].setBlock(line[i]); if (positions[i] !== i) moved = true; } } else { for (var i = 0; i < line.length; i++) { grid[GRID_SIZE - 1 - i][col].setBlock(line[i]); if (positions[i] !== GRID_SIZE - 1 - i) moved = true; } } } } if (moved) { LK.getSound('slide').play(); scoreTxt.setText('Score: ' + LK.getScore()); LK.setTimeout(function () { addRandomBlock(); if (!canMove()) { gameOver = true; gameOverTxt.visible = true; LK.setTimeout(function () { LK.showGameOver(); }, 1500); } isMoving = false; }, 100); } else { isMoving = false; } } var startX = 0; var startY = 0; var isDragging = false; game.down = function (x, y, obj) { if (obj.event && obj.event.preventDefault) { obj.event.preventDefault(); obj.event.stopPropagation(); } startX = x; startY = y; isDragging = true; }; game.up = function (x, y, obj) { if (obj.event && obj.event.preventDefault) { obj.event.preventDefault(); obj.event.stopPropagation(); } if (!isDragging) return; var deltaX = x - startX; var deltaY = y - startY; var threshold = 50; if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > threshold) { if (deltaX > 0) { slideBlocks('right'); } else { slideBlocks('left'); } } else if (Math.abs(deltaY) > threshold) { if (deltaY > 0) { slideBlocks('down'); } else { slideBlocks('up'); } } isDragging = false; }; game.move = function (x, y, obj) { if (isDragging && obj.event && obj.event.preventDefault) { obj.event.preventDefault(); obj.event.stopPropagation(); } }; // Touch/swipe controls are handled by game.down, game.up, and game.move events above // Initialize with two random blocks addRandomBlock(); addRandomBlock(); game.update = function () { // Game logic is handled by events };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Block = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.value = getBlockValue(type);
var blockGraphics = self.attachAsset(type, {
anchorX: 0.5,
anchorY: 0.5
});
function getTextSize(value) {
var baseSize = 192; // 50% of cell height
var numDigits = value.toString().length;
if (numDigits <= 2) return baseSize;
if (numDigits === 3) return baseSize * 0.8;
if (numDigits === 4) return baseSize * 0.6;
return baseSize * 0.5;
}
var blockText = new Text2(self.value.toString(), {
size: getTextSize(self.value),
fill: 0xFFFFFF,
fontWeight: 'bold',
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
blockText.anchor.set(0.5, 0.5);
self.addChild(blockText);
self.setType = function (newType) {
self.type = newType;
self.value = getBlockValue(newType);
self.removeChild(blockGraphics);
blockGraphics = self.attachAsset(newType, {
anchorX: 0.5,
anchorY: 0.5
});
blockText.setText(self.value.toString());
blockText.style.fontSize = getTextSize(self.value);
};
return self;
});
var GridCell = Container.expand(function () {
var self = Container.call(this);
var cellGraphics = self.attachAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
self.block = null;
self.setBlock = function (block) {
if (self.block) {
self.removeChild(self.block);
}
self.block = block;
if (block) {
self.addChild(block);
block.x = 0;
block.y = 0;
}
};
self.hasBlock = function () {
return self.block !== null;
};
self.clearBlock = function () {
if (self.block) {
self.removeChild(self.block);
self.block = null;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2F4F2F
});
/****
* Game Code
****/
var GRID_SIZE = 4;
var CELL_SIZE = Math.floor(2048 * 0.75 / GRID_SIZE);
var CELL_SPACING = CELL_SIZE + 10;
var blockTypes = ['wood', 'stone', 'iron', 'gold', 'diamond', 'emerald', 'netherite', 'obsidian', 'bedrock', 'enderite', 'voidstone'];
var grid = [];
var isMoving = false;
var gameOver = false;
function getBlockValue(type) {
var values = {
'wood': 2,
'stone': 4,
'iron': 8,
'gold': 16,
'diamond': 32,
'emerald': 64,
'netherite': 128,
'obsidian': 256,
'bedrock': 512,
'enderite': 1024,
'voidstone': 2048
};
return values[type] || 2;
}
function getNextBlockType(currentType) {
var index = blockTypes.indexOf(currentType);
if (index < blockTypes.length - 1) {
return blockTypes[index + 1];
}
return currentType;
}
function getRandomBlockType() {
var types = ['wood', 'wood', 'wood', 'stone', 'stone', 'iron'];
return types[Math.floor(Math.random() * types.length)];
}
// Create grid
var gridContainer = new Container();
game.addChild(gridContainer);
for (var row = 0; row < GRID_SIZE; row++) {
grid[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
var cell = new GridCell();
cell.x = col * CELL_SPACING;
cell.y = row * CELL_SPACING;
gridContainer.addChild(cell);
grid[row][col] = cell;
}
}
// Center grid
gridContainer.x = (2048 - (GRID_SIZE - 1) * CELL_SPACING) / 2;
gridContainer.y = (2732 - (GRID_SIZE - 1) * CELL_SPACING) / 2;
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 100;
// Game over text
var gameOverTxt = new Text2('Game Over!', {
size: 120,
fill: 0xFF0000
});
gameOverTxt.anchor.set(0.5, 0.5);
gameOverTxt.visible = false;
LK.gui.center.addChild(gameOverTxt);
function addRandomBlock() {
var emptyCells = [];
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (!grid[row][col].hasBlock()) {
emptyCells.push({
row: row,
col: col
});
}
}
}
if (emptyCells.length > 0) {
var randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
var newBlock = new Block(getRandomBlockType());
grid[randomCell.row][randomCell.col].setBlock(newBlock);
// Scale animation
newBlock.scaleX = 0;
newBlock.scaleY = 0;
tween(newBlock, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
}
function canMove() {
// Check if any moves are possible
for (var row = 0; row < GRID_SIZE; row++) {
for (var col = 0; col < GRID_SIZE; col++) {
if (!grid[row][col].hasBlock()) {
return true;
}
var currentBlock = grid[row][col].block;
// Check adjacent cells for possible merges
var directions = [{
dr: 0,
dc: 1
}, {
dr: 0,
dc: -1
}, {
dr: 1,
dc: 0
}, {
dr: -1,
dc: 0
}];
for (var d = 0; d < directions.length; d++) {
var newRow = row + directions[d].dr;
var newCol = col + directions[d].dc;
if (newRow >= 0 && newRow < GRID_SIZE && newCol >= 0 && newCol < GRID_SIZE) {
var adjacentCell = grid[newRow][newCol];
if (!adjacentCell.hasBlock() || adjacentCell.block.type === currentBlock.type) {
return true;
}
}
}
}
}
return false;
}
function slideBlocks(direction) {
if (isMoving || gameOver) return;
var moved = false;
var merged = [];
// Initialize merged array
for (var row = 0; row < GRID_SIZE; row++) {
merged[row] = [];
for (var col = 0; col < GRID_SIZE; col++) {
merged[row][col] = false;
}
}
isMoving = true;
if (direction === 'left' || direction === 'right') {
for (var row = 0; row < GRID_SIZE; row++) {
var line = [];
var positions = [];
// Extract blocks from row
if (direction === 'left') {
for (var col = 0; col < GRID_SIZE; col++) {
if (grid[row][col].hasBlock()) {
line.push(grid[row][col].block);
positions.push(col);
grid[row][col].clearBlock();
}
}
} else {
for (var col = GRID_SIZE - 1; col >= 0; col--) {
if (grid[row][col].hasBlock()) {
line.push(grid[row][col].block);
positions.push(col);
grid[row][col].clearBlock();
}
}
}
// Merge identical adjacent blocks
for (var i = 0; i < line.length - 1; i++) {
if (line[i] && line[i + 1] && line[i].type === line[i + 1].type) {
var nextType = getNextBlockType(line[i].type);
line[i].setType(nextType);
LK.setScore(LK.getScore() + getBlockValue(nextType));
line[i + 1].destroy();
line[i + 1] = null;
moved = true;
LK.getSound('merge').play();
}
}
// Remove null elements
line = line.filter(function (block) {
return block !== null;
});
// Place blocks back
if (direction === 'left') {
for (var i = 0; i < line.length; i++) {
grid[row][i].setBlock(line[i]);
if (positions[i] !== i) moved = true;
}
} else {
for (var i = 0; i < line.length; i++) {
grid[row][GRID_SIZE - 1 - i].setBlock(line[i]);
if (positions[i] !== GRID_SIZE - 1 - i) moved = true;
}
}
}
} else {
for (var col = 0; col < GRID_SIZE; col++) {
var line = [];
var positions = [];
// Extract blocks from column
if (direction === 'up') {
for (var row = 0; row < GRID_SIZE; row++) {
if (grid[row][col].hasBlock()) {
line.push(grid[row][col].block);
positions.push(row);
grid[row][col].clearBlock();
}
}
} else {
for (var row = GRID_SIZE - 1; row >= 0; row--) {
if (grid[row][col].hasBlock()) {
line.push(grid[row][col].block);
positions.push(row);
grid[row][col].clearBlock();
}
}
}
// Merge identical adjacent blocks
for (var i = 0; i < line.length - 1; i++) {
if (line[i] && line[i + 1] && line[i].type === line[i + 1].type) {
var nextType = getNextBlockType(line[i].type);
line[i].setType(nextType);
LK.setScore(LK.getScore() + getBlockValue(nextType));
line[i + 1].destroy();
line[i + 1] = null;
moved = true;
LK.getSound('merge').play();
}
}
// Remove null elements
line = line.filter(function (block) {
return block !== null;
});
// Place blocks back
if (direction === 'up') {
for (var i = 0; i < line.length; i++) {
grid[i][col].setBlock(line[i]);
if (positions[i] !== i) moved = true;
}
} else {
for (var i = 0; i < line.length; i++) {
grid[GRID_SIZE - 1 - i][col].setBlock(line[i]);
if (positions[i] !== GRID_SIZE - 1 - i) moved = true;
}
}
}
}
if (moved) {
LK.getSound('slide').play();
scoreTxt.setText('Score: ' + LK.getScore());
LK.setTimeout(function () {
addRandomBlock();
if (!canMove()) {
gameOver = true;
gameOverTxt.visible = true;
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
isMoving = false;
}, 100);
} else {
isMoving = false;
}
}
var startX = 0;
var startY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
if (obj.event && obj.event.preventDefault) {
obj.event.preventDefault();
obj.event.stopPropagation();
}
startX = x;
startY = y;
isDragging = true;
};
game.up = function (x, y, obj) {
if (obj.event && obj.event.preventDefault) {
obj.event.preventDefault();
obj.event.stopPropagation();
}
if (!isDragging) return;
var deltaX = x - startX;
var deltaY = y - startY;
var threshold = 50;
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > threshold) {
if (deltaX > 0) {
slideBlocks('right');
} else {
slideBlocks('left');
}
} else if (Math.abs(deltaY) > threshold) {
if (deltaY > 0) {
slideBlocks('down');
} else {
slideBlocks('up');
}
}
isDragging = false;
};
game.move = function (x, y, obj) {
if (isDragging && obj.event && obj.event.preventDefault) {
obj.event.preventDefault();
obj.event.stopPropagation();
}
};
// Touch/swipe controls are handled by game.down, game.up, and game.move events above
// Initialize with two random blocks
addRandomBlock();
addRandomBlock();
game.update = function () {
// Game logic is handled by events
};