├── README.md ├── doge1.jpeg ├── favicon.png ├── img ├── 144 │ ├── doge-fat-114.gif │ ├── doge-hat-114.gif │ ├── doge-derp-114.gif │ ├── doge-prizza-114.gif │ ├── doge-shake-114.gif │ ├── doge-wink-114.gif │ ├── background-lo-res.png │ ├── doge-gradient-114.gif │ ├── doge-peepers-114.gif │ ├── doge-rainbow-114.gif │ ├── doge-shake-space-114.gif │ └── doge-sunglasses-114.gif └── 212 │ ├── doge-fat-212.gif │ ├── doge-hat-212.gif │ ├── doge-derp-212.gif │ ├── doge-prizza-212.gif │ ├── doge-shake-212.gif │ ├── doge-wink-212.gif │ ├── doge-gradient-212.gif │ ├── doge-peepers-212.gif │ ├── doge-rainbow-212.gif │ ├── doge-shake-space-212.gif │ └── doge-sunglasses-212.gif ├── meta └── apple-touch-icon.png ├── style ├── fonts │ ├── comic_sans.woff │ └── comic-sans.css └── main.css ├── rate.js ├── js ├── tile.js ├── animframe_polyfill.js ├── local_score_manager.js ├── application.js ├── grid.js ├── keyboard_input_manager.js ├── html_actuator.js └── game_manager.js └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # doge-2048.github.io -------------------------------------------------------------------------------- /doge1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/doge1.jpeg -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/favicon.png -------------------------------------------------------------------------------- /img/144/doge-fat-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-fat-114.gif -------------------------------------------------------------------------------- /img/144/doge-hat-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-hat-114.gif -------------------------------------------------------------------------------- /img/212/doge-fat-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-fat-212.gif -------------------------------------------------------------------------------- /img/212/doge-hat-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-hat-212.gif -------------------------------------------------------------------------------- /img/144/doge-derp-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-derp-114.gif -------------------------------------------------------------------------------- /img/144/doge-prizza-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-prizza-114.gif -------------------------------------------------------------------------------- /img/144/doge-shake-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-shake-114.gif -------------------------------------------------------------------------------- /img/144/doge-wink-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-wink-114.gif -------------------------------------------------------------------------------- /img/212/doge-derp-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-derp-212.gif -------------------------------------------------------------------------------- /img/212/doge-prizza-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-prizza-212.gif -------------------------------------------------------------------------------- /img/212/doge-shake-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-shake-212.gif -------------------------------------------------------------------------------- /img/212/doge-wink-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-wink-212.gif -------------------------------------------------------------------------------- /meta/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/meta/apple-touch-icon.png -------------------------------------------------------------------------------- /style/fonts/comic_sans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/style/fonts/comic_sans.woff -------------------------------------------------------------------------------- /img/144/background-lo-res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/background-lo-res.png -------------------------------------------------------------------------------- /img/144/doge-gradient-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-gradient-114.gif -------------------------------------------------------------------------------- /img/144/doge-peepers-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-peepers-114.gif -------------------------------------------------------------------------------- /img/144/doge-rainbow-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-rainbow-114.gif -------------------------------------------------------------------------------- /img/212/doge-gradient-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-gradient-212.gif -------------------------------------------------------------------------------- /img/212/doge-peepers-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-peepers-212.gif -------------------------------------------------------------------------------- /img/212/doge-rainbow-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-rainbow-212.gif -------------------------------------------------------------------------------- /rate.js: -------------------------------------------------------------------------------- 1 | document.querySelector('#rate').href = `https://chrome.google.com/webstore/detail/${chrome.runtime.id}/reviews`; -------------------------------------------------------------------------------- /img/144/doge-shake-space-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-shake-space-114.gif -------------------------------------------------------------------------------- /img/144/doge-sunglasses-114.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/144/doge-sunglasses-114.gif -------------------------------------------------------------------------------- /img/212/doge-shake-space-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-shake-space-212.gif -------------------------------------------------------------------------------- /img/212/doge-sunglasses-212.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/2Cmo/doge-2048.github.io/doge2048/img/212/doge-sunglasses-212.gif -------------------------------------------------------------------------------- /style/fonts/comic-sans.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "Comic Sans"; 3 | src: url("comic_sans.eot"); 4 | src: url("comic_sans.eot?#iefix") format("embedded-opentype"), 5 | url("comic_sans.woff") format("woff"); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | -------------------------------------------------------------------------------- /js/tile.js: -------------------------------------------------------------------------------- 1 | function Tile(position, value) { 2 | this.x = position.x; 3 | this.y = position.y; 4 | this.value = value || 2; 5 | 6 | this.previousPosition = null; 7 | this.mergedFrom = null; // Tracks tiles that merged together 8 | } 9 | 10 | Tile.prototype.savePosition = function () { 11 | this.previousPosition = { x: this.x, y: this.y }; 12 | }; 13 | 14 | Tile.prototype.updatePosition = function (position) { 15 | this.x = position.x; 16 | this.y = position.y; 17 | }; 18 | -------------------------------------------------------------------------------- /js/animframe_polyfill.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var lastTime = 0; 3 | var vendors = ['webkit', 'moz']; 4 | for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { 5 | window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; 6 | window.cancelAnimationFrame = 7 | window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; 8 | } 9 | 10 | if (!window.requestAnimationFrame) { 11 | window.requestAnimationFrame = function(callback, element) { 12 | var currTime = new Date().getTime(); 13 | var timeToCall = Math.max(0, 16 - (currTime - lastTime)); 14 | var id = window.setTimeout(function() { callback(currTime + timeToCall); }, 15 | timeToCall); 16 | lastTime = currTime + timeToCall; 17 | return id; 18 | }; 19 | } 20 | 21 | if (!window.cancelAnimationFrame) { 22 | window.cancelAnimationFrame = function(id) { 23 | clearTimeout(id); 24 | }; 25 | } 26 | }()); 27 | -------------------------------------------------------------------------------- /js/local_score_manager.js: -------------------------------------------------------------------------------- 1 | window.fakeStorage = { 2 | _data: {}, 3 | 4 | setItem: function (id, val) { 5 | return this._data[id] = String(val); 6 | }, 7 | 8 | getItem: function (id) { 9 | return this._data.hasOwnProperty(id) ? this._data[id] : undefined; 10 | }, 11 | 12 | removeItem: function (id) { 13 | return delete this._data[id]; 14 | }, 15 | 16 | clear: function () { 17 | return this._data = {}; 18 | } 19 | }; 20 | 21 | function LocalScoreManager() { 22 | this.key = "bestScore"; 23 | 24 | var supported = this.localStorageSupported(); 25 | this.storage = supported ? window.localStorage : window.fakeStorage; 26 | } 27 | 28 | LocalScoreManager.prototype.localStorageSupported = function () { 29 | var testKey = "test"; 30 | var storage = window.localStorage; 31 | 32 | try { 33 | storage.setItem(testKey, "1"); 34 | storage.removeItem(testKey); 35 | return true; 36 | } catch (error) { 37 | return false; 38 | } 39 | }; 40 | 41 | LocalScoreManager.prototype.get = function () { 42 | return this.storage.getItem(this.key) || 0; 43 | }; 44 | 45 | LocalScoreManager.prototype.set = function (score) { 46 | this.storage.setItem(this.key, score); 47 | }; 48 | -------------------------------------------------------------------------------- /js/application.js: -------------------------------------------------------------------------------- 1 | // Wait till the browser is ready to render the game (avoids glitches) 2 | window.requestAnimationFrame(function () { 3 | new GameManager(4, KeyboardInputManager, HTMLActuator, LocalScoreManager); 4 | }); 5 | 6 | 7 | var imageList = [ 8 | "img/212/doge-derp-212.gif", 9 | "img/212/doge-fat-212.gif", 10 | "img/212/doge-gradient-212.gif", 11 | "img/212/doge-hat-212.gif", 12 | "img/212/doge-peepers-212.gif", 13 | "img/212/doge-prizza-212.gif", 14 | "img/212/doge-rainbow-212.gif", 15 | "img/212/doge-shake-space-212.gif", 16 | "img/212/doge-sunglasses-212.gif", 17 | "img/212/doge-shake-212.gif", 18 | "img/212/doge-wink-212.gif", 19 | "img/114/doge-derp-114.gif", 20 | "img/114/doge-fat-114.gif", 21 | "img/114/doge-gradient-114.gif", 22 | "img/114/doge-hat-114.gif", 23 | "img/114/doge-peepers-114.gif", 24 | "img/114/doge-prizza-114.gif", 25 | "img/114/doge-rainbow-114.gif", 26 | "img/114/doge-shake-space-114.gif", 27 | "img/114/doge-sunglasses-114.gif", 28 | "img/114/doge-shake-114.gif", 29 | "img/114/doge-wink-114.gif", 30 | ]; 31 | for(var i = 0; i < imageList.length; i++ ) 32 | { 33 | var imageObject = new Image(); 34 | imageObject.src = imageList[i]; 35 | } 36 | -------------------------------------------------------------------------------- /js/grid.js: -------------------------------------------------------------------------------- 1 | function Grid(size) { 2 | this.size = size; 3 | 4 | this.cells = []; 5 | 6 | this.build(); 7 | } 8 | 9 | // Build a grid of the specified size 10 | Grid.prototype.build = function () { 11 | for (var x = 0; x < this.size; x++) { 12 | var row = this.cells[x] = []; 13 | 14 | for (var y = 0; y < this.size; y++) { 15 | row.push(null); 16 | } 17 | } 18 | }; 19 | 20 | // Find the first available random position 21 | Grid.prototype.randomAvailableCell = function () { 22 | var cells = this.availableCells(); 23 | 24 | if (cells.length) { 25 | return cells[Math.floor(Math.random() * cells.length)]; 26 | } 27 | }; 28 | 29 | Grid.prototype.availableCells = function () { 30 | var cells = []; 31 | 32 | this.eachCell(function (x, y, tile) { 33 | if (!tile) { 34 | cells.push({ x: x, y: y }); 35 | } 36 | }); 37 | 38 | return cells; 39 | }; 40 | 41 | // Call callback for every cell 42 | Grid.prototype.eachCell = function (callback) { 43 | for (var x = 0; x < this.size; x++) { 44 | for (var y = 0; y < this.size; y++) { 45 | callback(x, y, this.cells[x][y]); 46 | } 47 | } 48 | }; 49 | 50 | // Check if there are any cells available 51 | Grid.prototype.cellsAvailable = function () { 52 | return !!this.availableCells().length; 53 | }; 54 | 55 | // Check if the specified cell is taken 56 | Grid.prototype.cellAvailable = function (cell) { 57 | return !this.cellOccupied(cell); 58 | }; 59 | 60 | Grid.prototype.cellOccupied = function (cell) { 61 | return !!this.cellContent(cell); 62 | }; 63 | 64 | Grid.prototype.cellContent = function (cell) { 65 | if (this.withinBounds(cell)) { 66 | return this.cells[cell.x][cell.y]; 67 | } else { 68 | return null; 69 | } 70 | }; 71 | 72 | // Inserts a tile at its position 73 | Grid.prototype.insertTile = function (tile) { 74 | this.cells[tile.x][tile.y] = tile; 75 | }; 76 | 77 | Grid.prototype.removeTile = function (tile) { 78 | this.cells[tile.x][tile.y] = null; 79 | }; 80 | 81 | Grid.prototype.withinBounds = function (position) { 82 | return position.x >= 0 && position.x < this.size && 83 | position.y >= 0 && position.y < this.size; 84 | }; 85 | -------------------------------------------------------------------------------- /js/keyboard_input_manager.js: -------------------------------------------------------------------------------- 1 | function KeyboardInputManager() { 2 | this.events = {}; 3 | 4 | this.listen(); 5 | } 6 | 7 | KeyboardInputManager.prototype.on = function (event, callback) { 8 | if (!this.events[event]) { 9 | this.events[event] = []; 10 | } 11 | this.events[event].push(callback); 12 | }; 13 | 14 | KeyboardInputManager.prototype.emit = function (event, data) { 15 | var callbacks = this.events[event]; 16 | if (callbacks) { 17 | callbacks.forEach(function (callback) { 18 | callback(data); 19 | }); 20 | } 21 | }; 22 | 23 | KeyboardInputManager.prototype.listen = function () { 24 | var self = this; 25 | 26 | var map = { 27 | 38: 0, // Up 28 | 39: 1, // Right 29 | 40: 2, // Down 30 | 37: 3, // Left 31 | 75: 0, // vim keybindings 32 | 76: 1, 33 | 74: 2, 34 | 72: 3, 35 | 87: 0, // W 36 | 68: 1, // D 37 | 83: 2, // S 38 | 65: 3 // A 39 | }; 40 | 41 | document.addEventListener("keydown", function (event) { 42 | var modifiers = event.altKey || event.ctrlKey || event.metaKey || 43 | event.shiftKey; 44 | var mapped = map[event.which]; 45 | 46 | if (!modifiers) { 47 | if (mapped !== undefined) { 48 | event.preventDefault(); 49 | self.emit("move", mapped); 50 | } 51 | 52 | if (event.which === 32) self.restart.bind(self)(event); 53 | } 54 | }); 55 | 56 | var retry = document.querySelector(".retry-button"); 57 | retry.addEventListener("click", this.restart.bind(this)); 58 | retry.addEventListener("touchend", this.restart.bind(this)); 59 | 60 | var keepPlaying = document.querySelector(".keep-playing-button"); 61 | keepPlaying.addEventListener("click", this.keepPlaying.bind(this)); 62 | keepPlaying.addEventListener("touchend", this.keepPlaying.bind(this)); 63 | 64 | var showInfo = document.querySelector(".info-container"); 65 | showInfo.addEventListener("click", this.showInfo.bind(this)); 66 | showInfo.addEventListener("touchend", this.showInfo.bind(this)); 67 | 68 | // var hideInfo = document.querySelector(".hide-info"); 69 | // hideInfo.addEventListener("click", this.hideInfo.bind(this)); 70 | // hideInfo.addEventListener("touchend", this.hideInfo.bind(this)); 71 | 72 | 73 | // Listen to swipe events 74 | var touchStartClientX, touchStartClientY; 75 | var gameContainer = document.getElementsByClassName("game-container")[0]; 76 | 77 | gameContainer.addEventListener("touchstart", function (event) { 78 | if (event.touches.length > 1) return; 79 | 80 | touchStartClientX = event.touches[0].clientX; 81 | touchStartClientY = event.touches[0].clientY; 82 | event.preventDefault(); 83 | }); 84 | 85 | gameContainer.addEventListener("touchmove", function (event) { 86 | event.preventDefault(); 87 | }); 88 | 89 | gameContainer.addEventListener("touchend", function (event) { 90 | if (event.touches.length > 0) return; 91 | var dx = event.changedTouches[0].clientX - touchStartClientX; 92 | var absDx = Math.abs(dx); 93 | var dy = event.changedTouches[0].clientY - touchStartClientY; 94 | var absDy = Math.abs(dy); 95 | if (Math.max(absDx, absDy) > 10) { 96 | // (right : left) : (down : up) 97 | self.emit("move", absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 2 : 0)); 98 | } 99 | }); 100 | }; 101 | KeyboardInputManager.prototype.restart = function (event) { 102 | event.preventDefault(); 103 | this.emit("restart"); 104 | }; 105 | KeyboardInputManager.prototype.keepPlaying = function (event) { 106 | event.preventDefault(); 107 | this.emit("keepPlaying"); 108 | }; 109 | KeyboardInputManager.prototype.showInfo = function (event) { 110 | event.preventDefault(); 111 | this.emit("showInfo"); 112 | }; 113 | KeyboardInputManager.prototype.hideInfo = function (event) { 114 | event.preventDefault(); 115 | this.emit("hideInfo"); 116 | }; 117 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DOGE 2048 | ubg247 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 |
27 |

DOGE2048 28 |

29 |
30 | Unblocked Games | 31 | 32 | Rate Us 33 |
0
34 |
0
35 |
36 |
37 | 38 |
39 |
40 |

41 |
42 |
43 | 44 |

Use your arrow keys or swipe to combine similar Doges and score points!

45 |

Unlock all 11 doges to win!

46 |

Doge-ified by ubg247 47 |

2048 Created by Gabriele Cirulli.

48 |

Based on 1024 by Veewo Studio and conceptually similar to Threes by Asher Vollmer. 49 |

50 |
51 |
52 |

53 |
54 | Keep going 55 | Try again 56 |
57 |
58 | 59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | 86 |
87 |
88 |
89 |

Use your arrow keys or swipe to combine similar Doges and score points!

90 | 93 |
94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /js/html_actuator.js: -------------------------------------------------------------------------------- 1 | function HTMLActuator() { 2 | this.tileContainer = document.querySelector(".tile-container"); 3 | this.scoreContainer = document.querySelector(".score-container"); 4 | this.bestContainer = document.querySelector(".best-container"); 5 | this.messageContainer = document.querySelector(".game-message"); 6 | this.info = document.querySelector(".info"); 7 | this.dogeSays = document.querySelector(".doge-says"); 8 | this.adSpace = document.querySelector(".shout-out"); 9 | 10 | this.score = 0; 11 | } 12 | 13 | var dogeSayings = ['such good', 'so amaze', 'many points', 'very unstoppable', 'great jorb', 'such playing', 'very good', 'points', 'very gaming', 'such player', 'concern' ,'bewildered', 'pro gamer', 'many game', 'so good', 'very scores', 'so scoring', 'so hot right now', 'such playing', 'such matching', 'so matched', 'very matched', 'very neat' ,'such natural',] 14 | 15 | HTMLActuator.prototype.actuate = function (grid, metadata) { 16 | var self = this; 17 | 18 | window.requestAnimationFrame(function () { 19 | self.clearContainer(self.tileContainer); 20 | 21 | grid.cells.forEach(function (column) { 22 | column.forEach(function (cell) { 23 | if (cell) { 24 | self.addTile(cell); 25 | } 26 | }); 27 | }); 28 | 29 | self.updateScore(metadata.score); 30 | self.updateBestScore(metadata.bestScore); 31 | 32 | if (metadata.terminated) { 33 | if (metadata.over) { 34 | self.message(false); // You lose 35 | } else if (metadata.won) { 36 | self.message(true); // You win! 37 | } 38 | } 39 | 40 | }); 41 | }; 42 | 43 | // Continues the game (both restart and keep playing) 44 | HTMLActuator.prototype.continue = function () { 45 | this.clearMessage(); 46 | }; 47 | 48 | HTMLActuator.prototype.clearContainer = function (container) { 49 | while (container.firstChild) { 50 | container.removeChild(container.firstChild); 51 | } 52 | }; 53 | 54 | HTMLActuator.prototype.addTile = function (tile) { 55 | var self = this; 56 | 57 | var wrapper = document.createElement("div"); 58 | var inner = document.createElement("div"); 59 | var position = tile.previousPosition || { x: tile.x, y: tile.y }; 60 | var positionClass = this.positionClass(position); 61 | 62 | // We can't use classlist because it somehow glitches when replacing classes 63 | var classes = ["tile", "tile-" + tile.value, positionClass]; 64 | 65 | if (tile.value > 2048) classes.push("tile-super"); 66 | 67 | this.applyClasses(wrapper, classes); 68 | 69 | inner.classList.add("tile-inner"); 70 | inner.textContent = tile.value; 71 | 72 | if (tile.previousPosition) { 73 | // Make sure that the tile gets rendered in the previous position first 74 | window.requestAnimationFrame(function () { 75 | classes[2] = self.positionClass({ x: tile.x, y: tile.y }); 76 | self.applyClasses(wrapper, classes); // Update the position 77 | }); 78 | } else if (tile.mergedFrom) { 79 | classes.push("tile-merged"); 80 | this.applyClasses(wrapper, classes); 81 | 82 | // Render the tiles that merged 83 | tile.mergedFrom.forEach(function (merged) { 84 | self.addTile(merged); 85 | }); 86 | } else { 87 | classes.push("tile-new"); 88 | this.applyClasses(wrapper, classes); 89 | } 90 | 91 | // Add the inner part of the tile to the wrapper 92 | wrapper.appendChild(inner); 93 | 94 | // Put the tile on the board 95 | this.tileContainer.appendChild(wrapper); 96 | }; 97 | 98 | HTMLActuator.prototype.applyClasses = function (element, classes) { 99 | element.setAttribute("class", classes.join(" ")); 100 | }; 101 | 102 | HTMLActuator.prototype.normalizePosition = function (position) { 103 | return { x: position.x + 1, y: position.y + 1 }; 104 | }; 105 | 106 | HTMLActuator.prototype.positionClass = function (position) { 107 | position = this.normalizePosition(position); 108 | return "tile-position-" + position.x + "-" + position.y; 109 | }; 110 | 111 | HTMLActuator.prototype.updateScore = function (score) { 112 | this.clearContainer(this.scoreContainer); 113 | this.clearContainer(this.dogeSays) 114 | 115 | var difference = score - this.score; 116 | this.score = score; 117 | 118 | this.scoreContainer.textContent = this.score; 119 | 120 | if (difference > 0) { 121 | var addition = document.createElement("div"); 122 | addition.classList.add("score-addition"); 123 | addition.textContent = "+" + difference; 124 | this.scoreContainer.appendChild(addition); 125 | 126 | var message = dogeSayings[Math.floor(Math.random() * dogeSayings.length)] 127 | var messageElement = document.createElement("p"); 128 | messageElement.textContent = message 129 | var left = 'left:' + Math.round(Math.random() * 80) + '%;' 130 | var top = 'top:' + Math.round(Math.random() * 80) + '%;' 131 | var color = 'color: rgb(' + Math.round(Math.random() * 255) + ', ' + Math.round(Math.random() * 255) + ', ' + Math.round(Math.random() * 255) + ');' 132 | var styleString = left + top + color 133 | messageElement.setAttribute('style', styleString); 134 | this.dogeSays.appendChild(messageElement); 135 | if (difference > 4) { 136 | this.adSpace.innerHTML = ads[Math.floor(Math.random() * ads.length)] 137 | } 138 | 139 | } 140 | }; 141 | 142 | HTMLActuator.prototype.updateBestScore = function (bestScore) { 143 | this.bestContainer.textContent = bestScore; 144 | }; 145 | 146 | HTMLActuator.prototype.message = function (won) { 147 | var type = won ? "game-won" : "game-over"; 148 | var message = won ? "You win!" : "Game over!"; 149 | 150 | this.messageContainer.classList.add(type); 151 | this.messageContainer.getElementsByTagName("p")[0].textContent = message; 152 | }; 153 | 154 | HTMLActuator.prototype.clearMessage = function () { 155 | // IE only takes one value to remove at a time. 156 | this.messageContainer.classList.remove("game-won"); 157 | this.messageContainer.classList.remove("game-over"); 158 | }; 159 | 160 | 161 | HTMLActuator.prototype.showInfo = function () { 162 | if ( this.info.getAttribute('style') === "display:block;"){ 163 | this.info.setAttribute('style','display:none;') 164 | document.querySelector('.show-info').innerHTML = 'INFO'; 165 | } else { 166 | this.info.setAttribute('style','display:block;') 167 | document.querySelector('.show-info').innerHTML = 'CLOSE'; 168 | } 169 | } 170 | 171 | HTMLActuator.prototype.hideInfo = function () { 172 | this.info.setAttribute('style','display:none;') 173 | } 174 | -------------------------------------------------------------------------------- /js/game_manager.js: -------------------------------------------------------------------------------- 1 | function GameManager(size, InputManager, Actuator, ScoreManager) { 2 | this.size = size; // Size of the grid 3 | this.inputManager = new InputManager; 4 | this.scoreManager = new ScoreManager; 5 | this.actuator = new Actuator; 6 | 7 | this.startTiles = 2; 8 | 9 | this.inputManager.on("move", this.move.bind(this)); 10 | this.inputManager.on("restart", this.restart.bind(this)); 11 | this.inputManager.on("keepPlaying", this.keepPlaying.bind(this)); 12 | this.inputManager.on("showInfo", this.showInfo.bind(this)); 13 | this.inputManager.on("hideInfo", this.hideInfo.bind(this)); 14 | 15 | this.setup(); 16 | } 17 | 18 | // Restart the game 19 | GameManager.prototype.restart = function () { 20 | this.actuator.continue(); 21 | this.setup(); 22 | }; 23 | 24 | // Keep playing after winning 25 | GameManager.prototype.keepPlaying = function () { 26 | this.keepPlaying = true; 27 | this.actuator.continue(); 28 | }; 29 | 30 | GameManager.prototype.showInfo = function () { 31 | this.actuator.showInfo(); 32 | }; 33 | 34 | 35 | GameManager.prototype.hideInfo = function () { 36 | this.actuator.hideInfo(); 37 | }; 38 | 39 | GameManager.prototype.isGameTerminated = function () { 40 | if (this.over || (this.won && !this.keepPlaying)) { 41 | return true; 42 | } else { 43 | return false; 44 | } 45 | }; 46 | 47 | // Set up the game 48 | GameManager.prototype.setup = function () { 49 | this.grid = new Grid(this.size); 50 | 51 | this.score = 0; 52 | this.over = false; 53 | this.won = false; 54 | this.keepPlaying = false; 55 | 56 | // Add the initial tiles 57 | this.addStartTiles(); 58 | 59 | // Update the actuator 60 | this.actuate(); 61 | }; 62 | 63 | // Set up the initial tiles to start the game with 64 | GameManager.prototype.addStartTiles = function () { 65 | for (var i = 0; i < this.startTiles; i++) { 66 | this.addRandomTile(); 67 | } 68 | }; 69 | 70 | // Adds a tile in a random position 71 | GameManager.prototype.addRandomTile = function () { 72 | if (this.grid.cellsAvailable()) { 73 | var value = Math.random() < 0.9 ? 2 : 4; 74 | var tile = new Tile(this.grid.randomAvailableCell(), value); 75 | 76 | this.grid.insertTile(tile); 77 | } 78 | }; 79 | 80 | // Sends the updated grid to the actuator 81 | GameManager.prototype.actuate = function () { 82 | if (this.scoreManager.get() < this.score) { 83 | this.scoreManager.set(this.score); 84 | } 85 | 86 | this.actuator.actuate(this.grid, { 87 | score: this.score, 88 | over: this.over, 89 | won: this.won, 90 | bestScore: this.scoreManager.get(), 91 | terminated: this.isGameTerminated() 92 | }); 93 | 94 | }; 95 | 96 | // Save all tile positions and remove merger info 97 | GameManager.prototype.prepareTiles = function () { 98 | this.grid.eachCell(function (x, y, tile) { 99 | if (tile) { 100 | tile.mergedFrom = null; 101 | tile.savePosition(); 102 | } 103 | }); 104 | }; 105 | 106 | // Move a tile and its representation 107 | GameManager.prototype.moveTile = function (tile, cell) { 108 | this.grid.cells[tile.x][tile.y] = null; 109 | this.grid.cells[cell.x][cell.y] = tile; 110 | tile.updatePosition(cell); 111 | }; 112 | 113 | // Move tiles on the grid in the specified direction 114 | GameManager.prototype.move = function (direction) { 115 | // 0: up, 1: right, 2:down, 3: left 116 | var self = this; 117 | 118 | if (this.isGameTerminated()) return; // Don't do anything if the game's over 119 | 120 | var cell, tile; 121 | 122 | var vector = this.getVector(direction); 123 | var traversals = this.buildTraversals(vector); 124 | var moved = false; 125 | 126 | // Save the current tile positions and remove merger information 127 | this.prepareTiles(); 128 | 129 | // Traverse the grid in the right direction and move tiles 130 | traversals.x.forEach(function (x) { 131 | traversals.y.forEach(function (y) { 132 | cell = { x: x, y: y }; 133 | tile = self.grid.cellContent(cell); 134 | 135 | if (tile) { 136 | var positions = self.findFarthestPosition(cell, vector); 137 | var next = self.grid.cellContent(positions.next); 138 | 139 | // Only one merger per row traversal? 140 | if (next && next.value === tile.value && !next.mergedFrom) { 141 | var merged = new Tile(positions.next, tile.value * 2); 142 | merged.mergedFrom = [tile, next]; 143 | 144 | self.grid.insertTile(merged); 145 | self.grid.removeTile(tile); 146 | 147 | // Converge the two tiles' positions 148 | tile.updatePosition(positions.next); 149 | 150 | // Update the score 151 | self.score += merged.value; 152 | 153 | // The mighty 2048 tile 154 | if (merged.value === 2048) self.won = true; 155 | } else { 156 | self.moveTile(tile, positions.farthest); 157 | } 158 | 159 | if (!self.positionsEqual(cell, tile)) { 160 | moved = true; // The tile moved from its original cell! 161 | } 162 | } 163 | }); 164 | }); 165 | 166 | if (moved) { 167 | this.addRandomTile(); 168 | 169 | if (!this.movesAvailable()) { 170 | this.over = true; // Game over! 171 | } 172 | 173 | this.actuate(); 174 | } 175 | }; 176 | 177 | // Get the vector representing the chosen direction 178 | GameManager.prototype.getVector = function (direction) { 179 | // Vectors representing tile movement 180 | var map = { 181 | 0: { x: 0, y: -1 }, // up 182 | 1: { x: 1, y: 0 }, // right 183 | 2: { x: 0, y: 1 }, // down 184 | 3: { x: -1, y: 0 } // left 185 | }; 186 | 187 | return map[direction]; 188 | }; 189 | 190 | // Build a list of positions to traverse in the right order 191 | GameManager.prototype.buildTraversals = function (vector) { 192 | var traversals = { x: [], y: [] }; 193 | 194 | for (var pos = 0; pos < this.size; pos++) { 195 | traversals.x.push(pos); 196 | traversals.y.push(pos); 197 | } 198 | 199 | // Always traverse from the farthest cell in the chosen direction 200 | if (vector.x === 1) traversals.x = traversals.x.reverse(); 201 | if (vector.y === 1) traversals.y = traversals.y.reverse(); 202 | 203 | return traversals; 204 | }; 205 | 206 | GameManager.prototype.findFarthestPosition = function (cell, vector) { 207 | var previous; 208 | 209 | // Progress towards the vector direction until an obstacle is found 210 | do { 211 | previous = cell; 212 | cell = { x: previous.x + vector.x, y: previous.y + vector.y }; 213 | } while (this.grid.withinBounds(cell) && 214 | this.grid.cellAvailable(cell)); 215 | 216 | return { 217 | farthest: previous, 218 | next: cell // Used to check if a merge is required 219 | }; 220 | }; 221 | 222 | GameManager.prototype.movesAvailable = function () { 223 | return this.grid.cellsAvailable() || this.tileMatchesAvailable(); 224 | }; 225 | 226 | // Check for available matches between tiles (more expensive check) 227 | GameManager.prototype.tileMatchesAvailable = function () { 228 | var self = this; 229 | 230 | var tile; 231 | 232 | for (var x = 0; x < this.size; x++) { 233 | for (var y = 0; y < this.size; y++) { 234 | tile = this.grid.cellContent({ x: x, y: y }); 235 | 236 | if (tile) { 237 | for (var direction = 0; direction < 4; direction++) { 238 | var vector = self.getVector(direction); 239 | var cell = { x: x + vector.x, y: y + vector.y }; 240 | 241 | var other = self.grid.cellContent(cell); 242 | 243 | if (other && other.value === tile.value) { 244 | return true; // These two tiles can be merged 245 | } 246 | } 247 | } 248 | } 249 | } 250 | 251 | return false; 252 | }; 253 | 254 | GameManager.prototype.positionsEqual = function (first, second) { 255 | return first.x === second.x && first.y === second.y; 256 | }; 257 | -------------------------------------------------------------------------------- /style/main.css: -------------------------------------------------------------------------------- 1 | @import url(fonts/comic-sans.css); 2 | html, body { 3 | margin: 0; 4 | padding: 0; 5 | background: #fff; 6 | color: #000; 7 | /* font-family: "Clear Sans", "Helvetica Neue", Arial, sans-serif;*/ 8 | font-family: 'Comic Sans', 'Comic Sans', Chalkboard, Helvetica, Arial, sans-serif; 9 | font-size: 18px; 10 | -webkit-animation: background-gradient-change linear 6s infinite alternate; 11 | -moz-animation: background-gradient-change linear 6s infinite alternate; 12 | -moz-animation: background-gradient-change linear 6s infinite alternate; } 13 | 14 | body { 15 | margin: 20px 0 0 0; } 16 | 17 | .overlay{ 18 | height: 100%; 19 | width: 100%; 20 | position:fixed; 21 | top:0; 22 | left:0; 23 | overflow:auto; 24 | background: rgba(255,255,255,0.8); 25 | z-index: 1000; 26 | } 27 | 28 | .modal{ 29 | background: #f0f; 30 | border-radius: 3px; 31 | width:300px; 32 | margin-top:100px; 33 | margin-left: auto; 34 | margin-right: auto; 35 | } 36 | .appstore{ 37 | text-align: center; 38 | } 39 | 40 | .appstore-icon{ 41 | margin-top:20px; 42 | margin-left:auto; 43 | margin-right:auto; 44 | height: 212px; 45 | width: 212px; 46 | background: #f0f url('../img/212/doge-sunglasses-212.gif'); 47 | } 48 | .close-modal{ 49 | margin-top:20px; 50 | cursor: pointer; 51 | } 52 | 53 | .close-modal:hover{ 54 | -webkit-animation: hover-change linear 0.1s infinite; 55 | -moz-animation: hover-change linear 0.1s infinite; 56 | animation: hover-change linear 0.1s infinite; 57 | } 58 | 59 | .heading:after { 60 | content: ""; 61 | display: block; 62 | clear: both; } 63 | 64 | h1.title { 65 | color:#333; 66 | font-size: 27px; 67 | font-weight: bold; 68 | margin: 0; 69 | display: block; 70 | float: left; } 71 | 72 | #twitter-widget-0 { 73 | width: 100px !important; 74 | position: relative; 75 | } 76 | 77 | .COINWIDGETCOM_CONTAINER { 78 | position: relative; 79 | bottom: 5px; 80 | } 81 | 82 | .footer > div{ 83 | display:inline-block !important; 84 | width: auto !important; 85 | overflow:hidden; 86 | } 87 | 88 | .footer{ 89 | /* width:188px;*/ 90 | width:265px; 91 | margin-left: auto; 92 | margin-right: auto; 93 | text-align:center;} 94 | 95 | @-webkit-keyframes move-up { 96 | 0% { 97 | top: 25px; 98 | opacity: 1; } 99 | 100 | 100% { 101 | top: -50px; 102 | opacity: 0; } } 103 | 104 | @-moz-keyframes move-up { 105 | 0% { 106 | top: 25px; 107 | opacity: 1; } 108 | 109 | 100% { 110 | top: -50px; 111 | opacity: 0; } } 112 | 113 | @keyframes move-up { 114 | 0% { 115 | top: 25px; 116 | opacity: 1; } 117 | 118 | 100% { 119 | top: -50px; 120 | opacity: 0; } } 121 | 122 | @-webkit-keyframes fade-in-out { 123 | 0% { 124 | opacity: 0; } 125 | 126 | 50% { 127 | opacity: 1; } 128 | 129 | 100% { 130 | opacity: 0; } } 131 | 132 | @-moz-keyframes fade-in-out { 133 | 0% { 134 | opacity: 0; } 135 | 136 | 50% { 137 | opacity: 1; } 138 | 139 | 100% { 140 | opacity: 0; } } 141 | 142 | @keyframes fade-in-out { 143 | 0% { 144 | opacity: 0; } 145 | 146 | 50% { 147 | opacity: 1; } 148 | 149 | 100% { 150 | opacity: 0; } } 151 | 152 | @-webkit-keyframes hover-change { 153 | 0% {color: cyan;} 154 | 25% {color: magenta;} 155 | 50% {color: yellow;} 156 | 100% {color: white;} } 157 | 158 | @-moz-keyframes hover-change { 159 | 0% {color: cyan;} 160 | 25% {color: magenta;} 161 | 50% {color: yellow;} 162 | 100% {color: white;} } 163 | 164 | @keyframes hover-change { 165 | 0% {color: cyan;} 166 | 25% {color: magenta;} 167 | 50% {color: yellow;} 168 | 100% {color: white;} } 169 | 170 | @-webkit-keyframes background-gradient-change { 171 | 0% {background: #cff;} 172 | 33% {background: #fcf;} 173 | 66% {background: #ffc;} 174 | 100% {background: #cff;}} 175 | 176 | @-moz-keyframes background-gradient-change { 177 | 0% {background: #dff;} 178 | 33% {background: #fdf;} 179 | 66% {background: #ffd;} 180 | 100% {background: #dff;}} 181 | 182 | @keyframes background-gradient-change { 183 | 0% {background: #dff;} 184 | 33% {background: #fdf;} 185 | 66% {background: #ffd;} 186 | 100% {background: #dff;}} 187 | 188 | a:hover { 189 | -webkit-animation: hover-change linear 0.1s infinite; 190 | -moz-animation: hover-change linear 0.1s infinite; 191 | animation: hover-change linear 0.1s infinite; 192 | } 193 | 194 | .scores-container { 195 | float: right; 196 | text-align: right; } 197 | 198 | .game-container .doge-says { 199 | position: fixed; 200 | top: 0; 201 | left: 0; 202 | z-index: 100;} 203 | .game-container .doge-says p { 204 | position:fixed; 205 | font-size: 60px; 206 | font-weight: bold; 207 | height: 60px; 208 | line-height: 60px; 209 | -webkit-animation: fade-in-out 600ms ease-in; 210 | -moz-animation: fade-in-out 600ms ease-in; 211 | animation: fade-in-out 600ms ease-in; 212 | -webkit-animation-fill-mode: both; 213 | -moz-animation-fill-mode: both; 214 | animation-fill-mode: both; } 215 | 216 | 217 | .info-container { 218 | position: relative; 219 | cursor:pointer; 220 | left:50%; 221 | margin-left:-32px; 222 | margin-bottom:10px;} 223 | 224 | .shout-out-container{ 225 | text-align:center; 226 | } 227 | .shout-out{ 228 | height:10px; 229 | line-height: 10px; 230 | background: #f0f; 231 | padding: 10px 10px; 232 | border-radius: 3px; 233 | display:inline-block; 234 | } 235 | 236 | .shout-out a{ 237 | font-weight: normal; 238 | height:10px; 239 | width:auto; 240 | text-decoration:none; 241 | color:#fff; 242 | } 243 | 244 | .info-container, .hide-info { 245 | display: inline-block; 246 | background: #f0f; 247 | padding: 10px 15px; 248 | height: 10px; 249 | line-height: 10px; 250 | font-size:10px; 251 | font-weight: bold; 252 | border-radius: 3px; 253 | color: white; 254 | margin-top: 8px; 255 | width: 36px; 256 | text-align: center; } 257 | .info-container a, .hide-info a{ 258 | color:#fff; 259 | text-decoration:none;} 260 | 261 | .game-container .info { 262 | display: none; 263 | position: absolute; 264 | overflow: scroll; 265 | top: 0; 266 | right: 0; 267 | bottom: 0; 268 | left: 0; 269 | background: rgba(255,255,255,0.9); 270 | z-index: 100; 271 | border-radius: 6px; 272 | text-align: center; 273 | /* -webkit-animation: fade-in 800ms ease; 274 | -moz-animation: fade-in 800ms ease; 275 | animation: fade-in 800ms ease;*/ 276 | -webkit-animation-fill-mode: both; 277 | -moz-animation-fill-mode: both; 278 | animation-fill-mode: both; } 279 | .game-container .info p { 280 | position:relative; 281 | font-size: 16px; 282 | padding:10px 20px 10px 20px; 283 | font-weight: bold;} 284 | 285 | .score-container, .best-container { 286 | position: relative; 287 | display: inline-block; 288 | background: #f0f; 289 | padding: 15px 25px; 290 | /* font-size: 25px;*/ 291 | height: 9px; 292 | line-height: 27px; 293 | font-weight: bold; 294 | border-radius: 3px; 295 | color: white; 296 | margin-top: 8px; 297 | text-align: center; } 298 | .score-container:after, .best-container:after { 299 | position: absolute; 300 | width: 100%; 301 | top: 10px; 302 | left: 0; 303 | text-transform: uppercase; 304 | font-size: 12px; 305 | line-height: 13px; 306 | text-align: center; 307 | color: #000; } 308 | .score-container .score-addition, .best-container .score-addition { 309 | position: absolute; 310 | right: 30px; 311 | font-size: 20px; 312 | line-height: 20px; 313 | color: rgba(119, 110, 101, 0.9); 314 | z-index: 100; 315 | -webkit-animation: move-up 600ms ease-in; 316 | -moz-animation: move-up 600ms ease-in; 317 | animation: move-up 600ms ease-in; 318 | -webkit-animation-fill-mode: both; 319 | -moz-animation-fill-mode: both; 320 | animation-fill-mode: both; } 321 | 322 | .score-container:after { 323 | content: "Score"; } 324 | 325 | .best-container:after { 326 | content: "Best"; } 327 | 328 | p { 329 | margin-top: 0; 330 | margin-bottom: 10px; 331 | line-height: 1.65; } 332 | 333 | a { 334 | color: #f0f; 335 | font-weight: bold; 336 | text-decoration: underline; 337 | cursor: pointer; } 338 | 339 | strong.important { 340 | text-transform: uppercase; } 341 | 342 | hr { 343 | border: none; 344 | border-bottom: 1px solid #d8d4d0; 345 | margin-top: 20px; 346 | margin-bottom: 30px; } 347 | 348 | .container { 349 | width: 500px; 350 | margin: 0 auto; } 351 | 352 | @-webkit-keyframes fade-in { 353 | 0% { 354 | opacity: 0; } 355 | 356 | 100% { 357 | opacity: 1; } } 358 | 359 | @-moz-keyframes fade-in { 360 | 0% { 361 | opacity: 0; } 362 | 363 | 100% { 364 | opacity: 1; } } 365 | 366 | @keyframes fade-in { 367 | 0% { 368 | opacity: 0; } 369 | 370 | 100% { 371 | opacity: 1; } } 372 | 373 | .game-container { 374 | margin-top: 10px; 375 | position: relative; 376 | padding: 15px; 377 | cursor: default; 378 | -webkit-touch-callout: none; 379 | -webkit-user-select: none; 380 | -moz-user-select: none; 381 | background: rgba(0,0,0,0.05); 382 | /* background: #a0a0a0;*/ 383 | border-radius: 6px; 384 | width: 500px; 385 | height: 500px; 386 | -webkit-box-sizing: border-box; 387 | -moz-box-sizing: border-box; 388 | box-sizing: border-box; } 389 | .game-container .game-message{ 390 | display: none; 391 | position: absolute; 392 | top: 0; 393 | right: 0; 394 | bottom: 0; 395 | left: 0; 396 | background: rgba(255,255,255,0.9); 397 | z-index: 100; 398 | text-align: center; 399 | -webkit-animation: fade-in 800ms ease 1200ms; 400 | -moz-animation: fade-in 800ms ease 1200ms; 401 | animation: fade-in 800ms ease 1200ms; 402 | -webkit-animation-fill-mode: both; 403 | -moz-animation-fill-mode: both; 404 | animation-fill-mode: both; } 405 | .game-container .game-message p { 406 | font-size: 60px; 407 | font-weight: bold; 408 | height: 60px; 409 | line-height: 60px; 410 | margin-top: 222px; } 411 | .game-container .game-message .lower { 412 | display: block; 413 | margin-top: 59px; } 414 | .game-container .game-message a { 415 | display: inline-block; 416 | background: #f0f; 417 | border-radius: 3px; 418 | padding: 0 20px; 419 | text-decoration: none; 420 | color: #f9f6f2; 421 | height: 40px; 422 | line-height: 42px; 423 | margin-left: 9px; } 424 | .game-container .game-message a.keep-playing-button { 425 | display: none; } 426 | .game-container .game-message.game-won { 427 | background: rgba(237, 194, 46, 0.5); 428 | color: #f9f6f2; } 429 | .game-container .game-message.game-won a.keep-playing-button { 430 | display: inline-block; } 431 | .game-container .game-message.game-won, .game-container .game-message.game-over { 432 | display: block; } 433 | 434 | .grid-container { 435 | position: absolute; 436 | z-index: 1; } 437 | 438 | .grid-row { 439 | margin-bottom: 15px; } 440 | .grid-row:last-child { 441 | margin-bottom: 0; } 442 | .grid-row:after { 443 | content: ""; 444 | display: block; 445 | clear: both; } 446 | 447 | .grid-cell { 448 | width: 106.25px; 449 | height: 106.25px; 450 | margin-right: 15px; 451 | float: left; 452 | border-radius: 3px; 453 | background: rgba(255,255,255,0.8); 454 | /* background: rgba(238, 228, 218, 0.35);*/ 455 | } 456 | .grid-cell:last-child { 457 | margin-right: 0; } 458 | 459 | .tile-container { 460 | position: absolute; 461 | z-index: 2; } 462 | 463 | .tile, .tile .tile-inner { 464 | width: 107px; 465 | height: 107px; 466 | -webkit-transform: translate3d(0, 0, 0); 467 | line-height: 116.25px; } 468 | .tile.tile-position-1-1 { 469 | -webkit-transform: translate(0px, 0px); 470 | -moz-transform: translate(0px, 0px); 471 | transform: translate(0px, 0px); } 472 | .tile.tile-position-1-2 { 473 | -webkit-transform: translate(0px, 121px); 474 | -moz-transform: translate(0px, 121px); 475 | transform: translate(0px, 121px); } 476 | .tile.tile-position-1-3 { 477 | -webkit-transform: translate(0px, 242px); 478 | -moz-transform: translate(0px, 242px); 479 | transform: translate(0px, 242px); } 480 | .tile.tile-position-1-4 { 481 | -webkit-transform: translate(0px, 363px); 482 | -moz-transform: translate(0px, 363px); 483 | transform: translate(0px, 363px); } 484 | .tile.tile-position-2-1 { 485 | -webkit-transform: translate(121px, 0px); 486 | -moz-transform: translate(121px, 0px); 487 | transform: translate(121px, 0px); } 488 | .tile.tile-position-2-2 { 489 | -webkit-transform: translate(121px, 121px); 490 | -moz-transform: translate(121px, 121px); 491 | transform: translate(121px, 121px); } 492 | .tile.tile-position-2-3 { 493 | -webkit-transform: translate(121px, 242px); 494 | -moz-transform: translate(121px, 242px); 495 | transform: translate(121px, 242px); } 496 | .tile.tile-position-2-4 { 497 | -webkit-transform: translate(121px, 363px); 498 | -moz-transform: translate(121px, 363px); 499 | transform: translate(121px, 363px); } 500 | .tile.tile-position-3-1 { 501 | -webkit-transform: translate(242px, 0px); 502 | -moz-transform: translate(242px, 0px); 503 | transform: translate(242px, 0px); } 504 | .tile.tile-position-3-2 { 505 | -webkit-transform: translate(242px, 121px); 506 | -moz-transform: translate(242px, 121px); 507 | transform: translate(242px, 121px); } 508 | .tile.tile-position-3-3 { 509 | -webkit-transform: translate(242px, 242px); 510 | -moz-transform: translate(242px, 242px); 511 | transform: translate(242px, 242px); } 512 | .tile.tile-position-3-4 { 513 | -webkit-transform: translate(242px, 363px); 514 | -moz-transform: translate(242px, 363px); 515 | transform: translate(242px, 363px); } 516 | .tile.tile-position-4-1 { 517 | -webkit-transform: translate(363px, 0px); 518 | -moz-transform: translate(363px, 0px); 519 | transform: translate(363px, 0px); } 520 | .tile.tile-position-4-2 { 521 | -webkit-transform: translate(363px, 121px); 522 | -moz-transform: translate(363px, 121px); 523 | transform: translate(363px, 121px); } 524 | .tile.tile-position-4-3 { 525 | -webkit-transform: translate(363px, 242px); 526 | -moz-transform: translate(363px, 242px); 527 | transform: translate(363px, 242px); } 528 | .tile.tile-position-4-4 { 529 | -webkit-transform: translate(363px, 363px); 530 | -moz-transform: translate(363px, 363px); 531 | transform: translate(363px, 363px); } 532 | 533 | .tile { 534 | color: rgba(0,0,0,0); 535 | position: absolute; 536 | -webkit-transition: 100ms ease-in-out; 537 | -moz-transition: 100ms ease-in-out; 538 | transition: 100ms ease-in-out; 539 | -webkit-transition-property: -webkit-transform; 540 | -moz-transition-property: -moz-transform; 541 | transition-property: transform; } 542 | .tile .tile-inner { 543 | border-radius: 3px; 544 | background: #eee4da; 545 | text-align: center; 546 | font-weight: bold; 547 | z-index: 10; 548 | font-size: 55px; } 549 | .tile.tile-2 .tile-inner { 550 | background: #f0f url('../img/212/doge-wink-212.gif'); 551 | background-size: cover; 552 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } 553 | 554 | .tile.tile-4 .tile-inner { 555 | background: #f0f url('../img/212/doge-shake-space-212.gif'); 556 | background-size: cover; 557 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } 558 | 559 | .tile.tile-8 .tile-inner { 560 | background: #f0f url('../img/212/doge-peepers-212.gif'); 561 | background-size: cover;} 562 | 563 | .tile.tile-16 .tile-inner { 564 | background: #f0f url('../img/212/doge-prizza-212.gif'); 565 | background-size: cover;} 566 | 567 | .tile.tile-32 .tile-inner { 568 | background: #f0f url('../img/212/doge-hat-212.gif'); 569 | background-size: cover;} 570 | 571 | .tile.tile-64 .tile-inner { 572 | background: #f0f url('../img/212/doge-gradient-212.gif'); 573 | background-size: cover;} 574 | 575 | .tile.tile-128 .tile-inner { 576 | background: #f0f url('../img/212/doge-fat-212.gif'); 577 | background-size: cover; 578 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.2381), inset 0 0 0 1px rgba(255, 255, 255, 0.14286); 579 | font-size: 45px; } 580 | @media screen and (max-width: 480px) { 581 | .tile.tile-128 .tile-inner { 582 | font-size: 25px; } } 583 | .tile.tile-256 .tile-inner { 584 | 585 | background: #f0f url('../img/212/doge-rainbow-212.gif'); 586 | background-size: cover; 587 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.19048); 588 | font-size: 45px; } 589 | @media screen and (max-width: 480px) { 590 | .tile.tile-256 .tile-inner { 591 | font-size: 25px; } } 592 | .tile.tile-512 .tile-inner { 593 | 594 | background: #f0f url('../img/212/doge-sunglasses-212.gif'); 595 | background-size: cover; 596 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.39683), inset 0 0 0 1px rgba(255, 255, 255, 0.2381); 597 | font-size: 45px; } 598 | @media screen and (max-width: 480px) { 599 | .tile.tile-512 .tile-inner { 600 | font-size: 25px; } } 601 | .tile.tile-1024 .tile-inner { 602 | background: #f0f url('../img/212/doge-derp-212.gif'); 603 | background-size: cover; 604 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.28571); 605 | font-size: 35px; } 606 | @media screen and (max-width: 480px) { 607 | .tile.tile-1024 .tile-inner { 608 | font-size: 15px; } } 609 | .tile.tile-2048 .tile-inner { 610 | 611 | background: #f0f url('../img/212/doge-shake-212.gif'); 612 | background-size: cover; 613 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.55556), inset 0 0 0 1px rgba(255, 255, 255, 0.33333); 614 | font-size: 35px; } 615 | @media screen and (max-width: 480px) { 616 | .tile.tile-2048 .tile-inner { 617 | font-size: 15px; } } 618 | .tile.tile-super .tile-inner { 619 | 620 | background: #f0f url('../img/212/doge-derp-212.gif'); 621 | background-size: cover; 622 | font-size: 30px; } 623 | @media screen and (max-width: 480px) { 624 | .tile.tile-super .tile-inner { 625 | font-size: 10px; } } 626 | 627 | @-webkit-keyframes appear { 628 | 0% { 629 | opacity: 0; 630 | -webkit-transform: scale(0); 631 | -moz-transform: scale(0); 632 | transform: scale(0); } 633 | 634 | 100% { 635 | opacity: 1; 636 | -webkit-transform: scale(1); 637 | -moz-transform: scale(1); 638 | transform: scale(1); } } 639 | 640 | @-moz-keyframes appear { 641 | 0% { 642 | opacity: 0; 643 | -webkit-transform: scale(0); 644 | -moz-transform: scale(0); 645 | transform: scale(0); } 646 | 647 | 100% { 648 | opacity: 1; 649 | -webkit-transform: scale(1); 650 | -moz-transform: scale(1); 651 | transform: scale(1); } } 652 | 653 | @keyframes appear { 654 | 0% { 655 | opacity: 0; 656 | -webkit-transform: scale(0); 657 | -moz-transform: scale(0); 658 | transform: scale(0); } 659 | 660 | 100% { 661 | opacity: 1; 662 | -webkit-transform: scale(1); 663 | -moz-transform: scale(1); 664 | transform: scale(1); } } 665 | 666 | .tile-new .tile-inner { 667 | -webkit-animation: appear 200ms ease 100ms; 668 | -moz-animation: appear 200ms ease 100ms; 669 | animation: appear 200ms ease 100ms; 670 | -webkit-animation-fill-mode: backwards; 671 | -moz-animation-fill-mode: backwards; 672 | animation-fill-mode: backwards; } 673 | 674 | @-webkit-keyframes pop { 675 | 0% { 676 | -webkit-transform: scale(0); 677 | -moz-transform: scale(0); 678 | transform: scale(0); } 679 | 680 | 50% { 681 | -webkit-transform: scale(1.2); 682 | -moz-transform: scale(1.2); 683 | transform: scale(1.2); } 684 | 685 | 100% { 686 | -webkit-transform: scale(1); 687 | -moz-transform: scale(1); 688 | transform: scale(1); } } 689 | 690 | @-moz-keyframes pop { 691 | 0% { 692 | -webkit-transform: scale(0); 693 | -moz-transform: scale(0); 694 | transform: scale(0); } 695 | 696 | 50% { 697 | -webkit-transform: scale(1.2); 698 | -moz-transform: scale(1.2); 699 | transform: scale(1.2); } 700 | 701 | 100% { 702 | -webkit-transform: scale(1); 703 | -moz-transform: scale(1); 704 | transform: scale(1); } } 705 | 706 | @keyframes pop { 707 | 0% { 708 | -webkit-transform: scale(0); 709 | -moz-transform: scale(0); 710 | transform: scale(0); } 711 | 712 | 50% { 713 | -webkit-transform: scale(1.2); 714 | -moz-transform: scale(1.2); 715 | transform: scale(1.2); } 716 | 717 | 100% { 718 | -webkit-transform: scale(1); 719 | -moz-transform: scale(1); 720 | transform: scale(1); } } 721 | 722 | .tile-merged .tile-inner { 723 | z-index: 20; 724 | -webkit-animation: pop 200ms ease 100ms; 725 | -moz-animation: pop 200ms ease 100ms; 726 | animation: pop 200ms ease 100ms; 727 | -webkit-animation-fill-mode: backwards; 728 | -moz-animation-fill-mode: backwards; 729 | animation-fill-mode: backwards; } 730 | 731 | .game-intro { 732 | margin-bottom: 0; } 733 | 734 | .game-explanation, .shout-out { 735 | margin-top: 0px; 736 | text-align: center; 737 | font-size: 14px;} 738 | 739 | 740 | 741 | @media screen and (max-width: 480px) { 742 | html, body { 743 | font-size: 15px; } 744 | 745 | body { 746 | margin: 20px 0; 747 | padding: 0 20px; } 748 | 749 | .modal{ 750 | width:280px;} 751 | 752 | h1.title { 753 | font-size: 25px; 754 | margin-top: 15px; } 755 | 756 | .container { 757 | width: 280px; 758 | margin: 0 auto; } 759 | 760 | .score-container, .best-container { 761 | margin-top: 0; 762 | padding: 15px 10px; 763 | min-width: 40px; } 764 | 765 | .heading { 766 | margin-bottom: 10px; } 767 | 768 | .game-explanation { 769 | display:none;} 770 | 771 | .shout-out, .game-explanation{ 772 | margin-top:10px; 773 | height:0; 774 | padding-top:10px; 775 | padding-bottom:20px; 776 | /* font-size:12px;*/ 777 | } 778 | 779 | .game-container { 780 | margin-top: 40px; 781 | position: relative; 782 | padding: 10px; 783 | cursor: default; 784 | -webkit-touch-callout: none; 785 | -webkit-user-select: none; 786 | -moz-user-select: none; 787 | border-radius: 6px; 788 | width: 280px; 789 | height: 280px; 790 | -webkit-box-sizing: border-box; 791 | -moz-box-sizing: border-box; 792 | box-sizing: border-box; } 793 | .game-container .game-message { 794 | display: none; 795 | position: absolute; 796 | top: 0; 797 | right: 0; 798 | bottom: 0; 799 | left: 0; 800 | z-index: 100; 801 | text-align: center; 802 | -webkit-animation: fade-in 800ms ease; 803 | -moz-animation: fade-in 800ms ease; 804 | animation: fade-in 800ms ease; 805 | -webkit-animation-fill-mode: both; 806 | -moz-animation-fill-mode: both; 807 | animation-fill-mode: both; } 808 | .game-container .game-message p { 809 | font-size: 60px; 810 | font-weight: bold; 811 | height: 60px; 812 | line-height: 60px; 813 | margin-top: 222px; } 814 | .game-container .game-message .lower { 815 | display: block; 816 | margin-top: 59px; } 817 | .game-container .game-message a { 818 | display: inline-block; 819 | border-radius: 3px; 820 | padding: 0 20px; 821 | text-decoration: none; 822 | height: 40px; 823 | line-height: 42px; 824 | margin-left: 9px; } 825 | .game-container .game-message a.keep-playing-button { 826 | display: none; } 827 | .game-container .game-message.game-won { 828 | background: rgba(237, 194, 46, 0.5);} 829 | .game-container .game-message.game-won a.keep-playing-button { 830 | display: inline-block; } 831 | .game-container .game-message.game-won, .game-container .game-message.game-over { 832 | display: block; } 833 | 834 | .grid-container { 835 | position: absolute; 836 | z-index: 1; } 837 | 838 | .grid-row { 839 | margin-bottom: 10px; } 840 | .grid-row:last-child { 841 | margin-bottom: 0; } 842 | .grid-row:after { 843 | content: ""; 844 | display: block; 845 | clear: both; } 846 | 847 | .grid-cell { 848 | width: 57.5px; 849 | height: 57.5px; 850 | margin-right: 10px; 851 | float: left; 852 | border-radius: 3px;} 853 | .grid-cell:last-child { 854 | margin-right: 0; } 855 | 856 | .tile-container { 857 | position: absolute; 858 | z-index: 2; } 859 | 860 | .tile, .tile .tile-inner { 861 | width: 58px; 862 | height: 58px; 863 | line-height: 67.5px; } 864 | .tile.tile-position-1-1 { 865 | -webkit-transform: translate(0px, 0px); 866 | -moz-transform: translate(0px, 0px); 867 | transform: translate(0px, 0px); } 868 | .tile.tile-position-1-2 { 869 | -webkit-transform: translate(0px, 67px); 870 | -moz-transform: translate(0px, 67px); 871 | transform: translate(0px, 67px); } 872 | .tile.tile-position-1-3 { 873 | -webkit-transform: translate(0px, 135px); 874 | -moz-transform: translate(0px, 135px); 875 | transform: translate(0px, 135px); } 876 | .tile.tile-position-1-4 { 877 | -webkit-transform: translate(0px, 202px); 878 | -moz-transform: translate(0px, 202px); 879 | transform: translate(0px, 202px); } 880 | .tile.tile-position-2-1 { 881 | -webkit-transform: translate(67px, 0px); 882 | -moz-transform: translate(67px, 0px); 883 | transform: translate(67px, 0px); } 884 | .tile.tile-position-2-2 { 885 | -webkit-transform: translate(67px, 67px); 886 | -moz-transform: translate(67px, 67px); 887 | transform: translate(67px, 67px); } 888 | .tile.tile-position-2-3 { 889 | -webkit-transform: translate(67px, 135px); 890 | -moz-transform: translate(67px, 135px); 891 | transform: translate(67px, 135px); } 892 | .tile.tile-position-2-4 { 893 | -webkit-transform: translate(67px, 202px); 894 | -moz-transform: translate(67px, 202px); 895 | transform: translate(67px, 202px); } 896 | .tile.tile-position-3-1 { 897 | -webkit-transform: translate(135px, 0px); 898 | -moz-transform: translate(135px, 0px); 899 | transform: translate(135px, 0px); } 900 | .tile.tile-position-3-2 { 901 | -webkit-transform: translate(135px, 67px); 902 | -moz-transform: translate(135px, 67px); 903 | transform: translate(135px, 67px); } 904 | .tile.tile-position-3-3 { 905 | -webkit-transform: translate(135px, 135px); 906 | -moz-transform: translate(135px, 135px); 907 | transform: translate(135px, 135px); } 908 | .tile.tile-position-3-4 { 909 | -webkit-transform: translate(135px, 202px); 910 | -moz-transform: translate(135px, 202px); 911 | transform: translate(135px, 202px); } 912 | .tile.tile-position-4-1 { 913 | -webkit-transform: translate(202px, 0px); 914 | -moz-transform: translate(202px, 0px); 915 | transform: translate(202px, 0px); } 916 | .tile.tile-position-4-2 { 917 | -webkit-transform: translate(202px, 67px); 918 | -moz-transform: translate(202px, 67px); 919 | transform: translate(202px, 67px); } 920 | .tile.tile-position-4-3 { 921 | -webkit-transform: translate(202px, 135px); 922 | -moz-transform: translate(202px, 135px); 923 | transform: translate(202px, 135px); } 924 | .tile.tile-position-4-4 { 925 | -webkit-transform: translate(202px, 202px); 926 | -moz-transform: translate(202px, 202px); 927 | transform: translate(202px, 202px); } 928 | 929 | .tile.tile-2 .tile-inner { 930 | background: #f0f url('../img/114/doge-wink-114.gif'); 931 | background-size: cover; 932 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } 933 | 934 | .tile.tile-4 .tile-inner { 935 | background: #f0f url('../img/114/doge-shake-space-114.gif'); 936 | background-size: cover; 937 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } 938 | 939 | .tile.tile-8 .tile-inner { 940 | background: #f0f url('../img/114/doge-peepers-114.gif'); 941 | background-size: cover;} 942 | 943 | .tile.tile-16 .tile-inner { 944 | background: #f0f url('../img/114/doge-prizza-114.gif'); 945 | background-size: cover;} 946 | 947 | .tile.tile-32 .tile-inner { 948 | background: #f0f url('../img/114/doge-hat-114.gif'); 949 | background-size: cover;} 950 | 951 | .tile.tile-64 .tile-inner { 952 | background: #f0f url('../img/114/doge-gradient-114.gif'); 953 | background-size: cover;} 954 | 955 | .tile.tile-128 .tile-inner { 956 | background: #f0f url('../img/114/doge-fat-114.gif'); 957 | background-size: cover; 958 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.2381), inset 0 0 0 1px rgba(255, 255, 255, 0.14286); 959 | font-size: 45px; } 960 | @media screen and (max-width: 480px) { 961 | .tile.tile-128 .tile-inner { 962 | font-size: 25px; } } 963 | .tile.tile-256 .tile-inner { 964 | 965 | background: #f0f url('../img/114/doge-rainbow-114.gif'); 966 | background-size: cover; 967 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.19048); 968 | font-size: 45px; } 969 | @media screen and (max-width: 480px) { 970 | .tile.tile-256 .tile-inner { 971 | font-size: 25px; } } 972 | .tile.tile-512 .tile-inner { 973 | 974 | background: #f0f url('../img/114/doge-sunglasses-114.gif'); 975 | background-size: cover; 976 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.39683), inset 0 0 0 1px rgba(255, 255, 255, 0.2381); 977 | font-size: 45px; } 978 | @media screen and (max-width: 480px) { 979 | .tile.tile-512 .tile-inner { 980 | font-size: 25px; } } 981 | .tile.tile-1024 .tile-inner { 982 | background: #f0f url('../img/114/doge-derp-114.gif'); 983 | background-size: cover; 984 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.28571); 985 | font-size: 35px; } 986 | @media screen and (max-width: 480px) { 987 | .tile.tile-1024 .tile-inner { 988 | font-size: 15px; } } 989 | .tile.tile-2048 .tile-inner { 990 | 991 | background: #f0f url('../img/114/doge-shake-114.gif'); 992 | background-size: cover; 993 | box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.55556), inset 0 0 0 1px rgba(255, 255, 255, 0.33333); 994 | font-size: 35px; } 995 | @media screen and (max-width: 480px) { 996 | .tile.tile-2048 .tile-inner { 997 | font-size: 15px; } } 998 | .tile.tile-super .tile-inner { 999 | 1000 | background: #f0f url('../img/114/doge-derp-114.gif'); 1001 | background-size: cover; 1002 | font-size: 30px; } 1003 | @media screen and (max-width: 480px) { 1004 | .tile.tile-super .tile-inner { 1005 | font-size: 10px; } } 1006 | 1007 | 1008 | .footer{ 1009 | width:188px;} 1010 | 1011 | #twitter-widget-0 { 1012 | position: relative; 1013 | top:5px; 1014 | } 1015 | 1016 | .COINWIDGETCOM_CONTAINER { 1017 | display:none !important; 1018 | } 1019 | 1020 | .game-container .info p { 1021 | font-size: 12px; 1022 | padding:5px 10px 5px 10px; 1023 | } 1024 | 1025 | .game-container { 1026 | margin-top: 20px; } 1027 | 1028 | .tile .tile-inner { 1029 | font-size: 35px; } 1030 | 1031 | .doge-says p { 1032 | font-size: 30px !important; 1033 | height: 30px !important; 1034 | line-height: 30px !important;} 1035 | 1036 | .game-message p { 1037 | font-size: 30px !important; 1038 | height: 30px !important; 1039 | line-height: 30px !important; 1040 | margin-top: 90px !important; } 1041 | .game-message .lower { 1042 | margin-top: 30px !important; } } 1043 | --------------------------------------------------------------------------------