From 02a24c0610c56da8a3e7e0ed3790f252a760e9c9 Mon Sep 17 00:00:00 2001 From: Mark Frederiksen Date: Tue, 18 Mar 2014 14:48:55 -0400 Subject: [PATCH 01/12] Added persistence of game state to localstorage after each move Added rebuilding of game state from localstoage on page load Added New Game button to allow game restarts now that refreshes resume the game --- index.html | 2 +- js/game_manager.js | 47 +++++++++++++++++++++++++++--------- js/grid.js | 42 ++++++++++++++++++++++++++------ js/keyboard_input_manager.js | 4 +++ js/local_score_manager.js | 23 ++++++++++++++---- js/tile.js | 10 ++++++++ style/main.css | 16 ++++++++++-- style/main.scss | 9 ++++++- 8 files changed, 125 insertions(+), 28 deletions(-) diff --git a/index.html b/index.html index cbcfe65..29138a6 100644 --- a/index.html +++ b/index.html @@ -23,7 +23,7 @@

Join the numbers and get to the 2048 tile!

- + New Game

diff --git a/js/game_manager.js b/js/game_manager.js index b36aea3..da55aba 100644 --- a/js/game_manager.js +++ b/js/game_manager.js @@ -1,7 +1,7 @@ -function GameManager(size, InputManager, Actuator, ScoreManager) { +function GameManager(size, InputManager, Actuator, StorageManager) { this.size = size; // Size of the grid this.inputManager = new InputManager; - this.scoreManager = new ScoreManager; + this.storageManager = new StorageManager; this.actuator = new Actuator; this.startTiles = 2; @@ -15,6 +15,7 @@ function GameManager(size, InputManager, Actuator, ScoreManager) { // Restart the game GameManager.prototype.restart = function () { + this.storageManager.clearGameState(); this.actuator.continue(); this.setup(); }; @@ -35,15 +36,24 @@ GameManager.prototype.isGameTerminated = function () { // Set up the game GameManager.prototype.setup = function () { - this.grid = new Grid(this.size); + var previousGameState = this.storageManager.getGameState(); - this.score = 0; - this.over = false; - this.won = false; - this.keepPlaying = false; + if (previousGameState) { + this.grid = new Grid(previousGameState.grid.size, previousGameState.grid.cells); + this.score = previousGameState.score; + this.over = previousGameState.over; + this.won = previousGameState.won; + this.keepPlaying = previousGameState.keepPlaying; + } else { + this.grid = new Grid(this.size); + this.score = 0; + this.over = false; + this.won = false; + this.keepPlaying = false; - // Add the initial tiles - this.addStartTiles(); + // Add the initial tiles + this.addStartTiles(); + } // Update the actuator this.actuate(); @@ -68,20 +78,33 @@ GameManager.prototype.addRandomTile = function () { // Sends the updated grid to the actuator GameManager.prototype.actuate = function () { - if (this.scoreManager.get() < this.score) { - this.scoreManager.set(this.score); + if (this.storageManager.getBestScore() < this.score) { + this.storageManager.setBestScore(this.score); } + this.storageManager.setGameState(this.serializeGameState()); + this.actuator.actuate(this.grid, { score: this.score, over: this.over, won: this.won, - bestScore: this.scoreManager.get(), + bestScore: this.storageManager.getBestScore(), terminated: this.isGameTerminated() }); }; +GameManager.prototype.serializeGameState = function () { + return { + size: this.size, + grid: this.grid.gridState(), + score: this.score, + over: this.over, + won: this.won, + keepPlaying: this.keepPlaying + }; +} + // Save all tile positions and remove merger info GameManager.prototype.prepareTiles = function () { this.grid.eachCell(function (x, y, tile) { diff --git a/js/grid.js b/js/grid.js index 05fe057..a2215a7 100644 --- a/js/grid.js +++ b/js/grid.js @@ -1,20 +1,32 @@ -function Grid(size) { +function Grid(size, previousCellState) { this.size = size; - - this.cells = []; - - this.build(); + this.cells = previousCellState ? this.buildFromPreviousState(previousCellState) : this.buildNew(); } // Build a grid of the specified size -Grid.prototype.build = function () { +Grid.prototype.buildNew = function () { + var cells = []; for (var x = 0; x < this.size; x++) { - var row = this.cells[x] = []; + var row = cells[x] = []; for (var y = 0; y < this.size; y++) { row.push(null); } } + return cells; +}; + +Grid.prototype.buildFromPreviousState = function (state) { + var cells = []; + for (var x = 0; x < this.size; x++) { + var row = cells[x] = []; + + for (var y = 0; y < this.size; y++) { + var tileState = state[x][y]; + row.push(tileState ? new Tile(tileState.position, tileState.value) : null); + } + } + return cells; }; // Find the first available random position @@ -82,3 +94,19 @@ Grid.prototype.withinBounds = function (position) { return position.x >= 0 && position.x < this.size && position.y >= 0 && position.y < this.size; }; + +Grid.prototype.gridState = function () { + var cellState = []; + for (var x = 0; x < this.size; x++) { + var row = cellState[x] = []; + + for (var y = 0; y < this.size; y++) { + row.push(this.cells[x][y] ? this.cells[x][y].tileState() : null); + } + } + + return { + size: this.size, + cells: cellState + } +}; diff --git a/js/keyboard_input_manager.js b/js/keyboard_input_manager.js index 822cc3b..78bb337 100644 --- a/js/keyboard_input_manager.js +++ b/js/keyboard_input_manager.js @@ -57,6 +57,10 @@ KeyboardInputManager.prototype.listen = function () { retry.addEventListener("click", this.restart.bind(this)); retry.addEventListener("touchend", this.restart.bind(this)); + var restart = document.querySelector(".restart-button"); + restart.addEventListener("click", this.restart.bind(this)); + restart.addEventListener("touchend", this.restart.bind(this)); + var keepPlaying = document.querySelector(".keep-playing-button"); keepPlaying.addEventListener("click", this.keepPlaying.bind(this)); keepPlaying.addEventListener("touchend", this.keepPlaying.bind(this)); diff --git a/js/local_score_manager.js b/js/local_score_manager.js index ec4575d..0f37ec2 100644 --- a/js/local_score_manager.js +++ b/js/local_score_manager.js @@ -19,7 +19,8 @@ window.fakeStorage = { }; function LocalScoreManager() { - this.key = "bestScore"; + this.bestScoreKey = "bestScore"; + this.gameStateKey = "gameState"; var supported = this.localStorageSupported(); this.storage = supported ? window.localStorage : window.fakeStorage; @@ -38,11 +39,23 @@ LocalScoreManager.prototype.localStorageSupported = function () { } }; -LocalScoreManager.prototype.get = function () { - return this.storage.getItem(this.key) || 0; +LocalScoreManager.prototype.getBestScore = function () { + return this.storage.getItem(this.bestScoreKey) || 0; }; -LocalScoreManager.prototype.set = function (score) { - this.storage.setItem(this.key, score); +LocalScoreManager.prototype.setBestScore = function (score) { + this.storage.setItem(this.bestScoreKey, score); }; +LocalScoreManager.prototype.getGameState = function () { + var stateJSON = this.storage.getItem(this.gameStateKey); + return stateJSON ? JSON.parse(stateJSON) : null; +}; + +LocalScoreManager.prototype.setGameState = function (gameState) { + this.storage.setItem(this.gameStateKey, JSON.stringify(gameState)); +}; + +LocalScoreManager.prototype.clearGameState = function () { + this.storage.removeItem(this.gameStateKey); +}; diff --git a/js/tile.js b/js/tile.js index de08333..f124073 100644 --- a/js/tile.js +++ b/js/tile.js @@ -15,3 +15,13 @@ Tile.prototype.updatePosition = function (position) { this.x = position.x; this.y = position.y; }; + +Tile.prototype.tileState = function () { + return { + position: { + x: this.x, + y: this.y + }, + value: this.value + }; +} \ No newline at end of file diff --git a/style/main.css b/style/main.css index f8a856a..aba319b 100644 --- a/style/main.css +++ b/style/main.css @@ -143,8 +143,21 @@ hr { 100% { opacity: 1; } } +.restart-button { + display: inline-block; + background: #8f7a66; + border-radius: 3px; + padding: 0 20px; + text-decoration: none; + color: #f9f6f2; + height: 40px; + line-height: 42px; + display: block; + width: 100px; + margin: 10px auto 10px auto; + text-align: center; } + .game-container { - margin-top: 40px; position: relative; padding: 15px; cursor: default; @@ -515,7 +528,6 @@ hr { margin-bottom: 10px; } .game-container { - margin-top: 40px; position: relative; padding: 10px; cursor: default; diff --git a/style/main.scss b/style/main.scss index 1ec515e..aa04aeb 100644 --- a/style/main.scss +++ b/style/main.scss @@ -168,10 +168,17 @@ hr { line-height: 42px; } +.restart-button { + @include button; + display: block; + width: 100px; + margin: 10px auto 10px auto; + text-align: center; +} + // Game field mixin used to render CSS at different width @mixin game-field { .game-container { - margin-top: 40px; position: relative; padding: $grid-spacing; From 9ca6e3c788174701a9c423261049fa0f5e7914be Mon Sep 17 00:00:00 2001 From: "Maciej A. Czyzewski" Date: Thu, 20 Mar 2014 22:01:34 +0100 Subject: [PATCH 02/12] Update README.md, centered screenshot! I think screenshot is better when it is centered. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 96a85a7..e7cfd89 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ Many thanks to [rayhaanj](https://github.com/rayhaanj), [Mechazawa](https://gith ### Screenshot -[![Screenshot](http://pictures.gabrielecirulli.com/2048-20140309-234100.png)](http://pictures.gabrielecirulli.com/2048-20140309-234100.png) +

+ Screenshot +

That screenshot is fake, by the way. I never reached 2048 :smile: From 6c12037b2a090ed0f1bd7ab1738637810f98da46 Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Fri, 21 Mar 2014 15:33:51 +0100 Subject: [PATCH 03/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e7cfd89..19c6d0e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Many thanks to [rayhaanj](https://github.com/rayhaanj), [Mechazawa](https://gith ### Screenshot

- Screenshot + Screenshot

That screenshot is fake, by the way. I never reached 2048 :smile: From 08c50df9386e4003a76a5fb03a3941516531403f Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 15:38:52 +0100 Subject: [PATCH 04/12] rename LocalScoreManager to LocalStorageManager --- index.html | 2 +- js/application.js | 2 +- ...re_manager.js => local_storage_manager.js} | 22 +++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) rename js/{local_score_manager.js => local_storage_manager.js} (57%) diff --git a/index.html b/index.html index 29138a6..14ec922 100644 --- a/index.html +++ b/index.html @@ -83,7 +83,7 @@ - + diff --git a/js/application.js b/js/application.js index a4d310a..2c1108e 100644 --- a/js/application.js +++ b/js/application.js @@ -1,4 +1,4 @@ // Wait till the browser is ready to render the game (avoids glitches) window.requestAnimationFrame(function () { - new GameManager(4, KeyboardInputManager, HTMLActuator, LocalScoreManager); + new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager); }); diff --git a/js/local_score_manager.js b/js/local_storage_manager.js similarity index 57% rename from js/local_score_manager.js rename to js/local_storage_manager.js index 0f37ec2..74e5ee8 100644 --- a/js/local_score_manager.js +++ b/js/local_storage_manager.js @@ -18,7 +18,7 @@ window.fakeStorage = { } }; -function LocalScoreManager() { +function LocalStorageManager() { this.bestScoreKey = "bestScore"; this.gameStateKey = "gameState"; @@ -26,7 +26,7 @@ function LocalScoreManager() { this.storage = supported ? window.localStorage : window.fakeStorage; } -LocalScoreManager.prototype.localStorageSupported = function () { +LocalStorageManager.prototype.localStorageSupported = function () { var testKey = "test"; var storage = window.localStorage; @@ -39,23 +39,23 @@ LocalScoreManager.prototype.localStorageSupported = function () { } }; -LocalScoreManager.prototype.getBestScore = function () { +LocalStorageManager.prototype.getBestScore = function () { return this.storage.getItem(this.bestScoreKey) || 0; }; -LocalScoreManager.prototype.setBestScore = function (score) { +LocalStorageManager.prototype.setBestScore = function (score) { this.storage.setItem(this.bestScoreKey, score); }; -LocalScoreManager.prototype.getGameState = function () { - var stateJSON = this.storage.getItem(this.gameStateKey); - return stateJSON ? JSON.parse(stateJSON) : null; +LocalStorageManager.prototype.getGameState = function () { + var stateJSON = this.storage.getItem(this.gameStateKey); + return stateJSON ? JSON.parse(stateJSON) : null; }; -LocalScoreManager.prototype.setGameState = function (gameState) { - this.storage.setItem(this.gameStateKey, JSON.stringify(gameState)); +LocalStorageManager.prototype.setGameState = function (gameState) { + this.storage.setItem(this.gameStateKey, JSON.stringify(gameState)); }; -LocalScoreManager.prototype.clearGameState = function () { - this.storage.removeItem(this.gameStateKey); +LocalStorageManager.prototype.clearGameState = function () { + this.storage.removeItem(this.gameStateKey); }; From 4d294cf9b93056a3f8910fcc061f1dad18b67398 Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 16:11:19 +0100 Subject: [PATCH 05/12] remove space to restart game, refactor code slightly --- index.html | 2 +- js/keyboard_input_manager.js | 71 +++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/index.html b/index.html index 14ec922..557b68e 100644 --- a/index.html +++ b/index.html @@ -22,7 +22,7 @@
0
-

Join the numbers and get to the 2048 tile!

+

Join the numbers and get the 2048 tile!

New Game
diff --git a/js/keyboard_input_manager.js b/js/keyboard_input_manager.js index cf67028..4f2e856 100644 --- a/js/keyboard_input_manager.js +++ b/js/keyboard_input_manager.js @@ -39,16 +39,17 @@ KeyboardInputManager.prototype.listen = function () { 39: 1, // Right 40: 2, // Down 37: 3, // Left - 75: 0, // vim keybindings - 76: 1, - 74: 2, - 72: 3, + 75: 0, // Vim up + 76: 1, // Vim right + 74: 2, // Vim down + 72: 3, // Vim left 87: 0, // W 68: 1, // D 83: 2, // S 65: 3 // A }; + // Respond to direction keys document.addEventListener("keydown", function (event) { var modifiers = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; @@ -59,38 +60,32 @@ KeyboardInputManager.prototype.listen = function () { event.preventDefault(); self.emit("move", mapped); } - - if (event.which === 32) self.restart.bind(self)(event); } }); - var retry = document.querySelector(".retry-button"); - retry.addEventListener("click", this.restart.bind(this)); - retry.addEventListener(this.eventTouchend, this.restart.bind(this)); + // Respond to button presses + this.bindButtonPress(".retry-button", this.restart); + this.bindButtonPress(".restart-button", this.restart); + this.bindButtonPress(".keep-playing-button", this.keepPlaying); - var restart = document.querySelector(".restart-button"); - restart.addEventListener("click", this.restart.bind(this)); - restart.addEventListener("touchend", this.restart.bind(this)); - - var keepPlaying = document.querySelector(".keep-playing-button"); - keepPlaying.addEventListener("click", this.keepPlaying.bind(this)); - keepPlaying.addEventListener("touchend", this.keepPlaying.bind(this)); - - // Listen to swipe events + // Respond to swipe events var touchStartClientX, touchStartClientY; var gameContainer = document.getElementsByClassName("game-container")[0]; gameContainer.addEventListener(this.eventTouchstart, function (event) { - if (( !window.navigator.msPointerEnabled && event.touches.length > 1) || event.targetTouches > 1) return; - - if(window.navigator.msPointerEnabled){ - touchStartClientX = event.pageX; - touchStartClientY = event.pageY; - } else { - touchStartClientX = event.touches[0].clientX; - touchStartClientY = event.touches[0].clientY; + if ((!window.navigator.msPointerEnabled && event.touches.length > 1) || + event.targetTouches > 1) { + return; // Ignore if touching with more than 1 finger } - + + if (window.navigator.msPointerEnabled) { + touchStartClientX = event.pageX; + touchStartClientY = event.pageY; + } else { + touchStartClientX = event.touches[0].clientX; + touchStartClientY = event.touches[0].clientY; + } + event.preventDefault(); }); @@ -99,15 +94,19 @@ KeyboardInputManager.prototype.listen = function () { }); gameContainer.addEventListener(this.eventTouchend, function (event) { - if (( !window.navigator.msPointerEnabled && event.touches.length > 0) || event.targetTouches > 0) return; + if ((!window.navigator.msPointerEnabled && event.touches.length > 0) || + event.targetTouches > 0) { + return; // Ignore if still touching with one or more fingers + } var touchEndClientX, touchEndClientY; - if(window.navigator.msPointerEnabled){ - touchEndClientX = event.pageX; - touchEndClientY = event.pageY; + + if (window.navigator.msPointerEnabled) { + touchEndClientX = event.pageX; + touchEndClientY = event.pageY; } else { - touchEndClientX = event.changedTouches[0].clientX; - touchEndClientY = event.changedTouches[0].clientY; + touchEndClientX = event.changedTouches[0].clientX; + touchEndClientY = event.changedTouches[0].clientY; } var dx = touchEndClientX - touchStartClientX; @@ -132,3 +131,9 @@ KeyboardInputManager.prototype.keepPlaying = function (event) { event.preventDefault(); this.emit("keepPlaying"); }; + +KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) { + var button = document.querySelector(selector); + button.addEventListener("click", fn.bind(this)); + button.addEventListener(this.eventTouchend, fn.bind(this)); +}; From c48b92689dd232656b669e13c982e1d74bf753bf Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 16:24:11 +0100 Subject: [PATCH 06/12] refactor grid, gamemanager, tile --- js/game_manager.js | 51 +++++++++++++++++++++++----------------------- js/grid.js | 39 +++++++++++++++++++---------------- js/tile.js | 18 ++++++++-------- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/js/game_manager.js b/js/game_manager.js index da55aba..49b903a 100644 --- a/js/game_manager.js +++ b/js/game_manager.js @@ -36,23 +36,24 @@ GameManager.prototype.isGameTerminated = function () { // Set up the game GameManager.prototype.setup = function () { - var previousGameState = this.storageManager.getGameState(); + var previousState = this.storageManager.getGameState(); - if (previousGameState) { - this.grid = new Grid(previousGameState.grid.size, previousGameState.grid.cells); - this.score = previousGameState.score; - this.over = previousGameState.over; - this.won = previousGameState.won; - this.keepPlaying = previousGameState.keepPlaying; + if (previousState) { + this.grid = new Grid(previousState.grid.size, + previousState.grid.cells); // Reload grid + this.score = previousState.score; + this.over = previousState.over; + this.won = previousState.won; + this.keepPlaying = previousState.keepPlaying; } else { - this.grid = new Grid(this.size); - this.score = 0; - this.over = false; - this.won = false; - this.keepPlaying = false; + this.grid = new Grid(this.size); + this.score = 0; + this.over = false; + this.won = false; + this.keepPlaying = false; - // Add the initial tiles - this.addStartTiles(); + // Add the initial tiles + this.addStartTiles(); } // Update the actuator @@ -82,7 +83,7 @@ GameManager.prototype.actuate = function () { this.storageManager.setBestScore(this.score); } - this.storageManager.setGameState(this.serializeGameState()); + this.storageManager.setGameState(this.serialize()); this.actuator.actuate(this.grid, { score: this.score, @@ -94,16 +95,16 @@ GameManager.prototype.actuate = function () { }; -GameManager.prototype.serializeGameState = function () { - return { - size: this.size, - grid: this.grid.gridState(), - score: this.score, - over: this.over, - won: this.won, - keepPlaying: this.keepPlaying - }; -} +GameManager.prototype.serialize = function () { + return { + size: this.size, + grid: this.grid.serialize(), + score: this.score, + over: this.over, + won: this.won, + keepPlaying: this.keepPlaying + }; +}; // Save all tile positions and remove merger info GameManager.prototype.prepareTiles = function () { diff --git a/js/grid.js b/js/grid.js index a2215a7..29f0821 100644 --- a/js/grid.js +++ b/js/grid.js @@ -1,11 +1,12 @@ -function Grid(size, previousCellState) { +function Grid(size, previousState) { this.size = size; - this.cells = previousCellState ? this.buildFromPreviousState(previousCellState) : this.buildNew(); + this.cells = previousState ? this.fromState(previousState) : this.empty(); } // Build a grid of the specified size -Grid.prototype.buildNew = function () { +Grid.prototype.empty = function () { var cells = []; + for (var x = 0; x < this.size; x++) { var row = cells[x] = []; @@ -13,20 +14,23 @@ Grid.prototype.buildNew = function () { row.push(null); } } + return cells; }; -Grid.prototype.buildFromPreviousState = function (state) { - var cells = []; - for (var x = 0; x < this.size; x++) { - var row = cells[x] = []; +Grid.prototype.fromState = function (state) { + var cells = []; - for (var y = 0; y < this.size; y++) { - var tileState = state[x][y]; - row.push(tileState ? new Tile(tileState.position, tileState.value) : null); - } + for (var x = 0; x < this.size; x++) { + var row = cells[x] = []; + + for (var y = 0; y < this.size; y++) { + var tile = state[x][y]; + row.push(tile ? new Tile(tile.position, tile.value) : null); } - return cells; + } + + return cells; }; // Find the first available random position @@ -95,18 +99,19 @@ Grid.prototype.withinBounds = function (position) { position.y >= 0 && position.y < this.size; }; -Grid.prototype.gridState = function () { +Grid.prototype.serialize = function () { var cellState = []; + for (var x = 0; x < this.size; x++) { var row = cellState[x] = []; for (var y = 0; y < this.size; y++) { - row.push(this.cells[x][y] ? this.cells[x][y].tileState() : null); + row.push(this.cells[x][y] ? this.cells[x][y].serialize() : null); } } return { - size: this.size, - cells: cellState - } + size: this.size, + cells: cellState + }; }; diff --git a/js/tile.js b/js/tile.js index f124073..92a670a 100644 --- a/js/tile.js +++ b/js/tile.js @@ -16,12 +16,12 @@ Tile.prototype.updatePosition = function (position) { this.y = position.y; }; -Tile.prototype.tileState = function () { - return { - position: { - x: this.x, - y: this.y - }, - value: this.value - }; -} \ No newline at end of file +Tile.prototype.serialize = function () { + return { + position: { + x: this.x, + y: this.y + }, + value: this.value + }; +}; From a6531b08bdf7cea4e402dda078e8016563cce401 Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 16:29:23 +0100 Subject: [PATCH 07/12] add getter comments --- js/local_storage_manager.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/local_storage_manager.js b/js/local_storage_manager.js index 74e5ee8..776e94b 100644 --- a/js/local_storage_manager.js +++ b/js/local_storage_manager.js @@ -39,6 +39,7 @@ LocalStorageManager.prototype.localStorageSupported = function () { } }; +// Best score getters/setters LocalStorageManager.prototype.getBestScore = function () { return this.storage.getItem(this.bestScoreKey) || 0; }; @@ -47,6 +48,7 @@ LocalStorageManager.prototype.setBestScore = function (score) { this.storage.setItem(this.bestScoreKey, score); }; +// Game state getters/setters and clearing LocalStorageManager.prototype.getGameState = function () { var stateJSON = this.storage.getItem(this.gameStateKey); return stateJSON ? JSON.parse(stateJSON) : null; From 4ad15d4cbd224fd36d4f1139ebb28c6b4af1ad6d Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 16:35:47 +0100 Subject: [PATCH 08/12] add R key to restart game --- js/keyboard_input_manager.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/keyboard_input_manager.js b/js/keyboard_input_manager.js index 4f2e856..32a177a 100644 --- a/js/keyboard_input_manager.js +++ b/js/keyboard_input_manager.js @@ -61,6 +61,11 @@ KeyboardInputManager.prototype.listen = function () { self.emit("move", mapped); } } + + // R key restarts the game + if (!modifiers && event.which === 82) { + self.restart.call(self, event); + } }); // Respond to button presses From 560859fcd9af9b4280e32d48806d91057702e0b0 Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 17:00:50 +0100 Subject: [PATCH 09/12] restyle new game button to put it on the right side of the introduction --- index.html | 8 ++++-- style/helpers.scss | 9 +++++++ style/main.css | 62 ++++++++++++++++++++++++++-------------------- style/main.scss | 49 ++++++++++++++++++++++++++---------- 4 files changed, 86 insertions(+), 42 deletions(-) diff --git a/index.html b/index.html index 557b68e..292ad08 100644 --- a/index.html +++ b/index.html @@ -22,8 +22,12 @@
0
-

Join the numbers and get the 2048 tile!

- New Game + +
+

Join the numbers and get the 2048 tile!

+ New Game +
+

diff --git a/style/helpers.scss b/style/helpers.scss index 53b9dc1..7b4445b 100644 --- a/style/helpers.scss +++ b/style/helpers.scss @@ -70,3 +70,12 @@ @content; } } + +// Clearfix +@mixin clearfix { + &:after { + content: ""; + display: block; + clear: both; + } +} diff --git a/style/main.css b/style/main.css index 5fc88e3..a42d04d 100644 --- a/style/main.css +++ b/style/main.css @@ -30,7 +30,6 @@ h1.title { 100% { top: -50px; opacity: 0; } } - @-moz-keyframes move-up { 0% { top: 25px; @@ -39,7 +38,6 @@ h1.title { 100% { top: -50px; opacity: 0; } } - @keyframes move-up { 0% { top: 25px; @@ -48,7 +46,6 @@ h1.title { 100% { top: -50px; opacity: 0; } } - .scores-container { float: right; text-align: right; } @@ -128,36 +125,20 @@ hr { 100% { opacity: 1; } } - @-moz-keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } - @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } - -.restart-button { - display: inline-block; - background: #8f7a66; - border-radius: 3px; - padding: 0 20px; - text-decoration: none; - color: #f9f6f2; - height: 40px; - line-height: 42px; - display: block; - width: 100px; - margin: 10px auto 10px auto; - text-align: center; } - .game-container { + margin-top: 40px; position: relative; padding: 15px; cursor: default; @@ -406,7 +387,6 @@ hr { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } } - @-moz-keyframes appear { 0% { opacity: 0; @@ -419,7 +399,6 @@ hr { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } } - @keyframes appear { 0% { opacity: 0; @@ -432,7 +411,6 @@ hr { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } } - .tile-new .tile-inner { -webkit-animation: appear 200ms ease 100ms; -moz-animation: appear 200ms ease 100ms; @@ -456,7 +434,6 @@ hr { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } } - @-moz-keyframes pop { 0% { -webkit-transform: scale(0); @@ -472,7 +449,6 @@ hr { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } } - @keyframes pop { 0% { -webkit-transform: scale(0); @@ -488,7 +464,6 @@ hr { -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } } - .tile-merged .tile-inner { z-index: 20; -webkit-animation: pop 200ms ease 100ms; @@ -498,8 +473,27 @@ hr { -moz-animation-fill-mode: backwards; animation-fill-mode: backwards; } +.above-game:after { + content: ""; + display: block; + clear: both; } + .game-intro { - margin-bottom: 0; } + float: left; + line-height: 42px; } + +.restart-button { + display: inline-block; + background: #8f7a66; + border-radius: 3px; + padding: 0 20px; + text-decoration: none; + color: #f9f6f2; + height: 40px; + line-height: 42px; + display: block; + text-align: center; + float: right; } .game-explanation { margin-top: 50px; } @@ -528,7 +522,21 @@ hr { .heading { margin-bottom: 10px; } + .game-intro { + width: 55%; + display: block; + box-sizing: border-box; + line-height: 1.65; } + + .restart-button { + width: 42%; + padding: 0; + display: block; + box-sizing: border-box; + margin-top: 2px; } + .game-container { + margin-top: 40px; position: relative; padding: 10px; cursor: default; diff --git a/style/main.scss b/style/main.scss index 5386e53..25cc3f3 100644 --- a/style/main.scss +++ b/style/main.scss @@ -34,10 +34,8 @@ body { margin: 80px 0; } -.heading:after { - content: ""; - display: block; - clear: both; +.heading { + @include clearfix; } h1.title { @@ -168,17 +166,10 @@ hr { line-height: 42px; } -.restart-button { - @include button; - display: block; - width: 100px; - margin: 10px auto 10px auto; - text-align: center; -} - // Game field mixin used to render CSS at different width @mixin game-field { .game-container { + margin-top: 40px; position: relative; padding: $grid-spacing; @@ -454,8 +445,24 @@ hr { @include animation-fill-mode(backwards); } +.above-game { + @include clearfix; + // margin-bottom: 10px; +} + .game-intro { - margin-bottom: 0; + float: left; + line-height: 42px; + // margin-bottom: 0; +} + +.restart-button { + @include button; + display: block; + // width: 100px; + // margin: 10px auto 10px auto; + text-align: center; + float: right; } .game-explanation { @@ -499,6 +506,22 @@ hr { margin-bottom: 10px; } + // Show intro and restart button side by side + .game-intro { + width: 55%; + display: block; + box-sizing: border-box; + line-height: 1.65; + } + + .restart-button { + width: 42%; + padding: 0; + display: block; + box-sizing: border-box; + margin-top: 2px; + } + // Render the game field at the right width @include game-field; From 4fa41a045be4e3654eca43cc9a6852a5fd56d3d3 Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 17:01:36 +0100 Subject: [PATCH 10/12] reintroduce "to" in intro --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 292ad08..edc7b55 100644 --- a/index.html +++ b/index.html @@ -24,7 +24,7 @@
-

Join the numbers and get the 2048 tile!

+

Join the numbers and get to the 2048 tile!

New Game
From 88e084a0d731f138a017e62400d364bcdb682e22 Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 17:06:32 +0100 Subject: [PATCH 11/12] remove irrelevant size property on serialized game --- js/game_manager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/game_manager.js b/js/game_manager.js index 49b903a..3651d08 100644 --- a/js/game_manager.js +++ b/js/game_manager.js @@ -97,7 +97,6 @@ GameManager.prototype.actuate = function () { GameManager.prototype.serialize = function () { return { - size: this.size, grid: this.grid.serialize(), score: this.score, over: this.over, From 8ad8318c7ce84298b17dcf0aa15f357926cb2ffa Mon Sep 17 00:00:00 2001 From: Gabriele Cirulli Date: Sat, 22 Mar 2014 17:06:37 +0100 Subject: [PATCH 12/12] align assignments --- js/game_manager.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/game_manager.js b/js/game_manager.js index 3651d08..f60fd2d 100644 --- a/js/game_manager.js +++ b/js/game_manager.js @@ -1,10 +1,10 @@ function GameManager(size, InputManager, Actuator, StorageManager) { - this.size = size; // Size of the grid - this.inputManager = new InputManager; + this.size = size; // Size of the grid + this.inputManager = new InputManager; this.storageManager = new StorageManager; - this.actuator = new Actuator; + this.actuator = new Actuator; - this.startTiles = 2; + this.startTiles = 2; this.inputManager.on("move", this.move.bind(this)); this.inputManager.on("restart", this.restart.bind(this));