/**** * Classes ****/ var Tile = Container.expand(function (value) { var self = Container.call(this); self.alpha = 0; var fadeIn = function fadeIn() { if (self.alpha < 1) { self.alpha = Math.min(self.alpha + 0.24, 1); self.scale.set(self.alpha); LK.setTimeout(fadeIn, 16.67); } else { self.alpha = 1; self.scale.set(1); } }; fadeIn(); self.value = value || 2; var tileGraphics = self.attachAsset('tile', { anchorX: 0.5, anchorY: 0.5 }); var hsvToRgb = function hsvToRgb(h, s, v) { var r, g, b; var i = Math.floor(h * 6); var f = h * 6 - i; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); switch (i % 6) { case 0: r = v, g = t, b = p; break; case 1: r = q, g = v, b = p; break; case 2: r = p, g = v, b = t; break; case 3: r = p, g = q, b = v; break; case 4: r = t, g = p, b = v; break; case 5: r = v, g = p, b = q; break; } return (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255); }; self.setTint = function () { var hue = (Math.log2(self.value) + 6) % 20 / 20; tileGraphics.tint = hsvToRgb(hue, 0.3, 1); }; self.setTint(); var tileLabel = new Text2(self.value.toString(), { size: 300, fill: '#332d28', font: 'Sans-Serif', weight: '800', strokeThickness: 0 }); tileLabel.anchor.set(0.5, 0.5); tileLabel.x = 0; tileLabel.y = -40; self.addChild(tileLabel); self.setValue = function (value) { self.newValue = value; }; self.updateToRealValue = function () { if (self.newValue) { self.value = self.newValue; tileLabel.setText(self.value.toString()); var textScale = Math.min(1, 350 / (tileLabel.width / tileLabel.scale.x)); tileLabel.scale.set(textScale); self.setTint(); self.newValue = null; self.scale.set(1.2); var scaleDown = function scaleDown() { if (self.scale.x > 1) { self.scale.x -= 0.02; self.scale.y -= 0.02; LK.setTimeout(scaleDown, 16.67); } else { self.scale.set(1); } }; scaleDown(); } }; self.targetX = 0; self.targetY = 0; self.isMoving = false; self.merged = false; self.setPosition = function (x, y, instant) { self.targetX = x * 500 + 250; self.targetY = y * 500 + 250; if (instant) { self.x = self.targetX; self.y = self.targetY; } }; self.move = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 150) { self.isMoving = true; self.x += dx / distance * 150; self.y += dy / distance * 150; return false; } self.isMoving = false; self.x = self.targetX; self.y = self.targetY; return true; }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ game.checkPossibleMoves = function () { for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (squares[i][j] === null) { return true; } if (i < gridSize - 1 && squares[i][j] !== null && squares[i + 1][j] !== null && squares[i][j].value === squares[i + 1][j].value) { return true; } if (j < gridSize - 1 && squares[i][j] !== null && squares[i][j + 1] !== null && squares[i][j].value === squares[i][j + 1].value) { return true; } } } return false; }; var scoreTxt = new Text2('2', { size: 220, fill: '#000000', font: 'Impact', strokeThickness: 0 }); scoreTxt.anchor.set(.5, 0); LK.gui.topCenter.addChild(scoreTxt); var tutorialTxt = new Text2('Swipe to merge & merge', { size: 120, fill: '#000000', font: 'Impact', strokeThickness: 0 }); tutorialTxt.anchor.set(.5, 1); LK.gui.bottom.addChild(tutorialTxt); tutorialTxt.y -= 30; var toBeRemoved = []; game.addRandomTile = function () { var emptyPositions = []; for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (squares[i][j] === null) { emptyPositions.push({ x: i, y: j }); } } } if (emptyPositions.length > 0) { var randomPosition = emptyPositions[Math.floor(Math.random() * emptyPositions.length)]; var square = new Tile(Math.random() < 0.5 ? 2 : 4); square.setPosition(randomPosition.x, randomPosition.y, true); squares[randomPosition.x][randomPosition.y] = square; gridContainer.addChild(square); } }; game.mergeTiles = function (x1, y1, x2, y2) { if (squares[x1][y1] !== null && squares[x2][y2] !== null && squares[x1][y1].value === squares[x2][y2].value && !squares[x1][y1].merged && !squares[x2][y2].merged) { squares[x2][y2].setValue(squares[x2][y2].value * 2, true); squares[x2][y2].merged = true; squares[x1][y1].targetX = squares[x2][y2].targetX; squares[x1][y1].targetY = squares[x2][y2].targetY; toBeRemoved.push(squares[x1][y1]); squares[x1][y1] = null; gridContainer.removeChild(squares[x2][y2]); gridContainer.addChild(squares[x2][y2]); return true; } return false; }; var gridSize = 4; game.setBackgroundColor(0xD3D3D3); var gridContainer = new Container(); gridContainer.x = 44; gridContainer.y = 400; game.addChild(gridContainer); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { var gridTile = gridContainer.attachAsset('gridTile', { anchorX: 0.5, anchorY: 0.5 }); gridTile.x = i * 500 + 250; gridTile.y = j * 500 + 250; gridTile.alpha = .1; } } var squares = new Array(gridSize).fill().map(function () { return new Array(gridSize).fill(null); }); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { squares[i][j] = null; } } var initialTiles = 2; for (var i = 0; i < initialTiles; i++) { var x, y; do { x = Math.floor(Math.random() * gridSize); y = Math.floor(Math.random() * gridSize); } while (squares[x][y] !== null); var square = new Tile(); square.setPosition(x, y, true); square.alpha = 1; square.scale.set(1); squares[x][y] = square; gridContainer.addChild(square); } var swipeStart = { x: 0, y: 0 }; var swipeEnd = { x: 0, y: 0 }; var boardChanged = false; var winMessageShown = false; game.moveTiles = function (direction) { var dx = (direction === 'right') - (direction === 'left'); var dy = (direction === 'down') - (direction === 'up'); var moved = false; do { moved = false; var iStart = dx > 0 ? gridSize - 1 : 0; var iEnd = dx > 0 ? -1 : gridSize; var iStep = dx > 0 ? -1 : 1; var jStart = dy > 0 ? gridSize - 1 : 0; var jEnd = dy > 0 ? -1 : gridSize; var jStep = dy > 0 ? -1 : 1; for (var i = iStart; i !== iEnd; i += iStep) { for (var j = jStart; j !== jEnd; j += jStep) { var x = i + dx; var y = j + dy; if (x >= 0 && x < gridSize && y >= 0 && y < gridSize && squares[i][j] !== null) { if (squares[x][y] === null) { squares[x][y] = squares[i][j]; squares[i][j] = null; squares[x][y].setPosition(x, y); moved = true; boardChanged = true; } else if (squares[x][y] !== null && squares[i][j] !== null && squares[x][y].value === squares[i][j].value) { moved = game.mergeTiles(i, j, x, y); if (moved) { boardChanged = true; } } } } } } while (moved); for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (squares[i][j] !== null) { squares[i][j].merged = false; } } } }; game.on('down', function (obj) { var anyTileMoving = squares.some(function (row) { return row.some(function (tile) { return tile && tile.isMoving; }); }); if (!anyTileMoving) { var pos = obj.event.getLocalPosition(game); swipeStart = { x: pos.x, y: pos.y }; } }); game.on('up', function (obj) { var pos = obj.event.getLocalPosition(game); swipeEnd = { x: pos.x, y: pos.y }; var dx = swipeEnd.x - swipeStart.x; var dy = swipeEnd.y - swipeStart.y; var threshold = 50; if (Math.abs(dx) > threshold || Math.abs(dy) > threshold) { if (Math.abs(dx) > Math.abs(dy)) { if (dx > 0) { game.moveTiles('right'); } else { game.moveTiles('left'); } } else { if (dy > 0) { game.moveTiles('down'); } else { game.moveTiles('up'); } } if (tutorialTxt) { LK.gui.bottom.removeChild(tutorialTxt); tutorialTxt = null; } } }); LK.on('tick', function () { var allTilesStopped = true; for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (squares[i][j] !== null) { if (!squares[i][j].move()) { allTilesStopped = false; } } } } for (var i = 0; i < toBeRemoved.length; i++) { if (!toBeRemoved[i].move()) { allTilesStopped = false; } else { toBeRemoved[i].destroy(); toBeRemoved.splice(i, 1); i--; } } if (allTilesStopped) { for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (squares[i][j] !== null && squares[i][j].newValue) { squares[i][j].updateToRealValue(); if (squares[i][j].value === 2048 && !winMessageShown) { var winMessage = new Text2('Congratulations\n you win!', { size: 150, fill: '#ffffff', font: 'Sans-Serif', weight: '800', stroke: '#000000', strokeThickness: 25, align: 'center' }); winMessage.anchor.set(0.5, 0.5); LK.gui.center.addChild(winMessage); winMessageShown = true; LK.setTimeout(function () { LK.gui.center.removeChild(winMessage); }, 5000); } } } } if (boardChanged) { game.addRandomTile(); boardChanged = false; var maxTileValue = Math.max.apply(Math, squares.map(function (row) { return Math.max.apply(Math, row.map(function (tile) { return tile ? tile.value : 0; })); })); var newScore = maxTileValue; LK.setScore(newScore); scoreTxt.setText(newScore.toString()); } if (!game.checkPossibleMoves()) { for (var i = 0; i < gridSize; i++) { for (var j = 0; j < gridSize; j++) { if (squares[i][j] !== null) { squares[i][j].alpha = 1; squares[i][j].scale.set(1); } } } LK.showGameOver(); } } });
/****
* Classes
****/
var Tile = Container.expand(function (value) {
var self = Container.call(this);
self.alpha = 0;
var fadeIn = function fadeIn() {
if (self.alpha < 1) {
self.alpha = Math.min(self.alpha + 0.24, 1);
self.scale.set(self.alpha);
LK.setTimeout(fadeIn, 16.67);
} else {
self.alpha = 1;
self.scale.set(1);
}
};
fadeIn();
self.value = value || 2;
var tileGraphics = self.attachAsset('tile', {
anchorX: 0.5,
anchorY: 0.5
});
var hsvToRgb = function hsvToRgb(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0:
r = v, g = t, b = p;
break;
case 1:
r = q, g = v, b = p;
break;
case 2:
r = p, g = v, b = t;
break;
case 3:
r = p, g = q, b = v;
break;
case 4:
r = t, g = p, b = v;
break;
case 5:
r = v, g = p, b = q;
break;
}
return (Math.round(r * 255) << 16) + (Math.round(g * 255) << 8) + Math.round(b * 255);
};
self.setTint = function () {
var hue = (Math.log2(self.value) + 6) % 20 / 20;
tileGraphics.tint = hsvToRgb(hue, 0.3, 1);
};
self.setTint();
var tileLabel = new Text2(self.value.toString(), {
size: 300,
fill: '#332d28',
font: 'Sans-Serif',
weight: '800',
strokeThickness: 0
});
tileLabel.anchor.set(0.5, 0.5);
tileLabel.x = 0;
tileLabel.y = -40;
self.addChild(tileLabel);
self.setValue = function (value) {
self.newValue = value;
};
self.updateToRealValue = function () {
if (self.newValue) {
self.value = self.newValue;
tileLabel.setText(self.value.toString());
var textScale = Math.min(1, 350 / (tileLabel.width / tileLabel.scale.x));
tileLabel.scale.set(textScale);
self.setTint();
self.newValue = null;
self.scale.set(1.2);
var scaleDown = function scaleDown() {
if (self.scale.x > 1) {
self.scale.x -= 0.02;
self.scale.y -= 0.02;
LK.setTimeout(scaleDown, 16.67);
} else {
self.scale.set(1);
}
};
scaleDown();
}
};
self.targetX = 0;
self.targetY = 0;
self.isMoving = false;
self.merged = false;
self.setPosition = function (x, y, instant) {
self.targetX = x * 500 + 250;
self.targetY = y * 500 + 250;
if (instant) {
self.x = self.targetX;
self.y = self.targetY;
}
};
self.move = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 150) {
self.isMoving = true;
self.x += dx / distance * 150;
self.y += dy / distance * 150;
return false;
}
self.isMoving = false;
self.x = self.targetX;
self.y = self.targetY;
return true;
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
game.checkPossibleMoves = function () {
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
if (squares[i][j] === null) {
return true;
}
if (i < gridSize - 1 && squares[i][j] !== null && squares[i + 1][j] !== null && squares[i][j].value === squares[i + 1][j].value) {
return true;
}
if (j < gridSize - 1 && squares[i][j] !== null && squares[i][j + 1] !== null && squares[i][j].value === squares[i][j + 1].value) {
return true;
}
}
}
return false;
};
var scoreTxt = new Text2('2', {
size: 220,
fill: '#000000',
font: 'Impact',
strokeThickness: 0
});
scoreTxt.anchor.set(.5, 0);
LK.gui.topCenter.addChild(scoreTxt);
var tutorialTxt = new Text2('Swipe to merge & merge', {
size: 120,
fill: '#000000',
font: 'Impact',
strokeThickness: 0
});
tutorialTxt.anchor.set(.5, 1);
LK.gui.bottom.addChild(tutorialTxt);
tutorialTxt.y -= 30;
var toBeRemoved = [];
game.addRandomTile = function () {
var emptyPositions = [];
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
if (squares[i][j] === null) {
emptyPositions.push({
x: i,
y: j
});
}
}
}
if (emptyPositions.length > 0) {
var randomPosition = emptyPositions[Math.floor(Math.random() * emptyPositions.length)];
var square = new Tile(Math.random() < 0.5 ? 2 : 4);
square.setPosition(randomPosition.x, randomPosition.y, true);
squares[randomPosition.x][randomPosition.y] = square;
gridContainer.addChild(square);
}
};
game.mergeTiles = function (x1, y1, x2, y2) {
if (squares[x1][y1] !== null && squares[x2][y2] !== null && squares[x1][y1].value === squares[x2][y2].value && !squares[x1][y1].merged && !squares[x2][y2].merged) {
squares[x2][y2].setValue(squares[x2][y2].value * 2, true);
squares[x2][y2].merged = true;
squares[x1][y1].targetX = squares[x2][y2].targetX;
squares[x1][y1].targetY = squares[x2][y2].targetY;
toBeRemoved.push(squares[x1][y1]);
squares[x1][y1] = null;
gridContainer.removeChild(squares[x2][y2]);
gridContainer.addChild(squares[x2][y2]);
return true;
}
return false;
};
var gridSize = 4;
game.setBackgroundColor(0xD3D3D3);
var gridContainer = new Container();
gridContainer.x = 44;
gridContainer.y = 400;
game.addChild(gridContainer);
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
var gridTile = gridContainer.attachAsset('gridTile', {
anchorX: 0.5,
anchorY: 0.5
});
gridTile.x = i * 500 + 250;
gridTile.y = j * 500 + 250;
gridTile.alpha = .1;
}
}
var squares = new Array(gridSize).fill().map(function () {
return new Array(gridSize).fill(null);
});
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
squares[i][j] = null;
}
}
var initialTiles = 2;
for (var i = 0; i < initialTiles; i++) {
var x, y;
do {
x = Math.floor(Math.random() * gridSize);
y = Math.floor(Math.random() * gridSize);
} while (squares[x][y] !== null);
var square = new Tile();
square.setPosition(x, y, true);
square.alpha = 1;
square.scale.set(1);
squares[x][y] = square;
gridContainer.addChild(square);
}
var swipeStart = {
x: 0,
y: 0
};
var swipeEnd = {
x: 0,
y: 0
};
var boardChanged = false;
var winMessageShown = false;
game.moveTiles = function (direction) {
var dx = (direction === 'right') - (direction === 'left');
var dy = (direction === 'down') - (direction === 'up');
var moved = false;
do {
moved = false;
var iStart = dx > 0 ? gridSize - 1 : 0;
var iEnd = dx > 0 ? -1 : gridSize;
var iStep = dx > 0 ? -1 : 1;
var jStart = dy > 0 ? gridSize - 1 : 0;
var jEnd = dy > 0 ? -1 : gridSize;
var jStep = dy > 0 ? -1 : 1;
for (var i = iStart; i !== iEnd; i += iStep) {
for (var j = jStart; j !== jEnd; j += jStep) {
var x = i + dx;
var y = j + dy;
if (x >= 0 && x < gridSize && y >= 0 && y < gridSize && squares[i][j] !== null) {
if (squares[x][y] === null) {
squares[x][y] = squares[i][j];
squares[i][j] = null;
squares[x][y].setPosition(x, y);
moved = true;
boardChanged = true;
} else if (squares[x][y] !== null && squares[i][j] !== null && squares[x][y].value === squares[i][j].value) {
moved = game.mergeTiles(i, j, x, y);
if (moved) {
boardChanged = true;
}
}
}
}
}
} while (moved);
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
if (squares[i][j] !== null) {
squares[i][j].merged = false;
}
}
}
};
game.on('down', function (obj) {
var anyTileMoving = squares.some(function (row) {
return row.some(function (tile) {
return tile && tile.isMoving;
});
});
if (!anyTileMoving) {
var pos = obj.event.getLocalPosition(game);
swipeStart = {
x: pos.x,
y: pos.y
};
}
});
game.on('up', function (obj) {
var pos = obj.event.getLocalPosition(game);
swipeEnd = {
x: pos.x,
y: pos.y
};
var dx = swipeEnd.x - swipeStart.x;
var dy = swipeEnd.y - swipeStart.y;
var threshold = 50;
if (Math.abs(dx) > threshold || Math.abs(dy) > threshold) {
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 0) {
game.moveTiles('right');
} else {
game.moveTiles('left');
}
} else {
if (dy > 0) {
game.moveTiles('down');
} else {
game.moveTiles('up');
}
}
if (tutorialTxt) {
LK.gui.bottom.removeChild(tutorialTxt);
tutorialTxt = null;
}
}
});
LK.on('tick', function () {
var allTilesStopped = true;
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
if (squares[i][j] !== null) {
if (!squares[i][j].move()) {
allTilesStopped = false;
}
}
}
}
for (var i = 0; i < toBeRemoved.length; i++) {
if (!toBeRemoved[i].move()) {
allTilesStopped = false;
} else {
toBeRemoved[i].destroy();
toBeRemoved.splice(i, 1);
i--;
}
}
if (allTilesStopped) {
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
if (squares[i][j] !== null && squares[i][j].newValue) {
squares[i][j].updateToRealValue();
if (squares[i][j].value === 2048 && !winMessageShown) {
var winMessage = new Text2('Congratulations\n you win!', {
size: 150,
fill: '#ffffff',
font: 'Sans-Serif',
weight: '800',
stroke: '#000000',
strokeThickness: 25,
align: 'center'
});
winMessage.anchor.set(0.5, 0.5);
LK.gui.center.addChild(winMessage);
winMessageShown = true;
LK.setTimeout(function () {
LK.gui.center.removeChild(winMessage);
}, 5000);
}
}
}
}
if (boardChanged) {
game.addRandomTile();
boardChanged = false;
var maxTileValue = Math.max.apply(Math, squares.map(function (row) {
return Math.max.apply(Math, row.map(function (tile) {
return tile ? tile.value : 0;
}));
}));
var newScore = maxTileValue;
LK.setScore(newScore);
scoreTxt.setText(newScore.toString());
}
if (!game.checkPossibleMoves()) {
for (var i = 0; i < gridSize; i++) {
for (var j = 0; j < gridSize; j++) {
if (squares[i][j] !== null) {
squares[i][j].alpha = 1;
squares[i][j].scale.set(1);
}
}
}
LK.showGameOver();
}
}
});