diff --git a/index.html b/index.html index 8e86f47cff27d0c8acf2cf51772cb0d9cbd7d9a5..3fb403eb11cd1c7787a837f2c407ab7ffc2c7b55 100644 --- a/index.html +++ b/index.html @@ -33,6 +33,7 @@

+ Keep going Try again
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) {