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
This commit is contained in:
+35
-12
@@ -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) {
|
||||
|
||||
+35
-7
@@ -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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
+10
@@ -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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user