/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GameBoard = Container.expand(function (size) {
var self = Container.call(this);
self.size = size || 4;
self.tiles = [];
self.cellSize = 200;
self.init = function () {
// Create background grid
for (var row = 0; row < self.size; row++) {
for (var col = 0; col < self.size; col++) {
var cellBg = self.attachAsset('grid_bg', {
anchorX: 0.5,
anchorY: 0.5
});
cellBg.x = col * self.cellSize;
cellBg.y = row * self.cellSize;
}
}
// Initialize tile array
for (var i = 0; i < self.size; i++) {
self.tiles[i] = [];
for (var j = 0; j < self.size; j++) {
self.tiles[i][j] = new Tile(0);
self.tiles[i][j].x = j * self.cellSize;
self.tiles[i][j].y = i * self.cellSize;
self.addChild(self.tiles[i][j]);
}
}
self.addRandomTile();
self.addRandomTile();
};
self.addRandomTile = function () {
var emptyCells = [];
for (var row = 0; row < self.size; row++) {
for (var col = 0; col < self.size; col++) {
if (self.tiles[row][col].value === 0) {
emptyCells.push({
row: row,
col: col
});
}
}
}
if (emptyCells.length > 0) {
var randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
var value = Math.random() < 0.9 ? 2 : 4;
self.tiles[randomCell.row][randomCell.col].setValue(value);
}
};
self.move = function (direction) {
var boardStateBeforeMove = [];
for (var r = 0; r < self.size; r++) {
boardStateBeforeMove[r] = [];
for (var c = 0; c < self.size; c++) {
boardStateBeforeMove[r][c] = self.tiles[r][c].value;
}
}
var scoreBeforeMove = score;
var goldBeforeMove = gold;
var moved = false;
var merged = [];
for (var i = 0; i < self.size; i++) {
merged[i] = [];
for (var j = 0; j < self.size; j++) {
merged[i][j] = false;
}
}
if (direction === 'left') {
for (var row = 0; row < self.size; row++) {
for (var col = 1; col < self.size; col++) {
if (self.tiles[row][col].value !== 0) {
var targetCol = col;
while (targetCol > 0 && self.tiles[row][targetCol - 1].value === 0) {
targetCol--;
}
if (targetCol > 0 && self.tiles[row][targetCol - 1].value === self.tiles[row][col].value && !merged[row][targetCol - 1]) {
self.tiles[row][targetCol - 1].setValue(self.tiles[row][targetCol - 1].value * 2);
self.tiles[row][col].setValue(0);
merged[row][targetCol - 1] = true;
moved = true;
self.onMerge(self.tiles[row][targetCol - 1].value);
} else if (targetCol !== col) {
self.tiles[row][targetCol].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
} else if (direction === 'right') {
for (var row = 0; row < self.size; row++) {
for (var col = self.size - 2; col >= 0; col--) {
if (self.tiles[row][col].value !== 0) {
var targetCol = col;
while (targetCol < self.size - 1 && self.tiles[row][targetCol + 1].value === 0) {
targetCol++;
}
if (targetCol < self.size - 1 && self.tiles[row][targetCol + 1].value === self.tiles[row][col].value && !merged[row][targetCol + 1]) {
self.tiles[row][targetCol + 1].setValue(self.tiles[row][targetCol + 1].value * 2);
self.tiles[row][col].setValue(0);
merged[row][targetCol + 1] = true;
moved = true;
self.onMerge(self.tiles[row][targetCol + 1].value);
} else if (targetCol !== col) {
self.tiles[row][targetCol].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
} else if (direction === 'up') {
for (var col = 0; col < self.size; col++) {
for (var row = 1; row < self.size; row++) {
if (self.tiles[row][col].value !== 0) {
var targetRow = row;
while (targetRow > 0 && self.tiles[targetRow - 1][col].value === 0) {
targetRow--;
}
if (targetRow > 0 && self.tiles[targetRow - 1][col].value === self.tiles[row][col].value && !merged[targetRow - 1][col]) {
self.tiles[targetRow - 1][col].setValue(self.tiles[targetRow - 1][col].value * 2);
self.tiles[row][col].setValue(0);
merged[targetRow - 1][col] = true;
moved = true;
self.onMerge(self.tiles[targetRow - 1][col].value);
} else if (targetRow !== row) {
self.tiles[targetRow][col].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
} else if (direction === 'down') {
for (var col = 0; col < self.size; col++) {
for (var row = self.size - 2; row >= 0; row--) {
if (self.tiles[row][col].value !== 0) {
var targetRow = row;
while (targetRow < self.size - 1 && self.tiles[targetRow + 1][col].value === 0) {
targetRow++;
}
if (targetRow < self.size - 1 && self.tiles[targetRow + 1][col].value === self.tiles[row][col].value && !merged[targetRow + 1][col]) {
self.tiles[targetRow + 1][col].setValue(self.tiles[targetRow + 1][col].value * 2);
self.tiles[row][col].setValue(0);
merged[targetRow + 1][col] = true;
moved = true;
self.onMerge(self.tiles[targetRow + 1][col].value);
} else if (targetRow !== row) {
self.tiles[targetRow][col].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
}
if (moved) {
lastBoardState = boardStateBeforeMove;
lastScore = scoreBeforeMove;
lastGold = goldBeforeMove;
undoAvailable = true;
if (undoButton) {
undoButton.alpha = 1.0;
}
self.addRandomTile();
LK.getSound('merge').play();
}
return moved;
};
self.onMerge = function (value) {
// Override this in game code
};
self.init();
return self;
});
var RewardPopup = Container.expand(function (value, goldReward, playerName) {
var self = Container.call(this);
self.init = function () {
// Background
self.bg = self.attachAsset('popup_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.bg.alpha = 0.8;
// Title
var messages = {
128: 'Great start, ' + playerName + '!',
256: 'You\'re on fire, ' + playerName + '!',
512: 'Amazing progress, ' + playerName + '!',
1024: 'Outstanding work, ' + playerName + '!',
2048: 'Incredible achievement, ' + playerName + '!'
};
self.titleText = new Text2(messages[value] || 'Well done!', {
size: 60,
fill: '#ffffff'
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -80;
self.addChild(self.titleText);
// Achievement text
self.achievementText = new Text2('Reached ' + value + '!', {
size: 80,
fill: '#ffd700'
});
self.achievementText.anchor.set(0.5, 0.5);
self.achievementText.y = 0;
self.addChild(self.achievementText);
// Gold reward
self.goldText = new Text2('+' + goldReward + ' Gold Coins!', {
size: 50,
fill: '#ffd700'
});
self.goldText.anchor.set(0.5, 0.5);
self.goldText.y = 80;
self.addChild(self.goldText);
// Gold coin icon
self.goldCoin = self.attachAsset('gold_coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.goldCoin.x = -100;
self.goldCoin.y = 80;
};
self.init();
return self;
});
var SetupScreen = Container.expand(function () {
var self = Container.call(this);
self.selectedSize = 4;
self.init = function () {
// Title
self.titleText = new Text2('2048 Gold Rush', {
size: 120,
fill: '#776e65'
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.x = 1024;
self.titleText.y = 400;
self.addChild(self.titleText);
// Grid size instruction
self.sizeInstruction = new Text2('Choose grid size:', {
size: 60,
fill: '#776e65'
});
self.sizeInstruction.anchor.set(0.5, 0.5);
self.sizeInstruction.x = 1024;
self.sizeInstruction.y = 700;
self.addChild(self.sizeInstruction);
// 4x4 button
self.button4x4 = self.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.button4x4.x = 800;
self.button4x4.y = 850;
self.button4x4Text = new Text2('4x4', {
size: 50,
fill: '#f9f6f2'
});
self.button4x4Text.anchor.set(0.5, 0.5);
self.button4x4Text.x = 800;
self.button4x4Text.y = 850;
self.addChild(self.button4x4Text);
// 5x5 button
self.button5x5 = self.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.button5x5.x = 1248;
self.button5x5.y = 850;
self.button5x5Text = new Text2('5x5', {
size: 50,
fill: '#f9f6f2'
});
self.button5x5Text.anchor.set(0.5, 0.5);
self.button5x5Text.x = 1248;
self.button5x5Text.y = 850;
self.addChild(self.button5x5Text);
// Start button
self.startButton = self.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.startButton.x = 1024;
self.startButton.y = 1050;
self.startButtonText = new Text2('Start Game', {
size: 50,
fill: '#f9f6f2'
});
self.startButtonText.anchor.set(0.5, 0.5);
self.startButtonText.x = 1024;
self.startButtonText.y = 1050;
self.addChild(self.startButtonText);
self.updateSelection();
};
self.updateSelection = function () {
self.button4x4.alpha = self.selectedSize === 4 ? 1.0 : 0.6;
self.button5x5.alpha = self.selectedSize === 5 ? 1.0 : 0.6;
};
self.down = function (x, y, obj) {
var localPos;
if (obj && obj.parent && obj.parent.toGlobal) {
localPos = self.toLocal(obj.parent.toGlobal(obj.position));
} else {
localPos = {
x: x,
y: y
};
}
if (Math.abs(localPos.x - 800) < 150 && Math.abs(localPos.y - 850) < 40) {
self.selectedSize = 4;
self.updateSelection();
} else if (Math.abs(localPos.x - 1248) < 150 && Math.abs(localPos.y - 850) < 40) {
self.selectedSize = 5;
self.updateSelection();
} else if (Math.abs(localPos.x - 1024) < 150 && Math.abs(localPos.y - 1050) < 40) {
self.onStartGame();
}
};
self.onStartGame = function () {
// Override this in game code
};
self.init();
return self;
});
var Tile = Container.expand(function (value) {
var self = Container.call(this);
self.value = value || 0;
self.createGraphics = function () {
if (self.graphics) {
self.removeChild(self.graphics);
}
var assetName = self.value === 0 ? 'tile_empty' : 'tile_' + self.value;
self.graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
if (self.value > 0) {
self.text = new Text2(self.value.toString(), {
size: self.value >= 1000 ? 50 : 60,
fill: self.value <= 4 ? "#776e65" : "#f9f6f2"
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
}
};
self.setValue = function (newValue) {
self.value = newValue;
self.createGraphics();
};
self.createGraphics();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfaf8ef
});
/****
* Game Code
****/
var gameState = 'setup'; // setup, playing
var playerName = 'Player';
var gridSize = 4;
var board = null;
var setupScreen = null;
var score = 0;
var gold = 0;
var achievedMilestones = {};
var currentPopup = null;
var popupTimer = null;
// Undo and Swap Feature Variables
var lastBoardState = null;
var lastScore = 0;
var lastGold = 0;
var undoAvailable = false;
var undoButton = null;
var playerNameText = null;
var swapModeActive = false;
var swapAbilityUnlocked = false;
var swapCharges = 0;
var firstSelectedTile = null;
var swapButton = null;
var swapButtonText = null;
// Swipe detection
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeActive = false;
var minSwipeDistance = 100;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: '#776e65'
});
scoreText.anchor.set(1, 0);
scoreText.x = -20;
LK.gui.topRight.addChild(scoreText);
var goldText = new Text2('Gold: 0', {
size: 60,
fill: '#ffd700'
});
goldText.anchor.set(1, 0);
goldText.y = 80;
LK.gui.topRight.addChild(goldText);
function updateScore(points) {
score += points;
LK.setScore(score);
scoreText.setText('Score: ' + score);
}
function updateGold(goldPoints) {
gold += goldPoints;
goldText.setText('Gold: ' + gold);
if (!swapAbilityUnlocked && gold >= 50) {
swapAbilityUnlocked = true;
swapCharges = 5;
if (swapButton) {
swapButton.visible = true;
updateSwapButtonText();
}
}
}
function handleUndo() {
if (!undoAvailable || !lastBoardState) return;
for (var row = 0; row < board.size; row++) {
for (var col = 0; col < board.size; col++) {
board.tiles[row][col].setValue(lastBoardState[row][col]);
}
}
score = lastScore;
LK.setScore(score);
scoreText.setText('Score: ' + score);
gold = lastGold;
goldText.setText('Gold: ' + gold);
undoAvailable = false;
lastBoardState = null;
undoButton.alpha = 0.5;
}
function updateSwapButtonText() {
if (swapAbilityUnlocked) {
swapButtonText.setText('Swap (' + swapCharges + ')');
}
}
function handleSwapButton() {
if (!swapAbilityUnlocked || swapCharges <= 0) return;
swapModeActive = !swapModeActive;
if (swapModeActive) {
swapButton.alpha = 1.0;
} else {
swapButton.alpha = 0.8;
if (firstSelectedTile) {
firstSelectedTile.scale.set(1);
firstSelectedTile = null;
}
}
}
function handleTileSelection(gameX, gameY) {
var boardPos = board.toLocal({
x: gameX,
y: gameY
});
var col = Math.floor(boardPos.x / board.cellSize);
var row = Math.floor(boardPos.y / board.cellSize);
if (row >= 0 && row < board.size && col >= 0 && col < board.size) {
var clickedTile = board.tiles[row][col];
if (clickedTile.value === 0) return;
if (!firstSelectedTile) {
firstSelectedTile = clickedTile;
firstSelectedTile.scale.set(1.1);
} else {
if (firstSelectedTile === clickedTile) {
firstSelectedTile.scale.set(1);
firstSelectedTile = null;
return;
}
var val1 = firstSelectedTile.value;
var val2 = clickedTile.value;
firstSelectedTile.setValue(val2);
clickedTile.setValue(val1);
firstSelectedTile.scale.set(1);
swapCharges--;
updateSwapButtonText();
swapModeActive = false;
firstSelectedTile = null;
swapButton.alpha = 0.8;
if (swapCharges <= 0) {
swapButton.visible = false;
}
}
}
}
function checkMilestone(value) {
var goldRewards = {
128: 2,
256: 4,
512: 8,
1024: 16,
2048: 32
};
if (goldRewards[value] && !achievedMilestones[value]) {
achievedMilestones[value] = true;
updateGold(goldRewards[value]);
showRewardPopup(value, goldRewards[value]);
LK.getSound('gold').play();
}
}
function showRewardPopup(value, goldReward) {
if (currentPopup) {
game.removeChild(currentPopup);
}
currentPopup = new RewardPopup(value, goldReward, playerName);
currentPopup.x = 1024;
currentPopup.y = 1366;
game.addChild(currentPopup);
if (popupTimer) {
LK.clearTimeout(popupTimer);
}
popupTimer = LK.setTimeout(function () {
if (currentPopup) {
game.removeChild(currentPopup);
currentPopup = null;
}
}, 3000);
}
function startGame() {
gameState = 'playing';
if (setupScreen) {
game.removeChild(setupScreen);
setupScreen = null;
}
board = new GameBoard(gridSize);
var boardContainerWidth = gridSize * 200;
board.x = (2048 - boardContainerWidth) / 2;
board.y = (2732 - boardContainerWidth) / 2;
board.onMerge = function (value) {
updateScore(value);
checkMilestone(value);
};
game.addChild(board);
playerNameText = new Text2(playerName, {
size: 70,
fill: '#776e65'
});
playerNameText.anchor.set(0.5, 0);
playerNameText.y = 20;
LK.gui.top.addChild(playerNameText);
undoButton = new Container();
var undoBg = undoButton.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
var undoText = new Text2('Undo', {
size: 50,
fill: '#f9f6f2'
});
undoText.anchor.set(0.5, 0.5);
undoButton.addChild(undoText);
undoButton.x = -200;
undoButton.alpha = 0.5;
undoButton.down = handleUndo;
LK.gui.bottom.addChild(undoButton);
swapButton = new Container();
var swapBg = swapButton.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
swapButtonText = new Text2('Swap', {
size: 50,
fill: '#f9f6f2'
});
swapButtonText.anchor.set(0.5, 0.5);
swapButton.addChild(swapButtonText);
swapButton.x = 200;
swapButton.visible = false;
swapButton.down = handleSwapButton;
LK.gui.bottom.addChild(swapButton);
}
function generateRandomName() {
var adjectives = ['Swift', 'Golden', 'Clever', 'Lucky', 'Mighty', 'Wise', 'Brave', 'Happy', 'Quick', 'Silent'];
var nouns = ['Fox', 'Lion', 'Puma', 'Tiger', 'Eagle', 'Hawk', 'Wolf', 'Bear', 'Shark', 'Dragon'];
var adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
var noun = nouns[Math.floor(Math.random() * nouns.length)];
return adjective + noun + Math.floor(Math.random() * 100);
}
function initSetup() {
setupScreen = new SetupScreen();
setupScreen.onStartGame = function () {
playerName = generateRandomName();
gridSize = setupScreen.selectedSize;
startGame();
};
game.addChild(setupScreen);
}
game.down = function (x, y, obj) {
if (gameState === 'playing') {
if (swapModeActive) {
handleTileSelection(x, y);
return;
}
swipeStartX = x;
swipeStartY = y;
isSwipeActive = true;
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing' && isSwipeActive) {
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance >= minSwipeDistance) {
var direction = null;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
direction = deltaX > 0 ? 'right' : 'left';
} else {
direction = deltaY > 0 ? 'down' : 'up';
}
if (direction && board) {
board.move(direction);
}
}
isSwipeActive = false;
}
};
// Initialize setup screen
initSetup(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var GameBoard = Container.expand(function (size) {
var self = Container.call(this);
self.size = size || 4;
self.tiles = [];
self.cellSize = 200;
self.init = function () {
// Create background grid
for (var row = 0; row < self.size; row++) {
for (var col = 0; col < self.size; col++) {
var cellBg = self.attachAsset('grid_bg', {
anchorX: 0.5,
anchorY: 0.5
});
cellBg.x = col * self.cellSize;
cellBg.y = row * self.cellSize;
}
}
// Initialize tile array
for (var i = 0; i < self.size; i++) {
self.tiles[i] = [];
for (var j = 0; j < self.size; j++) {
self.tiles[i][j] = new Tile(0);
self.tiles[i][j].x = j * self.cellSize;
self.tiles[i][j].y = i * self.cellSize;
self.addChild(self.tiles[i][j]);
}
}
self.addRandomTile();
self.addRandomTile();
};
self.addRandomTile = function () {
var emptyCells = [];
for (var row = 0; row < self.size; row++) {
for (var col = 0; col < self.size; col++) {
if (self.tiles[row][col].value === 0) {
emptyCells.push({
row: row,
col: col
});
}
}
}
if (emptyCells.length > 0) {
var randomCell = emptyCells[Math.floor(Math.random() * emptyCells.length)];
var value = Math.random() < 0.9 ? 2 : 4;
self.tiles[randomCell.row][randomCell.col].setValue(value);
}
};
self.move = function (direction) {
var boardStateBeforeMove = [];
for (var r = 0; r < self.size; r++) {
boardStateBeforeMove[r] = [];
for (var c = 0; c < self.size; c++) {
boardStateBeforeMove[r][c] = self.tiles[r][c].value;
}
}
var scoreBeforeMove = score;
var goldBeforeMove = gold;
var moved = false;
var merged = [];
for (var i = 0; i < self.size; i++) {
merged[i] = [];
for (var j = 0; j < self.size; j++) {
merged[i][j] = false;
}
}
if (direction === 'left') {
for (var row = 0; row < self.size; row++) {
for (var col = 1; col < self.size; col++) {
if (self.tiles[row][col].value !== 0) {
var targetCol = col;
while (targetCol > 0 && self.tiles[row][targetCol - 1].value === 0) {
targetCol--;
}
if (targetCol > 0 && self.tiles[row][targetCol - 1].value === self.tiles[row][col].value && !merged[row][targetCol - 1]) {
self.tiles[row][targetCol - 1].setValue(self.tiles[row][targetCol - 1].value * 2);
self.tiles[row][col].setValue(0);
merged[row][targetCol - 1] = true;
moved = true;
self.onMerge(self.tiles[row][targetCol - 1].value);
} else if (targetCol !== col) {
self.tiles[row][targetCol].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
} else if (direction === 'right') {
for (var row = 0; row < self.size; row++) {
for (var col = self.size - 2; col >= 0; col--) {
if (self.tiles[row][col].value !== 0) {
var targetCol = col;
while (targetCol < self.size - 1 && self.tiles[row][targetCol + 1].value === 0) {
targetCol++;
}
if (targetCol < self.size - 1 && self.tiles[row][targetCol + 1].value === self.tiles[row][col].value && !merged[row][targetCol + 1]) {
self.tiles[row][targetCol + 1].setValue(self.tiles[row][targetCol + 1].value * 2);
self.tiles[row][col].setValue(0);
merged[row][targetCol + 1] = true;
moved = true;
self.onMerge(self.tiles[row][targetCol + 1].value);
} else if (targetCol !== col) {
self.tiles[row][targetCol].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
} else if (direction === 'up') {
for (var col = 0; col < self.size; col++) {
for (var row = 1; row < self.size; row++) {
if (self.tiles[row][col].value !== 0) {
var targetRow = row;
while (targetRow > 0 && self.tiles[targetRow - 1][col].value === 0) {
targetRow--;
}
if (targetRow > 0 && self.tiles[targetRow - 1][col].value === self.tiles[row][col].value && !merged[targetRow - 1][col]) {
self.tiles[targetRow - 1][col].setValue(self.tiles[targetRow - 1][col].value * 2);
self.tiles[row][col].setValue(0);
merged[targetRow - 1][col] = true;
moved = true;
self.onMerge(self.tiles[targetRow - 1][col].value);
} else if (targetRow !== row) {
self.tiles[targetRow][col].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
} else if (direction === 'down') {
for (var col = 0; col < self.size; col++) {
for (var row = self.size - 2; row >= 0; row--) {
if (self.tiles[row][col].value !== 0) {
var targetRow = row;
while (targetRow < self.size - 1 && self.tiles[targetRow + 1][col].value === 0) {
targetRow++;
}
if (targetRow < self.size - 1 && self.tiles[targetRow + 1][col].value === self.tiles[row][col].value && !merged[targetRow + 1][col]) {
self.tiles[targetRow + 1][col].setValue(self.tiles[targetRow + 1][col].value * 2);
self.tiles[row][col].setValue(0);
merged[targetRow + 1][col] = true;
moved = true;
self.onMerge(self.tiles[targetRow + 1][col].value);
} else if (targetRow !== row) {
self.tiles[targetRow][col].setValue(self.tiles[row][col].value);
self.tiles[row][col].setValue(0);
moved = true;
}
}
}
}
}
if (moved) {
lastBoardState = boardStateBeforeMove;
lastScore = scoreBeforeMove;
lastGold = goldBeforeMove;
undoAvailable = true;
if (undoButton) {
undoButton.alpha = 1.0;
}
self.addRandomTile();
LK.getSound('merge').play();
}
return moved;
};
self.onMerge = function (value) {
// Override this in game code
};
self.init();
return self;
});
var RewardPopup = Container.expand(function (value, goldReward, playerName) {
var self = Container.call(this);
self.init = function () {
// Background
self.bg = self.attachAsset('popup_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.bg.alpha = 0.8;
// Title
var messages = {
128: 'Great start, ' + playerName + '!',
256: 'You\'re on fire, ' + playerName + '!',
512: 'Amazing progress, ' + playerName + '!',
1024: 'Outstanding work, ' + playerName + '!',
2048: 'Incredible achievement, ' + playerName + '!'
};
self.titleText = new Text2(messages[value] || 'Well done!', {
size: 60,
fill: '#ffffff'
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.y = -80;
self.addChild(self.titleText);
// Achievement text
self.achievementText = new Text2('Reached ' + value + '!', {
size: 80,
fill: '#ffd700'
});
self.achievementText.anchor.set(0.5, 0.5);
self.achievementText.y = 0;
self.addChild(self.achievementText);
// Gold reward
self.goldText = new Text2('+' + goldReward + ' Gold Coins!', {
size: 50,
fill: '#ffd700'
});
self.goldText.anchor.set(0.5, 0.5);
self.goldText.y = 80;
self.addChild(self.goldText);
// Gold coin icon
self.goldCoin = self.attachAsset('gold_coin', {
anchorX: 0.5,
anchorY: 0.5
});
self.goldCoin.x = -100;
self.goldCoin.y = 80;
};
self.init();
return self;
});
var SetupScreen = Container.expand(function () {
var self = Container.call(this);
self.selectedSize = 4;
self.init = function () {
// Title
self.titleText = new Text2('2048 Gold Rush', {
size: 120,
fill: '#776e65'
});
self.titleText.anchor.set(0.5, 0.5);
self.titleText.x = 1024;
self.titleText.y = 400;
self.addChild(self.titleText);
// Grid size instruction
self.sizeInstruction = new Text2('Choose grid size:', {
size: 60,
fill: '#776e65'
});
self.sizeInstruction.anchor.set(0.5, 0.5);
self.sizeInstruction.x = 1024;
self.sizeInstruction.y = 700;
self.addChild(self.sizeInstruction);
// 4x4 button
self.button4x4 = self.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.button4x4.x = 800;
self.button4x4.y = 850;
self.button4x4Text = new Text2('4x4', {
size: 50,
fill: '#f9f6f2'
});
self.button4x4Text.anchor.set(0.5, 0.5);
self.button4x4Text.x = 800;
self.button4x4Text.y = 850;
self.addChild(self.button4x4Text);
// 5x5 button
self.button5x5 = self.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.button5x5.x = 1248;
self.button5x5.y = 850;
self.button5x5Text = new Text2('5x5', {
size: 50,
fill: '#f9f6f2'
});
self.button5x5Text.anchor.set(0.5, 0.5);
self.button5x5Text.x = 1248;
self.button5x5Text.y = 850;
self.addChild(self.button5x5Text);
// Start button
self.startButton = self.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
self.startButton.x = 1024;
self.startButton.y = 1050;
self.startButtonText = new Text2('Start Game', {
size: 50,
fill: '#f9f6f2'
});
self.startButtonText.anchor.set(0.5, 0.5);
self.startButtonText.x = 1024;
self.startButtonText.y = 1050;
self.addChild(self.startButtonText);
self.updateSelection();
};
self.updateSelection = function () {
self.button4x4.alpha = self.selectedSize === 4 ? 1.0 : 0.6;
self.button5x5.alpha = self.selectedSize === 5 ? 1.0 : 0.6;
};
self.down = function (x, y, obj) {
var localPos;
if (obj && obj.parent && obj.parent.toGlobal) {
localPos = self.toLocal(obj.parent.toGlobal(obj.position));
} else {
localPos = {
x: x,
y: y
};
}
if (Math.abs(localPos.x - 800) < 150 && Math.abs(localPos.y - 850) < 40) {
self.selectedSize = 4;
self.updateSelection();
} else if (Math.abs(localPos.x - 1248) < 150 && Math.abs(localPos.y - 850) < 40) {
self.selectedSize = 5;
self.updateSelection();
} else if (Math.abs(localPos.x - 1024) < 150 && Math.abs(localPos.y - 1050) < 40) {
self.onStartGame();
}
};
self.onStartGame = function () {
// Override this in game code
};
self.init();
return self;
});
var Tile = Container.expand(function (value) {
var self = Container.call(this);
self.value = value || 0;
self.createGraphics = function () {
if (self.graphics) {
self.removeChild(self.graphics);
}
var assetName = self.value === 0 ? 'tile_empty' : 'tile_' + self.value;
self.graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
if (self.value > 0) {
self.text = new Text2(self.value.toString(), {
size: self.value >= 1000 ? 50 : 60,
fill: self.value <= 4 ? "#776e65" : "#f9f6f2"
});
self.text.anchor.set(0.5, 0.5);
self.addChild(self.text);
}
};
self.setValue = function (newValue) {
self.value = newValue;
self.createGraphics();
};
self.createGraphics();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0xfaf8ef
});
/****
* Game Code
****/
var gameState = 'setup'; // setup, playing
var playerName = 'Player';
var gridSize = 4;
var board = null;
var setupScreen = null;
var score = 0;
var gold = 0;
var achievedMilestones = {};
var currentPopup = null;
var popupTimer = null;
// Undo and Swap Feature Variables
var lastBoardState = null;
var lastScore = 0;
var lastGold = 0;
var undoAvailable = false;
var undoButton = null;
var playerNameText = null;
var swapModeActive = false;
var swapAbilityUnlocked = false;
var swapCharges = 0;
var firstSelectedTile = null;
var swapButton = null;
var swapButtonText = null;
// Swipe detection
var swipeStartX = 0;
var swipeStartY = 0;
var isSwipeActive = false;
var minSwipeDistance = 100;
// UI Elements
var scoreText = new Text2('Score: 0', {
size: 60,
fill: '#776e65'
});
scoreText.anchor.set(1, 0);
scoreText.x = -20;
LK.gui.topRight.addChild(scoreText);
var goldText = new Text2('Gold: 0', {
size: 60,
fill: '#ffd700'
});
goldText.anchor.set(1, 0);
goldText.y = 80;
LK.gui.topRight.addChild(goldText);
function updateScore(points) {
score += points;
LK.setScore(score);
scoreText.setText('Score: ' + score);
}
function updateGold(goldPoints) {
gold += goldPoints;
goldText.setText('Gold: ' + gold);
if (!swapAbilityUnlocked && gold >= 50) {
swapAbilityUnlocked = true;
swapCharges = 5;
if (swapButton) {
swapButton.visible = true;
updateSwapButtonText();
}
}
}
function handleUndo() {
if (!undoAvailable || !lastBoardState) return;
for (var row = 0; row < board.size; row++) {
for (var col = 0; col < board.size; col++) {
board.tiles[row][col].setValue(lastBoardState[row][col]);
}
}
score = lastScore;
LK.setScore(score);
scoreText.setText('Score: ' + score);
gold = lastGold;
goldText.setText('Gold: ' + gold);
undoAvailable = false;
lastBoardState = null;
undoButton.alpha = 0.5;
}
function updateSwapButtonText() {
if (swapAbilityUnlocked) {
swapButtonText.setText('Swap (' + swapCharges + ')');
}
}
function handleSwapButton() {
if (!swapAbilityUnlocked || swapCharges <= 0) return;
swapModeActive = !swapModeActive;
if (swapModeActive) {
swapButton.alpha = 1.0;
} else {
swapButton.alpha = 0.8;
if (firstSelectedTile) {
firstSelectedTile.scale.set(1);
firstSelectedTile = null;
}
}
}
function handleTileSelection(gameX, gameY) {
var boardPos = board.toLocal({
x: gameX,
y: gameY
});
var col = Math.floor(boardPos.x / board.cellSize);
var row = Math.floor(boardPos.y / board.cellSize);
if (row >= 0 && row < board.size && col >= 0 && col < board.size) {
var clickedTile = board.tiles[row][col];
if (clickedTile.value === 0) return;
if (!firstSelectedTile) {
firstSelectedTile = clickedTile;
firstSelectedTile.scale.set(1.1);
} else {
if (firstSelectedTile === clickedTile) {
firstSelectedTile.scale.set(1);
firstSelectedTile = null;
return;
}
var val1 = firstSelectedTile.value;
var val2 = clickedTile.value;
firstSelectedTile.setValue(val2);
clickedTile.setValue(val1);
firstSelectedTile.scale.set(1);
swapCharges--;
updateSwapButtonText();
swapModeActive = false;
firstSelectedTile = null;
swapButton.alpha = 0.8;
if (swapCharges <= 0) {
swapButton.visible = false;
}
}
}
}
function checkMilestone(value) {
var goldRewards = {
128: 2,
256: 4,
512: 8,
1024: 16,
2048: 32
};
if (goldRewards[value] && !achievedMilestones[value]) {
achievedMilestones[value] = true;
updateGold(goldRewards[value]);
showRewardPopup(value, goldRewards[value]);
LK.getSound('gold').play();
}
}
function showRewardPopup(value, goldReward) {
if (currentPopup) {
game.removeChild(currentPopup);
}
currentPopup = new RewardPopup(value, goldReward, playerName);
currentPopup.x = 1024;
currentPopup.y = 1366;
game.addChild(currentPopup);
if (popupTimer) {
LK.clearTimeout(popupTimer);
}
popupTimer = LK.setTimeout(function () {
if (currentPopup) {
game.removeChild(currentPopup);
currentPopup = null;
}
}, 3000);
}
function startGame() {
gameState = 'playing';
if (setupScreen) {
game.removeChild(setupScreen);
setupScreen = null;
}
board = new GameBoard(gridSize);
var boardContainerWidth = gridSize * 200;
board.x = (2048 - boardContainerWidth) / 2;
board.y = (2732 - boardContainerWidth) / 2;
board.onMerge = function (value) {
updateScore(value);
checkMilestone(value);
};
game.addChild(board);
playerNameText = new Text2(playerName, {
size: 70,
fill: '#776e65'
});
playerNameText.anchor.set(0.5, 0);
playerNameText.y = 20;
LK.gui.top.addChild(playerNameText);
undoButton = new Container();
var undoBg = undoButton.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
var undoText = new Text2('Undo', {
size: 50,
fill: '#f9f6f2'
});
undoText.anchor.set(0.5, 0.5);
undoButton.addChild(undoText);
undoButton.x = -200;
undoButton.alpha = 0.5;
undoButton.down = handleUndo;
LK.gui.bottom.addChild(undoButton);
swapButton = new Container();
var swapBg = swapButton.attachAsset('button_bg', {
anchorX: 0.5,
anchorY: 0.5
});
swapButtonText = new Text2('Swap', {
size: 50,
fill: '#f9f6f2'
});
swapButtonText.anchor.set(0.5, 0.5);
swapButton.addChild(swapButtonText);
swapButton.x = 200;
swapButton.visible = false;
swapButton.down = handleSwapButton;
LK.gui.bottom.addChild(swapButton);
}
function generateRandomName() {
var adjectives = ['Swift', 'Golden', 'Clever', 'Lucky', 'Mighty', 'Wise', 'Brave', 'Happy', 'Quick', 'Silent'];
var nouns = ['Fox', 'Lion', 'Puma', 'Tiger', 'Eagle', 'Hawk', 'Wolf', 'Bear', 'Shark', 'Dragon'];
var adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
var noun = nouns[Math.floor(Math.random() * nouns.length)];
return adjective + noun + Math.floor(Math.random() * 100);
}
function initSetup() {
setupScreen = new SetupScreen();
setupScreen.onStartGame = function () {
playerName = generateRandomName();
gridSize = setupScreen.selectedSize;
startGame();
};
game.addChild(setupScreen);
}
game.down = function (x, y, obj) {
if (gameState === 'playing') {
if (swapModeActive) {
handleTileSelection(x, y);
return;
}
swipeStartX = x;
swipeStartY = y;
isSwipeActive = true;
}
};
game.up = function (x, y, obj) {
if (gameState === 'playing' && isSwipeActive) {
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance >= minSwipeDistance) {
var direction = null;
if (Math.abs(deltaX) > Math.abs(deltaY)) {
direction = deltaX > 0 ? 'right' : 'left';
} else {
direction = deltaY > 0 ? 'down' : 'up';
}
if (direction && board) {
board.move(direction);
}
}
isSwipeActive = false;
}
};
// Initialize setup screen
initSetup();