diff --git a/index.html b/index.html
index 8e86f47cff27d0c8acf2cf51772cb0d9cbd7d9a5..3fb403eb11cd1c7787a837f2c407ab7ffc2c7b55 100644
--- a/index.html
+++ b/index.html
@@ -33,6 +33,7 @@
diff --git a/js/game_manager.js b/js/game_manager.js
index 01ce04c3bbec283e254f0c1e54d41a0b62b17b30..b36aea3122986eb8708de896d014d7ae613e3c05 100644
--- a/js/game_manager.js
+++ b/js/game_manager.js
@@ -8,23 +8,39 @@ function GameManager(size, InputManager, Actuator, ScoreManager) {
this.inputManager.on("move", this.move.bind(this));
this.inputManager.on("restart", this.restart.bind(this));
+ this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
this.setup();
}
// Restart the game
GameManager.prototype.restart = function () {
- this.actuator.restart();
+ this.actuator.continue();
this.setup();
};
+// Keep playing after winning
+GameManager.prototype.keepPlaying = function () {
+ this.keepPlaying = true;
+ this.actuator.continue();
+};
+
+GameManager.prototype.isGameTerminated = function () {
+ if (this.over || (this.won && !this.keepPlaying)) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
// Set up the game
GameManager.prototype.setup = function () {
- this.grid = new Grid(this.size);
+ this.grid = new Grid(this.size);
- this.score = 0;
- this.over = false;
- this.won = false;
+ this.score = 0;
+ this.over = false;
+ this.won = false;
+ this.keepPlaying = false;
// Add the initial tiles
this.addStartTiles();
@@ -57,10 +73,11 @@ GameManager.prototype.actuate = function () {
}
this.actuator.actuate(this.grid, {
- score: this.score,
- over: this.over,
- won: this.won,
- bestScore: this.scoreManager.get()
+ score: this.score,
+ over: this.over,
+ won: this.won,
+ bestScore: this.scoreManager.get(),
+ terminated: this.isGameTerminated()
});
};
@@ -87,7 +104,7 @@ GameManager.prototype.move = function (direction) {
// 0: up, 1: right, 2:down, 3: left
var self = this;
- if (this.over || this.won) return; // Don't do anything if the game's over
+ if (this.isGameTerminated()) return; // Don't do anything if the game's over
var cell, tile;
diff --git a/js/html_actuator.js b/js/html_actuator.js
index b05c477868d11ea51c283616de8cccc0a2b8f8c1..81359a7685c4bdc8ce1babc76ba9e25d4a27f316 100644
--- a/js/html_actuator.js
+++ b/js/html_actuator.js
@@ -25,15 +25,23 @@ HTMLActuator.prototype.actuate = function (grid, metadata) {
self.updateScore(metadata.score);
self.updateBestScore(metadata.bestScore);
- if (metadata.over) self.message(false); // You lose
- if (metadata.won) self.message(true); // You win!
+ if (metadata.terminated) {
+ if (metadata.over) {
+ self.message(false); // You lose
+ } else if (metadata.won) {
+ self.message(true); // You win!
+ }
+ }
+
});
};
-HTMLActuator.prototype.restart = function () {
+// Continues the game (both restart and keep playing)
+HTMLActuator.prototype.continue = function () {
if (typeof ga !== "undefined") {
ga("send", "event", "game", "restart");
}
+
this.clearMessage();
};
@@ -49,10 +57,13 @@ HTMLActuator.prototype.addTile = function (tile) {
var wrapper = document.createElement("div");
var inner = document.createElement("div");
var position = tile.previousPosition || { x: tile.x, y: tile.y };
- positionClass = this.positionClass(position);
+ var positionClass = this.positionClass(position);
// We can't use classlist because it somehow glitches when replacing classes
var classes = ["tile", "tile-" + tile.value, positionClass];
+
+ if (tile.value > 2048) classes.push("tile-super");
+
this.applyClasses(wrapper, classes);
inner.classList.add("tile-inner");
diff --git a/js/keyboard_input_manager.js b/js/keyboard_input_manager.js
index b85c8c2dca760ab87816c4fa35b378d83b5aa615..822cc3bdfdc1edf9c91436aed2817e60c82e012e 100644
--- a/js/keyboard_input_manager.js
+++ b/js/keyboard_input_manager.js
@@ -53,10 +53,14 @@ KeyboardInputManager.prototype.listen = function () {
}
});
- var retry = document.getElementsByClassName("retry-button")[0];
+ var retry = document.querySelector(".retry-button");
retry.addEventListener("click", this.restart.bind(this));
retry.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
var touchStartClientX, touchStartClientY;
var gameContainer = document.getElementsByClassName("game-container")[0];
@@ -93,3 +97,8 @@ KeyboardInputManager.prototype.restart = function (event) {
event.preventDefault();
this.emit("restart");
};
+
+KeyboardInputManager.prototype.keepPlaying = function (event) {
+ event.preventDefault();
+ this.emit("keepPlaying");
+};
diff --git a/js/local_score_manager.js b/js/local_score_manager.js
index 2c94dd3dd378134dc064885f78bd1aa271c56739..ec4575dafa61af1b52de9d435e1ae40980a43d97 100644
--- a/js/local_score_manager.js
+++ b/js/local_score_manager.js
@@ -19,12 +19,25 @@ window.fakeStorage = {
};
function LocalScoreManager() {
- var localSupported = !!window.localStorage;
-
this.key = "bestScore";
- this.storage = localSupported ? window.localStorage : window.fakeStorage;
+
+ var supported = this.localStorageSupported();
+ this.storage = supported ? window.localStorage : window.fakeStorage;
}
+LocalScoreManager.prototype.localStorageSupported = function () {
+ var testKey = "test";
+ var storage = window.localStorage;
+
+ try {
+ storage.setItem(testKey, "1");
+ storage.removeItem(testKey);
+ return true;
+ } catch (error) {
+ return false;
+ }
+};
+
LocalScoreManager.prototype.get = function () {
return this.storage.getItem(this.key) || 0;
};
diff --git a/style/main.css b/style/main.css
index 2fb2b42bb24ba907a91fdea8fe5ba90a06d1fdf8..d96983725d884a7cf751e4386ea79eb3fd1f2371 100644
--- a/style/main.css
+++ b/style/main.css
@@ -193,6 +193,8 @@ hr {
height: 40px;
line-height: 42px;
margin-left: 9px; }
+ .game-container .game-message a.keep-playing-button {
+ display: none; }
.game-container .game-message .score-sharing {
display: inline-block;
vertical-align: middle;
@@ -200,6 +202,8 @@ hr {
.game-container .game-message.game-won {
background: rgba(237, 194, 46, 0.5);
color: #f9f6f2; }
+ .game-container .game-message.game-won a.keep-playing-button {
+ display: inline-block; }
.game-container .game-message.game-won, .game-container .game-message.game-over {
display: block; }
@@ -372,6 +376,13 @@ hr {
@media screen and (max-width: 480px) {
.tile.tile-2048 .tile-inner {
font-size: 15px; } }
+ .tile.tile-super .tile-inner {
+ color: #f9f6f2;
+ background: #3c3a32;
+ font-size: 30px; }
+ @media screen and (max-width: 480px) {
+ .tile.tile-super .tile-inner {
+ font-size: 10px; } }
@-webkit-keyframes appear {
0% {
@@ -564,6 +575,8 @@ hr {
height: 40px;
line-height: 42px;
margin-left: 9px; }
+ .game-container .game-message a.keep-playing-button {
+ display: none; }
.game-container .game-message .score-sharing {
display: inline-block;
vertical-align: middle;
@@ -571,6 +584,8 @@ hr {
.game-container .game-message.game-won {
background: rgba(237, 194, 46, 0.5);
color: #f9f6f2; }
+ .game-container .game-message.game-won a.keep-playing-button {
+ display: inline-block; }
.game-container .game-message.game-won, .game-container .game-message.game-over {
display: block; }
diff --git a/style/main.scss b/style/main.scss
index 519365961ff8798f400c366750687bdc5cde897b..03d6875e85a23d98c7e2dbb3d23d2d638f031296 100644
--- a/style/main.scss
+++ b/style/main.scss
@@ -218,6 +218,10 @@ hr {
@include button;
margin-left: 9px;
// margin-top: 59px;
+
+ &.keep-playing-button {
+ display: none;
+ }
}
.score-sharing {
@@ -232,6 +236,10 @@ hr {
&.game-won {
background: rgba($tile-gold-color, .5);
color: $bright-text-color;
+
+ a.keep-playing-button {
+ display: inline-block;
+ }
}
&.game-won, &.game-over {
@@ -391,6 +399,18 @@ hr {
$exponent: $exponent + 1;
}
+
+ // Super tiles (above 2048)
+ &.tile-super .tile-inner {
+ color: $bright-text-color;
+ background: mix(#333, $tile-gold-color, 95%);
+
+ font-size: 30px;
+
+ @include smaller(480px) {
+ font-size: 10px;
+ }
+ }
}
@include keyframes(appear) {