提交 bd7f8963 编写于 作者: G Gabriele Cirulli

Merge branch 'resume-game' of github.com:mfrederiksen/2048 into mfrederiksen-resume-game

...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
</div> </div>
</div> </div>
<p class="game-intro">Join the numbers and get to the <strong>2048 tile!</strong></p> <p class="game-intro">Join the numbers and get to the <strong>2048 tile!</strong></p>
<a class="restart-button">New Game</a>
<div class="game-container"> <div class="game-container">
<div class="game-message"> <div class="game-message">
<p></p> <p></p>
......
function GameManager(size, InputManager, Actuator, ScoreManager) { function GameManager(size, InputManager, Actuator, StorageManager) {
this.size = size; // Size of the grid this.size = size; // Size of the grid
this.inputManager = new InputManager; this.inputManager = new InputManager;
this.scoreManager = new ScoreManager; this.storageManager = new StorageManager;
this.actuator = new Actuator; this.actuator = new Actuator;
this.startTiles = 2; this.startTiles = 2;
...@@ -15,6 +15,7 @@ function GameManager(size, InputManager, Actuator, ScoreManager) { ...@@ -15,6 +15,7 @@ function GameManager(size, InputManager, Actuator, ScoreManager) {
// Restart the game // Restart the game
GameManager.prototype.restart = function () { GameManager.prototype.restart = function () {
this.storageManager.clearGameState();
this.actuator.continue(); this.actuator.continue();
this.setup(); this.setup();
}; };
...@@ -35,8 +36,16 @@ GameManager.prototype.isGameTerminated = function () { ...@@ -35,8 +36,16 @@ GameManager.prototype.isGameTerminated = function () {
// Set up the game // Set up the game
GameManager.prototype.setup = function () { GameManager.prototype.setup = function () {
var previousGameState = 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;
} else {
this.grid = new Grid(this.size); this.grid = new Grid(this.size);
this.score = 0; this.score = 0;
this.over = false; this.over = false;
this.won = false; this.won = false;
...@@ -44,6 +53,7 @@ GameManager.prototype.setup = function () { ...@@ -44,6 +53,7 @@ GameManager.prototype.setup = function () {
// Add the initial tiles // Add the initial tiles
this.addStartTiles(); this.addStartTiles();
}
// Update the actuator // Update the actuator
this.actuate(); this.actuate();
...@@ -68,20 +78,33 @@ GameManager.prototype.addRandomTile = function () { ...@@ -68,20 +78,33 @@ GameManager.prototype.addRandomTile = function () {
// Sends the updated grid to the actuator // Sends the updated grid to the actuator
GameManager.prototype.actuate = function () { GameManager.prototype.actuate = function () {
if (this.scoreManager.get() < this.score) { if (this.storageManager.getBestScore() < this.score) {
this.scoreManager.set(this.score); this.storageManager.setBestScore(this.score);
} }
this.storageManager.setGameState(this.serializeGameState());
this.actuator.actuate(this.grid, { this.actuator.actuate(this.grid, {
score: this.score, score: this.score,
over: this.over, over: this.over,
won: this.won, won: this.won,
bestScore: this.scoreManager.get(), bestScore: this.storageManager.getBestScore(),
terminated: this.isGameTerminated() 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 // Save all tile positions and remove merger info
GameManager.prototype.prepareTiles = function () { GameManager.prototype.prepareTiles = function () {
this.grid.eachCell(function (x, y, tile) { this.grid.eachCell(function (x, y, tile) {
......
function Grid(size) { function Grid(size, previousCellState) {
this.size = size; this.size = size;
this.cells = previousCellState ? this.buildFromPreviousState(previousCellState) : this.buildNew();
this.cells = [];
this.build();
} }
// Build a grid of the specified size // 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++) { 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++) { for (var y = 0; y < this.size; y++) {
row.push(null); 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 // Find the first available random position
...@@ -82,3 +94,19 @@ Grid.prototype.withinBounds = function (position) { ...@@ -82,3 +94,19 @@ Grid.prototype.withinBounds = function (position) {
return position.x >= 0 && position.x < this.size && return position.x >= 0 && position.x < this.size &&
position.y >= 0 && position.y < 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
}
};
...@@ -68,6 +68,10 @@ KeyboardInputManager.prototype.listen = function () { ...@@ -68,6 +68,10 @@ KeyboardInputManager.prototype.listen = function () {
retry.addEventListener("click", this.restart.bind(this)); retry.addEventListener("click", this.restart.bind(this));
retry.addEventListener(this.eventTouchend, this.restart.bind(this)); retry.addEventListener(this.eventTouchend, 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"); var keepPlaying = document.querySelector(".keep-playing-button");
keepPlaying.addEventListener("click", this.keepPlaying.bind(this)); keepPlaying.addEventListener("click", this.keepPlaying.bind(this));
keepPlaying.addEventListener("touchend", this.keepPlaying.bind(this)); keepPlaying.addEventListener("touchend", this.keepPlaying.bind(this));
......
...@@ -19,7 +19,8 @@ window.fakeStorage = { ...@@ -19,7 +19,8 @@ window.fakeStorage = {
}; };
function LocalScoreManager() { function LocalScoreManager() {
this.key = "bestScore"; this.bestScoreKey = "bestScore";
this.gameStateKey = "gameState";
var supported = this.localStorageSupported(); var supported = this.localStorageSupported();
this.storage = supported ? window.localStorage : window.fakeStorage; this.storage = supported ? window.localStorage : window.fakeStorage;
...@@ -38,11 +39,23 @@ LocalScoreManager.prototype.localStorageSupported = function () { ...@@ -38,11 +39,23 @@ LocalScoreManager.prototype.localStorageSupported = function () {
} }
}; };
LocalScoreManager.prototype.get = function () { LocalScoreManager.prototype.getBestScore = function () {
return this.storage.getItem(this.key) || 0; return this.storage.getItem(this.bestScoreKey) || 0;
}; };
LocalScoreManager.prototype.set = function (score) { LocalScoreManager.prototype.setBestScore = function (score) {
this.storage.setItem(this.key, 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);
};
...@@ -15,3 +15,13 @@ Tile.prototype.updatePosition = function (position) { ...@@ -15,3 +15,13 @@ Tile.prototype.updatePosition = function (position) {
this.x = position.x; this.x = position.x;
this.y = position.y; 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
...@@ -143,8 +143,21 @@ hr { ...@@ -143,8 +143,21 @@ hr {
100% { 100% {
opacity: 1; } } 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 { .game-container {
margin-top: 40px;
position: relative; position: relative;
padding: 15px; padding: 15px;
cursor: default; cursor: default;
...@@ -516,7 +529,6 @@ hr { ...@@ -516,7 +529,6 @@ hr {
margin-bottom: 10px; } margin-bottom: 10px; }
.game-container { .game-container {
margin-top: 40px;
position: relative; position: relative;
padding: 10px; padding: 10px;
cursor: default; cursor: default;
......
...@@ -168,10 +168,17 @@ hr { ...@@ -168,10 +168,17 @@ hr {
line-height: 42px; 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 // Game field mixin used to render CSS at different width
@mixin game-field { @mixin game-field {
.game-container { .game-container {
margin-top: 40px;
position: relative; position: relative;
padding: $grid-spacing; padding: $grid-spacing;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册