/**** * Classes ****/ var Cell = Container.expand(function (type) { var self = Container.call(this); var cellGraphics = self.attachAsset('cell', { anchorX: 0.5, anchorY: 0.5 }); var clockGraphics = self.attachAsset('clock', { anchorX: 0.5, anchorY: 0.5 }); clockGraphics.y = -8; clockGraphics.x = -4; clockGraphics.blendMode = 2; var indicatorAngles = [270, 330, 30, 90, 150, 210]; var indicatorDistance = 100; indicatorAngles.forEach(function (angle) { var radian = angle * (Math.PI / 180); var indicatorX = clockGraphics.x + Math.cos(radian) * indicatorDistance; var indicatorY = clockGraphics.y + Math.sin(radian) * indicatorDistance; var indicator = self.addChild(new ClockIndicator()); indicator.x = indicatorX; indicator.y = indicatorY; indicator.rotation = radian; }); self.targetX = 0; self.targetY = 0; self.targetAlpha = 1; self.isMoving = false; self.totalTypes = 6; self.type = type !== undefined ? type : Math.floor(Math.random() * self.totalTypes); self.realType = self.type; self.currentHue = self.type / self.totalTypes; self.targetHue = self.type / self.totalTypes; self.targetRotation = self.type * (2 * Math.PI / self.totalTypes); var color = hsvToRgb(self.targetHue, 0.25, 1); cellGraphics.tint = color; clockGraphics.rotation = self.targetRotation; self.changeType = function (newType) { self.type = newType % self.totalTypes; self.realType = newType; self.targetHue = self.realType / self.totalTypes; self.targetRotation = self.realType * (2 * Math.PI / self.totalTypes); }; self._move_migrated = function (x, y, instant) { self.targetX = x; self.targetY = y; if (instant) { self.x = x; self.y = y; } else { var steps = 20; self.speedX = (x - self.x) / steps; self.speedY = (y - self.y) / steps; } }; self.tick = function (allNotMoving) { if (allNotMoving) { if (self.currentHue !== self.targetHue) { var hueDifference = self.targetHue - self.currentHue; var hueStep = hueDifference * 0.05; self.currentHue += hueStep; if (Math.abs(hueDifference) < 0.01) { self.currentHue = self.targetHue; } var color = hsvToRgb(self.currentHue, 0.25, 1); cellGraphics.tint = color; } var rotationDifference = self.targetRotation - clockGraphics.rotation; if (Math.abs(rotationDifference) > 0.01) { clockGraphics.rotation += rotationDifference * 0.05; } else { clockGraphics.rotation = self.targetRotation; } } var alphaDifference = self.targetAlpha - self.alpha; if (Math.abs(alphaDifference) > 0.01) { self.alpha += alphaDifference * 0.1; } else { self.alpha = self.targetAlpha; } var acceleration = 1; self.speedX = self.speedX || 0; self.speedY = self.speedY || 0; var threshold = 1; var dx = self.targetX - self.x; var dy = self.targetY - self.y; if (Math.abs(dx) < threshold && Math.abs(dy) < threshold) { self.x = self.targetX; self.y = self.targetY; self.isMoving = false; self.speedX = 0; self.speedY = 0; } else { var nextX = self.x + self.speedX; var nextY = self.y + self.speedY; if (self.speedX > 0 && nextX > self.targetX || self.speedX < 0 && nextX < self.targetX) { nextX = self.targetX; self.speedX = 0; } if (self.speedY > 0 && nextY > self.targetY || self.speedY < 0 && nextY < self.targetY) { nextY = self.targetY; self.speedY = 0; } self.x = nextX; self.y = nextY; self.isMoving = self.x !== self.targetX || self.y !== self.targetY; } }; }); var ClockIndicator = Container.expand(function () { var self = Container.call(this); var indicatorGraphics = self.attachAsset('clockIndicator', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var GridBackgroundCell = Container.expand(function () { var self = Container.call(this); var bgCellGraphics = self.attachAsset('gridCell', { anchorX: 0.5, anchorY: 0.5 }); bgCellGraphics.alpha = 0.5; bgCellGraphics.x += 10; bgCellGraphics.y += 15; self.setAlphaAndTint = function (alpha, tint) { bgCellGraphics.alpha = alpha; bgCellGraphics.tint = tint; }; }); var PointsText = Container.expand(function (points, x, y) { var self = Container.call(this); var text = new Text2('+' + points, { size: 180, fill: '#000000', weight: '800', align: 'center', stroke: '#ffffff', strokeThickness: 12 }); text.anchor.set(.5, .5); text.x = x; text.y = y; self.addChild(text); self.getText = function () { return text; }; self.alpha = 1; self.fadeOutDuration = 30; self.fadeOutStartTime = LK.ticks + 20; self.tick = function () { var elapsedTime = LK.ticks - self.fadeOutStartTime; if (elapsedTime < 0) { return; } if (elapsedTime < self.fadeOutDuration) { self.alpha = 1 - elapsedTime / self.fadeOutDuration; self.y -= 2; } else { self.alpha = 0; self.destroy(); } }; }); var Tile = Container.expand(function (type) { var self = Container.call(this); var tileGraphics = self.attachAsset('tile', { anchorX: 0.5, anchorY: 0.5 }); tileGraphics.alpha = 0; self.targetX = 0; self.targetY = 0; self.isMoving = false; self.totalTypes = 3; self.type = type || Math.floor(Math.random() * self.totalTypes); var hue = self.type / self.totalTypes; var color = hsvToRgb(hue, 0.5, 1); tileGraphics.tint = color; self.cells = []; var cellWidth = 0; var cellHeight = 0; self.structure = []; if (self.type === 0) { self.structure = [[1, 1]]; var cell1 = new Cell(); var cell2 = new Cell(); cellWidth = cell1.width; cellHeight = cell1.height; self.cells.push(cell1); self.cells.push(cell2); } else if (self.type === 1) { self.structure = [[1], [1]]; var cell1 = new Cell(); var cell2 = new Cell(); cellWidth = cell1.width; cellHeight = cell1.height; self.cells.push(cell1); self.cells.push(cell2); } else if (self.type === 2) { self.structure = [[1]]; var cell1 = new Cell(); cellWidth = cell1.width; cellHeight = cell1.height; self.cells.push(cell1); } self.cells.forEach(function (cell, index) { if (self.type === 0) { cell.x = index === 0 ? self.x - cellWidth / 2 : self.x + cellWidth / 2; cell.y = self.y; } else if (self.type === 1) { cell.x = self.x; cell.y = index === 0 ? self.y - cellHeight / 2 : self.y + cellHeight / 2; } self.addChild(cell); }); self._move_migrated = function (x, y, instant) { self.targetX = x; self.targetY = y; if (instant) { self.x = x; self.y = y; } }; self.tick = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 1) { self.x += dx * 0.15; self.y += dy * 0.15; self.isMoving = true; } else { self.x = self.targetX; self.y = self.targetY; self.isMoving = false; } }; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ function hsvToRgb(h, s, v) { var i = Math.floor(h * 6), f = h * 6 - i, p = v * (1 - s), q = v * (1 - f * s), t = v * (1 - (1 - f) * s), mod = i % 6, r = [v, q, p, p, t, v][mod], g = [t, v, v, q, p, p][mod], b = [p, p, t, v, v, q][mod]; return (r * 255 << 16) + (g * 255 << 8) + b * 255; } var effectsArray = []; game.processMergeAndGameOver = function (force) { force = force || false; var isAnyRowMoving = grid.some(function (row) { return row.some(function (cell) { return cell && cell.isMoving; }); }); if (!isAnyRowMoving && !game.mergeMode || force) { grid.forEach(function (row) { row.forEach(function (cell) { if (cell) { var colRow = game.findCellColRow(cell); var connectedNeighbors = game.findConnectedNeighbors(cell); if (connectedNeighbors.length >= 3) { toMerge.push(connectedNeighbors); game.setMergeMode(true); } } }); }); if (game.mergeMode) { grid.forEach(function (row) { row.forEach(function (cell) { if (cell && !toMerge.some(function (mergeGroup) { return mergeGroup.includes(cell); })) { cell.targetAlpha = 0.4; } }); }); game.scoreMultiplier += 1; game.updateScoreMultiplier(game.scoreMultiplier); } else { game.scoreMultiplier = -1; game.updateScoreMultiplier(game.scoreMultiplier); } var isAnyTileMoving = bottomTiles.some(function (tile) { return tile.isMoving; }); isAnyRowMoving = grid.some(function (row) { return row.some(function (cell) { return cell && cell.isMoving; }); }); if (!isAnyTileMoving && !game.canPlaceAnyTile() && !isAnyRowMoving && toDelete.length === 0 && !game.mergeMode) { LK.showGameOver(); } } }; game.addAndHandleCell = function (targetCell) { gridContainer.addChild(targetCell); targetCell.on('down', function () { if (game.mergeMode) { game.mergeConnectedNeighbors(targetCell); } }); }; game.mergeConnectedNeighbors = function (cell) { var connectedNeighbors = game.findConnectedNeighbors(cell); if (connectedNeighbors.length >= 3) { var colRow = game.findCellColRow(cell); var newType = cell.realType + 1; var pointsEarned = connectedNeighbors.length * Math.max(game.scoreMultiplier * 3, 1); var pointsText = new PointsText(pointsEarned, cell.x, cell.y - 300); gridContainer.addChild(pointsText); effectsArray.push(pointsText); game.score += pointsEarned; LK.setScore(game.score); LK.setScore(game.score); scoreTxt.setText(game.score.toString()); connectedNeighbors.forEach(function (neighborCell) { var neighborColRow = game.findCellColRow(neighborCell); if (neighborColRow) { if (neighborCell === cell) { cell.changeType(newType); gridContainer.removeChild(cell); gridContainer.addChild(cell); return; } grid[neighborColRow.col][neighborColRow.row] = null; neighborCell.isMoving = true; toDelete.push(neighborCell); neighborCell._move_migrated(cell.x, cell.y); } }, this); } }; var bottomTilesContainer = new Container(); game.setMergeMode = function (mode) { game.mergeMode = mode; bottomTilesContainer.alpha = mode ? 0.4 : 1; if (!mode && game.mergeModeText) { game.mergeModeText.destroy(); game.mergeModeText = null; } if (mode && !game.mergeModeTextShown) { var mergeModeText = new Text2('Tap a tile to merge\nall tiles into it', { size: 130, fill: '#000000', weight: '800', align: 'center', dropShadow: true, dropShadowColor: '#ffffff', dropShadowBlur: 4, dropShadowAngle: Math.PI / 6, dropShadowDistance: 6 }); mergeModeText.anchor.set(0.5, 1); mergeModeText.y = -75; LK.gui.bottom.addChild(mergeModeText); game.mergeModeText = mergeModeText; game.mergeModeTextShown = true; } }; game.setMergeMode(false); game.score = 0; game.scoreMultiplier = -1; game.setBackgroundColor(0xffffff); var backgroundGraphics = game.attachAsset('background', { anchorX: 0.5, anchorY: 0.5 }); game.addChild(backgroundGraphics); backgroundGraphics.x = 2048 / 2; backgroundGraphics.y = 2732 / 2; backgroundGraphics.alpha = 0.5; var bottomTileBackground = game.attachAsset('bottomTileBackground', { anchorX: 0.5, anchorY: 1 }); game.addChild(bottomTileBackground); bottomTileBackground.x = 2048 / 2; bottomTileBackground.y = 2732; bottomTileBackground.alpha = 0.5; game.findCellColRow = function (cell) { for (var col = 0; col < gridWidth; col++) { for (var row = 0; row < gridHeight; row++) { if (grid[col][row] === cell) { return { col: col, row: row }; } } } return null; }; game.canPlaceAnyTile = function () { for (var i = 0; i < bottomTiles.length; i++) { var tile = bottomTiles[i]; for (var col = 0; col < gridWidth; col++) { for (var row = 0; row < gridHeight; row++) { if (game.canPlaceTile(tile, col, row)) { return true; } } } } return false; }; game.canPlaceTile = function (tile, gridX, gridY) { for (var row = 0; row < tile.structure.length; row++) { for (var col = 0; col < tile.structure[row].length; col++) { if (tile.structure[row][col] === 1) { var targetCol = gridX + col; var targetRow = gridY + row; if (targetCol < 0 || targetCol >= gridWidth || targetRow < 0 || targetRow >= gridHeight) { return false; } if (grid[targetCol][targetRow]) { return false; } } } } return true; }; game.toTest = []; game.getOverlappingCells = function (tile) { var overlappingCells = []; var shouldReturnEmpty = false; tile.cells.forEach(function (cell) { var cellBounds = cell.getBounds(); for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { var bgCell = bgGrid[i][j]; var bgCellBounds = bgCell.getBounds(); if (cellBounds.contains(bgCellBounds.x + bgCellBounds.width / 2, bgCellBounds.y + bgCellBounds.height / 2)) { if (grid[i][j]) { shouldReturnEmpty = true; break; } overlappingCells.push(bgCell); } } if (shouldReturnEmpty) { break; } } }); if (shouldReturnEmpty) { return []; } return overlappingCells; }; game.resetBackgroundGridCells = function () { for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { var bgCell = bgGrid[i][j]; bgCell.setAlphaAndTint(0.5, 0xFFFFFF); } } }; var gridWidth = 5; var gridHeight = 5; var gridSpacing = 2; var tempTile = new Tile(); var tileWidth = tempTile.width; var tileHeight = tempTile.height; tempTile.destroy(); var tempCell = new Cell(); var cellWidth = 320; var cellHeight = 320; tempCell.destroy(); var gridContainer = new Container(); game.addChild(gridContainer); var totalGridWidth = gridWidth * (cellWidth + gridSpacing) - gridSpacing; var totalGridHeight = gridHeight * (cellHeight + gridSpacing) - gridSpacing; gridContainer.x = (2048 - totalGridWidth) / 2 + cellWidth / 2; gridContainer.y = (2732 - totalGridHeight) / 2 + cellHeight / 2 - 290; game.calculateTargetPosition = function (col, row) { return { x: col * (cellWidth + gridSpacing), y: row * (cellHeight + gridSpacing) }; }; game.findConnectedNeighbors = function (cell, connectedNeighbors) { connectedNeighbors = connectedNeighbors || []; if (!cell) { return []; } var cellType = cell.type; var cellColRow = game.findCellColRow(cell); if (cellColRow) { var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; directions.forEach(function (dir) { var newRow = cellColRow.row + dir[0]; var newCol = cellColRow.col + dir[1]; if (newRow >= 0 && newRow < gridHeight && newCol >= 0 && newCol < gridWidth) { var neighborCell = grid[newCol][newRow]; if (neighborCell && neighborCell.visible && neighborCell.type === cellType && connectedNeighbors.indexOf(neighborCell) === -1) { connectedNeighbors.push(neighborCell); game.findConnectedNeighbors(neighborCell, connectedNeighbors); } } }); } return connectedNeighbors; }; game.findBgCellColRow = function (bgCell) { for (var col = 0; col < gridWidth; col++) { for (var row = 0; row < gridHeight; row++) { if (bgGrid[col][row] === bgCell) { return { col: col, row: row }; } } } return null; }; var grid = Array(5).fill().map(function () { return Array(5).fill(null); }); var bgGrid = Array(5).fill().map(function () { return Array(5).fill(null); }); for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { var bgCell = new GridBackgroundCell(); var targetPos = game.calculateTargetPosition(i, j); bgCell.x = targetPos.x; bgCell.y = targetPos.y; bgGrid[i][j] = bgCell; gridContainer.addChild(bgCell); } } for (var k = 0; k < 2; k++) { var randomCol = Math.floor(Math.random() * gridWidth); var randomRow = Math.floor(Math.random() * gridHeight); while (grid[randomCol][randomRow]) { randomCol = Math.floor(Math.random() * gridWidth); randomRow = Math.floor(Math.random() * gridHeight); } var cell = new Cell(); var targetPos = game.calculateTargetPosition(randomCol, randomRow); cell._move_migrated(targetPos.x, targetPos.y, true); grid[randomCol][randomRow] = cell; game.addAndHandleCell(cell); } game.on('move', function (x, y, obj) { if (draggedTile) { var pos = game.toLocal(obj.global); draggedTile.x = pos.x; draggedTile.y = pos.y; game.highlightOverlappingCells(draggedTile); } }); game.highlightOverlappingCells = function (tile) { game.resetBackgroundGridCells(); var overlappingCells = game.getOverlappingCells(tile); if (overlappingCells.length !== tile.cells.length) { return; } overlappingCells.forEach(function (bgCell, index) { var cell = tile.cells[index]; var color = hsvToRgb(cell.currentHue, 0.25, 1); bgCell.setAlphaAndTint(1, color); }); }; LK.on('tick', function () { for (var i = effectsArray.length - 1; i >= 0; i--) { var effectNode = effectsArray[i]; effectNode.tick(); if (effectNode.alpha <= 0) { effectNode.destroy(); effectsArray.splice(i, 1); } } var allNotMoving = toDelete.every(function (cell) { return !cell.isMoving; }); if (toDelete.length > 0) { if (allNotMoving) { if (toDelete.length > 0) { game.setMergeMode(false); grid.forEach(function (row) { row.forEach(function (cell) { if (cell) { cell.targetAlpha = 1; } }); }); toMerge.forEach(function (group) { group.forEach(function (cell) { game.toTest.push(cell); }); }); toMerge = []; game.processMergeAndGameOver(true); } toDelete.forEach(function (cell) { cell.destroy(); }); toDelete = []; for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { if (grid[i][j] && !grid[i][j].visible) { grid[i][j].visible = true; game.toTest.push(grid[i][j]); } } } } else { for (var i = 0; i < toDelete.length; i++) { toDelete[i].tick(); } } } for (var i = 0; i < gridWidth; i++) { for (var j = 0; j < gridHeight; j++) { if (grid[i][j]) { grid[i][j].tick(allNotMoving); } } } for (var i = 0; i < bottomTiles.length; i++) { if (bottomTiles[i] !== draggedTile) { bottomTiles[i].tick(); } } var isAnyRowMoving = grid.some(function (row) { return row.some(function (cell) { return cell && cell.isMoving; }); }); game.processMergeAndGameOver(); }); var bottomTiles = []; var toDelete = []; var toMerge = []; var draggedTile = null; game.addBottomTiles = function () { var numberOfTiles = 3; var totalTilesWidth = numberOfTiles * tileWidth + (numberOfTiles - 1) * gridSpacing; var margin = (2048 - totalTilesWidth) / 2; var spacing = margin + tileWidth / 2; var posY = 2732 - tileHeight / 2 - margin; for (var i = 0; i < numberOfTiles; i++) { var tile = new Tile(); var posX = spacing + i * (tileWidth + gridSpacing); tile._move_migrated(posX, 2732 + tileHeight, true); tile._move_migrated(posX, posY); bottomTiles[i] = tile; tile.on('down', function () { if (game.mergeMode) { return; } bottomTilesContainer.removeChild(this); bottomTilesContainer.addChild(this); draggedTile = this; }); bottomTilesContainer.addChild(tile); } }; var scoreTxt = new Text2('0', { size: 150, fill: '#24272b', font: 'Impact', dropShadow: true, dropShadowColor: '#ffffff', dropShadowBlur: 4, dropShadowAngle: Math.PI / 6, dropShadowDistance: 6 }); scoreTxt.anchor.set(.5, 0); LK.gui.top.addChild(scoreTxt); game.addChild(bottomTilesContainer); var scoreMultiplierTxt = new Text2('+1', { size: 100, fill: '#24272b', font: 'Impact', dropShadow: true, dropShadowColor: '#ffffff', dropShadowBlur: 4, dropShadowAngle: Math.PI / 6, dropShadowDistance: 6 }); scoreMultiplierTxt.anchor.set(1, 0); scoreMultiplierTxt.x = -20; scoreMultiplierTxt.y = 20; LK.gui.topRight.addChild(scoreMultiplierTxt); game.updateScoreMultiplier = function (multiplier) { scoreMultiplierTxt.setText('x' + Math.max(1, multiplier * 3)); }; game.updateScoreMultiplier(game.scoreMultiplier); game.on('up', function (x, y, obj) { game.resetBackgroundGridCells(); if (draggedTile) { var overlappingCells = game.getOverlappingCells(draggedTile); if (overlappingCells.length === draggedTile.cells.length) { overlappingCells.forEach(function (bgCell, index) { var colRow = game.findBgCellColRow(bgCell); if (colRow && draggedTile.cells[index]) { var cell = draggedTile.cells[index]; var targetPos = game.calculateTargetPosition(colRow.col, colRow.row); cell._move_migrated(targetPos.x, targetPos.y, true); grid[colRow.col][colRow.row] = cell; game.addAndHandleCell(cell); game.toTest.push(cell); } }); var tileIndex = bottomTiles.indexOf(draggedTile); if (tileIndex !== -1) { bottomTiles.splice(tileIndex, 1); } draggedTile.destroy(); if (bottomTiles.length === 0) { game.addBottomTiles(); } draggedTile = null; } } draggedTile = null; }); game.addBottomTiles();
/****
* Classes
****/
var Cell = Container.expand(function (type) {
var self = Container.call(this);
var cellGraphics = self.attachAsset('cell', {
anchorX: 0.5,
anchorY: 0.5
});
var clockGraphics = self.attachAsset('clock', {
anchorX: 0.5,
anchorY: 0.5
});
clockGraphics.y = -8;
clockGraphics.x = -4;
clockGraphics.blendMode = 2;
var indicatorAngles = [270, 330, 30, 90, 150, 210];
var indicatorDistance = 100;
indicatorAngles.forEach(function (angle) {
var radian = angle * (Math.PI / 180);
var indicatorX = clockGraphics.x + Math.cos(radian) * indicatorDistance;
var indicatorY = clockGraphics.y + Math.sin(radian) * indicatorDistance;
var indicator = self.addChild(new ClockIndicator());
indicator.x = indicatorX;
indicator.y = indicatorY;
indicator.rotation = radian;
});
self.targetX = 0;
self.targetY = 0;
self.targetAlpha = 1;
self.isMoving = false;
self.totalTypes = 6;
self.type = type !== undefined ? type : Math.floor(Math.random() * self.totalTypes);
self.realType = self.type;
self.currentHue = self.type / self.totalTypes;
self.targetHue = self.type / self.totalTypes;
self.targetRotation = self.type * (2 * Math.PI / self.totalTypes);
var color = hsvToRgb(self.targetHue, 0.25, 1);
cellGraphics.tint = color;
clockGraphics.rotation = self.targetRotation;
self.changeType = function (newType) {
self.type = newType % self.totalTypes;
self.realType = newType;
self.targetHue = self.realType / self.totalTypes;
self.targetRotation = self.realType * (2 * Math.PI / self.totalTypes);
};
self._move_migrated = function (x, y, instant) {
self.targetX = x;
self.targetY = y;
if (instant) {
self.x = x;
self.y = y;
} else {
var steps = 20;
self.speedX = (x - self.x) / steps;
self.speedY = (y - self.y) / steps;
}
};
self.tick = function (allNotMoving) {
if (allNotMoving) {
if (self.currentHue !== self.targetHue) {
var hueDifference = self.targetHue - self.currentHue;
var hueStep = hueDifference * 0.05;
self.currentHue += hueStep;
if (Math.abs(hueDifference) < 0.01) {
self.currentHue = self.targetHue;
}
var color = hsvToRgb(self.currentHue, 0.25, 1);
cellGraphics.tint = color;
}
var rotationDifference = self.targetRotation - clockGraphics.rotation;
if (Math.abs(rotationDifference) > 0.01) {
clockGraphics.rotation += rotationDifference * 0.05;
} else {
clockGraphics.rotation = self.targetRotation;
}
}
var alphaDifference = self.targetAlpha - self.alpha;
if (Math.abs(alphaDifference) > 0.01) {
self.alpha += alphaDifference * 0.1;
} else {
self.alpha = self.targetAlpha;
}
var acceleration = 1;
self.speedX = self.speedX || 0;
self.speedY = self.speedY || 0;
var threshold = 1;
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
if (Math.abs(dx) < threshold && Math.abs(dy) < threshold) {
self.x = self.targetX;
self.y = self.targetY;
self.isMoving = false;
self.speedX = 0;
self.speedY = 0;
} else {
var nextX = self.x + self.speedX;
var nextY = self.y + self.speedY;
if (self.speedX > 0 && nextX > self.targetX || self.speedX < 0 && nextX < self.targetX) {
nextX = self.targetX;
self.speedX = 0;
}
if (self.speedY > 0 && nextY > self.targetY || self.speedY < 0 && nextY < self.targetY) {
nextY = self.targetY;
self.speedY = 0;
}
self.x = nextX;
self.y = nextY;
self.isMoving = self.x !== self.targetX || self.y !== self.targetY;
}
};
});
var ClockIndicator = Container.expand(function () {
var self = Container.call(this);
var indicatorGraphics = self.attachAsset('clockIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
return self;
});
var GridBackgroundCell = Container.expand(function () {
var self = Container.call(this);
var bgCellGraphics = self.attachAsset('gridCell', {
anchorX: 0.5,
anchorY: 0.5
});
bgCellGraphics.alpha = 0.5;
bgCellGraphics.x += 10;
bgCellGraphics.y += 15;
self.setAlphaAndTint = function (alpha, tint) {
bgCellGraphics.alpha = alpha;
bgCellGraphics.tint = tint;
};
});
var PointsText = Container.expand(function (points, x, y) {
var self = Container.call(this);
var text = new Text2('+' + points, {
size: 180,
fill: '#000000',
weight: '800',
align: 'center',
stroke: '#ffffff',
strokeThickness: 12
});
text.anchor.set(.5, .5);
text.x = x;
text.y = y;
self.addChild(text);
self.getText = function () {
return text;
};
self.alpha = 1;
self.fadeOutDuration = 30;
self.fadeOutStartTime = LK.ticks + 20;
self.tick = function () {
var elapsedTime = LK.ticks - self.fadeOutStartTime;
if (elapsedTime < 0) {
return;
}
if (elapsedTime < self.fadeOutDuration) {
self.alpha = 1 - elapsedTime / self.fadeOutDuration;
self.y -= 2;
} else {
self.alpha = 0;
self.destroy();
}
};
});
var Tile = Container.expand(function (type) {
var self = Container.call(this);
var tileGraphics = self.attachAsset('tile', {
anchorX: 0.5,
anchorY: 0.5
});
tileGraphics.alpha = 0;
self.targetX = 0;
self.targetY = 0;
self.isMoving = false;
self.totalTypes = 3;
self.type = type || Math.floor(Math.random() * self.totalTypes);
var hue = self.type / self.totalTypes;
var color = hsvToRgb(hue, 0.5, 1);
tileGraphics.tint = color;
self.cells = [];
var cellWidth = 0;
var cellHeight = 0;
self.structure = [];
if (self.type === 0) {
self.structure = [[1, 1]];
var cell1 = new Cell();
var cell2 = new Cell();
cellWidth = cell1.width;
cellHeight = cell1.height;
self.cells.push(cell1);
self.cells.push(cell2);
} else if (self.type === 1) {
self.structure = [[1], [1]];
var cell1 = new Cell();
var cell2 = new Cell();
cellWidth = cell1.width;
cellHeight = cell1.height;
self.cells.push(cell1);
self.cells.push(cell2);
} else if (self.type === 2) {
self.structure = [[1]];
var cell1 = new Cell();
cellWidth = cell1.width;
cellHeight = cell1.height;
self.cells.push(cell1);
}
self.cells.forEach(function (cell, index) {
if (self.type === 0) {
cell.x = index === 0 ? self.x - cellWidth / 2 : self.x + cellWidth / 2;
cell.y = self.y;
} else if (self.type === 1) {
cell.x = self.x;
cell.y = index === 0 ? self.y - cellHeight / 2 : self.y + cellHeight / 2;
}
self.addChild(cell);
});
self._move_migrated = function (x, y, instant) {
self.targetX = x;
self.targetY = y;
if (instant) {
self.x = x;
self.y = y;
}
};
self.tick = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 1) {
self.x += dx * 0.15;
self.y += dy * 0.15;
self.isMoving = true;
} else {
self.x = self.targetX;
self.y = self.targetY;
self.isMoving = false;
}
};
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
function hsvToRgb(h, s, v) {
var i = Math.floor(h * 6),
f = h * 6 - i,
p = v * (1 - s),
q = v * (1 - f * s),
t = v * (1 - (1 - f) * s),
mod = i % 6,
r = [v, q, p, p, t, v][mod],
g = [t, v, v, q, p, p][mod],
b = [p, p, t, v, v, q][mod];
return (r * 255 << 16) + (g * 255 << 8) + b * 255;
}
var effectsArray = [];
game.processMergeAndGameOver = function (force) {
force = force || false;
var isAnyRowMoving = grid.some(function (row) {
return row.some(function (cell) {
return cell && cell.isMoving;
});
});
if (!isAnyRowMoving && !game.mergeMode || force) {
grid.forEach(function (row) {
row.forEach(function (cell) {
if (cell) {
var colRow = game.findCellColRow(cell);
var connectedNeighbors = game.findConnectedNeighbors(cell);
if (connectedNeighbors.length >= 3) {
toMerge.push(connectedNeighbors);
game.setMergeMode(true);
}
}
});
});
if (game.mergeMode) {
grid.forEach(function (row) {
row.forEach(function (cell) {
if (cell && !toMerge.some(function (mergeGroup) {
return mergeGroup.includes(cell);
})) {
cell.targetAlpha = 0.4;
}
});
});
game.scoreMultiplier += 1;
game.updateScoreMultiplier(game.scoreMultiplier);
} else {
game.scoreMultiplier = -1;
game.updateScoreMultiplier(game.scoreMultiplier);
}
var isAnyTileMoving = bottomTiles.some(function (tile) {
return tile.isMoving;
});
isAnyRowMoving = grid.some(function (row) {
return row.some(function (cell) {
return cell && cell.isMoving;
});
});
if (!isAnyTileMoving && !game.canPlaceAnyTile() && !isAnyRowMoving && toDelete.length === 0 && !game.mergeMode) {
LK.showGameOver();
}
}
};
game.addAndHandleCell = function (targetCell) {
gridContainer.addChild(targetCell);
targetCell.on('down', function () {
if (game.mergeMode) {
game.mergeConnectedNeighbors(targetCell);
}
});
};
game.mergeConnectedNeighbors = function (cell) {
var connectedNeighbors = game.findConnectedNeighbors(cell);
if (connectedNeighbors.length >= 3) {
var colRow = game.findCellColRow(cell);
var newType = cell.realType + 1;
var pointsEarned = connectedNeighbors.length * Math.max(game.scoreMultiplier * 3, 1);
var pointsText = new PointsText(pointsEarned, cell.x, cell.y - 300);
gridContainer.addChild(pointsText);
effectsArray.push(pointsText);
game.score += pointsEarned;
LK.setScore(game.score);
LK.setScore(game.score);
scoreTxt.setText(game.score.toString());
connectedNeighbors.forEach(function (neighborCell) {
var neighborColRow = game.findCellColRow(neighborCell);
if (neighborColRow) {
if (neighborCell === cell) {
cell.changeType(newType);
gridContainer.removeChild(cell);
gridContainer.addChild(cell);
return;
}
grid[neighborColRow.col][neighborColRow.row] = null;
neighborCell.isMoving = true;
toDelete.push(neighborCell);
neighborCell._move_migrated(cell.x, cell.y);
}
}, this);
}
};
var bottomTilesContainer = new Container();
game.setMergeMode = function (mode) {
game.mergeMode = mode;
bottomTilesContainer.alpha = mode ? 0.4 : 1;
if (!mode && game.mergeModeText) {
game.mergeModeText.destroy();
game.mergeModeText = null;
}
if (mode && !game.mergeModeTextShown) {
var mergeModeText = new Text2('Tap a tile to merge\nall tiles into it', {
size: 130,
fill: '#000000',
weight: '800',
align: 'center',
dropShadow: true,
dropShadowColor: '#ffffff',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6
});
mergeModeText.anchor.set(0.5, 1);
mergeModeText.y = -75;
LK.gui.bottom.addChild(mergeModeText);
game.mergeModeText = mergeModeText;
game.mergeModeTextShown = true;
}
};
game.setMergeMode(false);
game.score = 0;
game.scoreMultiplier = -1;
game.setBackgroundColor(0xffffff);
var backgroundGraphics = game.attachAsset('background', {
anchorX: 0.5,
anchorY: 0.5
});
game.addChild(backgroundGraphics);
backgroundGraphics.x = 2048 / 2;
backgroundGraphics.y = 2732 / 2;
backgroundGraphics.alpha = 0.5;
var bottomTileBackground = game.attachAsset('bottomTileBackground', {
anchorX: 0.5,
anchorY: 1
});
game.addChild(bottomTileBackground);
bottomTileBackground.x = 2048 / 2;
bottomTileBackground.y = 2732;
bottomTileBackground.alpha = 0.5;
game.findCellColRow = function (cell) {
for (var col = 0; col < gridWidth; col++) {
for (var row = 0; row < gridHeight; row++) {
if (grid[col][row] === cell) {
return {
col: col,
row: row
};
}
}
}
return null;
};
game.canPlaceAnyTile = function () {
for (var i = 0; i < bottomTiles.length; i++) {
var tile = bottomTiles[i];
for (var col = 0; col < gridWidth; col++) {
for (var row = 0; row < gridHeight; row++) {
if (game.canPlaceTile(tile, col, row)) {
return true;
}
}
}
}
return false;
};
game.canPlaceTile = function (tile, gridX, gridY) {
for (var row = 0; row < tile.structure.length; row++) {
for (var col = 0; col < tile.structure[row].length; col++) {
if (tile.structure[row][col] === 1) {
var targetCol = gridX + col;
var targetRow = gridY + row;
if (targetCol < 0 || targetCol >= gridWidth || targetRow < 0 || targetRow >= gridHeight) {
return false;
}
if (grid[targetCol][targetRow]) {
return false;
}
}
}
}
return true;
};
game.toTest = [];
game.getOverlappingCells = function (tile) {
var overlappingCells = [];
var shouldReturnEmpty = false;
tile.cells.forEach(function (cell) {
var cellBounds = cell.getBounds();
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
var bgCell = bgGrid[i][j];
var bgCellBounds = bgCell.getBounds();
if (cellBounds.contains(bgCellBounds.x + bgCellBounds.width / 2, bgCellBounds.y + bgCellBounds.height / 2)) {
if (grid[i][j]) {
shouldReturnEmpty = true;
break;
}
overlappingCells.push(bgCell);
}
}
if (shouldReturnEmpty) {
break;
}
}
});
if (shouldReturnEmpty) {
return [];
}
return overlappingCells;
};
game.resetBackgroundGridCells = function () {
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
var bgCell = bgGrid[i][j];
bgCell.setAlphaAndTint(0.5, 0xFFFFFF);
}
}
};
var gridWidth = 5;
var gridHeight = 5;
var gridSpacing = 2;
var tempTile = new Tile();
var tileWidth = tempTile.width;
var tileHeight = tempTile.height;
tempTile.destroy();
var tempCell = new Cell();
var cellWidth = 320;
var cellHeight = 320;
tempCell.destroy();
var gridContainer = new Container();
game.addChild(gridContainer);
var totalGridWidth = gridWidth * (cellWidth + gridSpacing) - gridSpacing;
var totalGridHeight = gridHeight * (cellHeight + gridSpacing) - gridSpacing;
gridContainer.x = (2048 - totalGridWidth) / 2 + cellWidth / 2;
gridContainer.y = (2732 - totalGridHeight) / 2 + cellHeight / 2 - 290;
game.calculateTargetPosition = function (col, row) {
return {
x: col * (cellWidth + gridSpacing),
y: row * (cellHeight + gridSpacing)
};
};
game.findConnectedNeighbors = function (cell, connectedNeighbors) {
connectedNeighbors = connectedNeighbors || [];
if (!cell) {
return [];
}
var cellType = cell.type;
var cellColRow = game.findCellColRow(cell);
if (cellColRow) {
var directions = [[-1, 0], [1, 0], [0, -1], [0, 1]];
directions.forEach(function (dir) {
var newRow = cellColRow.row + dir[0];
var newCol = cellColRow.col + dir[1];
if (newRow >= 0 && newRow < gridHeight && newCol >= 0 && newCol < gridWidth) {
var neighborCell = grid[newCol][newRow];
if (neighborCell && neighborCell.visible && neighborCell.type === cellType && connectedNeighbors.indexOf(neighborCell) === -1) {
connectedNeighbors.push(neighborCell);
game.findConnectedNeighbors(neighborCell, connectedNeighbors);
}
}
});
}
return connectedNeighbors;
};
game.findBgCellColRow = function (bgCell) {
for (var col = 0; col < gridWidth; col++) {
for (var row = 0; row < gridHeight; row++) {
if (bgGrid[col][row] === bgCell) {
return {
col: col,
row: row
};
}
}
}
return null;
};
var grid = Array(5).fill().map(function () {
return Array(5).fill(null);
});
var bgGrid = Array(5).fill().map(function () {
return Array(5).fill(null);
});
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
var bgCell = new GridBackgroundCell();
var targetPos = game.calculateTargetPosition(i, j);
bgCell.x = targetPos.x;
bgCell.y = targetPos.y;
bgGrid[i][j] = bgCell;
gridContainer.addChild(bgCell);
}
}
for (var k = 0; k < 2; k++) {
var randomCol = Math.floor(Math.random() * gridWidth);
var randomRow = Math.floor(Math.random() * gridHeight);
while (grid[randomCol][randomRow]) {
randomCol = Math.floor(Math.random() * gridWidth);
randomRow = Math.floor(Math.random() * gridHeight);
}
var cell = new Cell();
var targetPos = game.calculateTargetPosition(randomCol, randomRow);
cell._move_migrated(targetPos.x, targetPos.y, true);
grid[randomCol][randomRow] = cell;
game.addAndHandleCell(cell);
}
game.on('move', function (x, y, obj) {
if (draggedTile) {
var pos = game.toLocal(obj.global);
draggedTile.x = pos.x;
draggedTile.y = pos.y;
game.highlightOverlappingCells(draggedTile);
}
});
game.highlightOverlappingCells = function (tile) {
game.resetBackgroundGridCells();
var overlappingCells = game.getOverlappingCells(tile);
if (overlappingCells.length !== tile.cells.length) {
return;
}
overlappingCells.forEach(function (bgCell, index) {
var cell = tile.cells[index];
var color = hsvToRgb(cell.currentHue, 0.25, 1);
bgCell.setAlphaAndTint(1, color);
});
};
LK.on('tick', function () {
for (var i = effectsArray.length - 1; i >= 0; i--) {
var effectNode = effectsArray[i];
effectNode.tick();
if (effectNode.alpha <= 0) {
effectNode.destroy();
effectsArray.splice(i, 1);
}
}
var allNotMoving = toDelete.every(function (cell) {
return !cell.isMoving;
});
if (toDelete.length > 0) {
if (allNotMoving) {
if (toDelete.length > 0) {
game.setMergeMode(false);
grid.forEach(function (row) {
row.forEach(function (cell) {
if (cell) {
cell.targetAlpha = 1;
}
});
});
toMerge.forEach(function (group) {
group.forEach(function (cell) {
game.toTest.push(cell);
});
});
toMerge = [];
game.processMergeAndGameOver(true);
}
toDelete.forEach(function (cell) {
cell.destroy();
});
toDelete = [];
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
if (grid[i][j] && !grid[i][j].visible) {
grid[i][j].visible = true;
game.toTest.push(grid[i][j]);
}
}
}
} else {
for (var i = 0; i < toDelete.length; i++) {
toDelete[i].tick();
}
}
}
for (var i = 0; i < gridWidth; i++) {
for (var j = 0; j < gridHeight; j++) {
if (grid[i][j]) {
grid[i][j].tick(allNotMoving);
}
}
}
for (var i = 0; i < bottomTiles.length; i++) {
if (bottomTiles[i] !== draggedTile) {
bottomTiles[i].tick();
}
}
var isAnyRowMoving = grid.some(function (row) {
return row.some(function (cell) {
return cell && cell.isMoving;
});
});
game.processMergeAndGameOver();
});
var bottomTiles = [];
var toDelete = [];
var toMerge = [];
var draggedTile = null;
game.addBottomTiles = function () {
var numberOfTiles = 3;
var totalTilesWidth = numberOfTiles * tileWidth + (numberOfTiles - 1) * gridSpacing;
var margin = (2048 - totalTilesWidth) / 2;
var spacing = margin + tileWidth / 2;
var posY = 2732 - tileHeight / 2 - margin;
for (var i = 0; i < numberOfTiles; i++) {
var tile = new Tile();
var posX = spacing + i * (tileWidth + gridSpacing);
tile._move_migrated(posX, 2732 + tileHeight, true);
tile._move_migrated(posX, posY);
bottomTiles[i] = tile;
tile.on('down', function () {
if (game.mergeMode) {
return;
}
bottomTilesContainer.removeChild(this);
bottomTilesContainer.addChild(this);
draggedTile = this;
});
bottomTilesContainer.addChild(tile);
}
};
var scoreTxt = new Text2('0', {
size: 150,
fill: '#24272b',
font: 'Impact',
dropShadow: true,
dropShadowColor: '#ffffff',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6
});
scoreTxt.anchor.set(.5, 0);
LK.gui.top.addChild(scoreTxt);
game.addChild(bottomTilesContainer);
var scoreMultiplierTxt = new Text2('+1', {
size: 100,
fill: '#24272b',
font: 'Impact',
dropShadow: true,
dropShadowColor: '#ffffff',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6
});
scoreMultiplierTxt.anchor.set(1, 0);
scoreMultiplierTxt.x = -20;
scoreMultiplierTxt.y = 20;
LK.gui.topRight.addChild(scoreMultiplierTxt);
game.updateScoreMultiplier = function (multiplier) {
scoreMultiplierTxt.setText('x' + Math.max(1, multiplier * 3));
};
game.updateScoreMultiplier(game.scoreMultiplier);
game.on('up', function (x, y, obj) {
game.resetBackgroundGridCells();
if (draggedTile) {
var overlappingCells = game.getOverlappingCells(draggedTile);
if (overlappingCells.length === draggedTile.cells.length) {
overlappingCells.forEach(function (bgCell, index) {
var colRow = game.findBgCellColRow(bgCell);
if (colRow && draggedTile.cells[index]) {
var cell = draggedTile.cells[index];
var targetPos = game.calculateTargetPosition(colRow.col, colRow.row);
cell._move_migrated(targetPos.x, targetPos.y, true);
grid[colRow.col][colRow.row] = cell;
game.addAndHandleCell(cell);
game.toTest.push(cell);
}
});
var tileIndex = bottomTiles.indexOf(draggedTile);
if (tileIndex !== -1) {
bottomTiles.splice(tileIndex, 1);
}
draggedTile.destroy();
if (bottomTiles.length === 0) {
game.addBottomTiles();
}
draggedTile = null;
}
}
draggedTile = null;
});
game.addBottomTiles();
Simple White square round corners. Vector. No details. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Simple White square round corners. Vector. No details. Single Game Texture. In-Game asset. 2d. White background. High contrast. No shadows.
Simple black arrow pointing up. Mouse cursor like.