From b39c986e1270914a1f4f93f593d8a00e6ce7bd83 Mon Sep 17 00:00:00 2001 From: jeffcheasey88 <66554203+jeffcheasey88@users.noreply.github.com> Date: Sat, 25 Mar 2023 19:34:30 +0100 Subject: [PATCH] MultiPlayer V1, its a pure 1 vs 1 --- .classpath | 4 ++ .project | 17 ++++++ assets/js/application.js | 6 +- assets/js/game_manager.js | 85 ++++++++++++++--------------- assets/js/html_actuator.js | 10 ++-- assets/js/local_storage_manager.js | 63 --------------------- assets/js/remote_storage_manager.js | 51 +++++++++++++++++ assets/style/main.css | 6 +- index.html | 63 ++++++++++++++++----- 9 files changed, 176 insertions(+), 129 deletions(-) create mode 100644 .classpath create mode 100644 .project delete mode 100644 assets/js/local_storage_manager.js create mode 100644 assets/js/remote_storage_manager.js diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..7cec603 --- /dev/null +++ b/.classpath @@ -0,0 +1,4 @@ + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..e44e865 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + endg-2048 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/assets/js/application.js b/assets/js/application.js index 2c1108e..46b9d34 100644 --- a/assets/js/application.js +++ b/assets/js/application.js @@ -1,4 +1,6 @@ // Wait till the browser is ready to render the game (avoids glitches) -window.requestAnimationFrame(function () { - new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager); +window.requestAnimationFrame(function (){ + let storage = new RemoteStorageManager; + new GameManager(4, new KeyboardInputManager, new HTMLActuator("game1"), storage, "game1"); + new GameManager(4, undefined, new HTMLActuator("game2"), storage, "game2"); }); diff --git a/assets/js/game_manager.js b/assets/js/game_manager.js index 7160285..7b9a036 100644 --- a/assets/js/game_manager.js +++ b/assets/js/game_manager.js @@ -1,21 +1,24 @@ -function GameManager(size, InputManager, Actuator, StorageManager) { +function GameManager(size, InputManager, Actuator, StorageManager, game){ this.size = size; // Size of the grid - this.inputManager = new InputManager; - this.storageManager = new StorageManager; - this.actuator = new Actuator; + this.inputManager = InputManager; + this.storageManager = StorageManager; + this.actuator = Actuator; + this.game = game; this.startTiles = 2; - this.inputManager.on("move", this.move.bind(this)); - this.inputManager.on("restart", this.restart.bind(this)); - this.inputManager.on("keepPlaying", this.keepPlaying.bind(this)); + if(this.inputManager){ + 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.storageManager.clearGameState(); + this.storageManager.sendAction("restart"); this.actuator.continueGame(); // Clear the game won/lost message this.setup(); }; @@ -32,30 +35,33 @@ GameManager.prototype.isGameTerminated = function () { }; // Set up the game -GameManager.prototype.setup = function () { - var previousState = this.storageManager.getGameState(); - - // Reload the game from a previous game if present - 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; - - // Add the initial tiles - this.addStartTiles(); - } - - // Update the actuator - this.actuate(); +GameManager.prototype.setup = function (){ + this.storageManager.onData((data) => { + if(data.action === "state"){ + // Reload the game from a previous game if present + if (data.value) { + var previousState = JSON.parse(data.value); + 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; + + // Add the initial tiles + this.addStartTiles(); + } + + // Update the actuator + this.actuate(); + } + }, this.game); }; // Set up the initial tiles to start the game with @@ -77,17 +83,6 @@ GameManager.prototype.addRandomTile = function () { // Sends the updated grid to the actuator GameManager.prototype.actuate = function () { - if (this.storageManager.getBestScore() < this.score) { - this.storageManager.setBestScore(this.score); - } - - // Clear the state when the game is over (game over only, not win) - if (this.over) { - console.log("over "+this.score); - this.storageManager.clearGameState(); - } else { - this.storageManager.setGameState(this.serialize()); - } this.actuator.actuate(this.grid, { score: this.score, @@ -96,6 +91,8 @@ GameManager.prototype.actuate = function () { bestScore: this.storageManager.getBestScore(), terminated: this.isGameTerminated() }); + + this.storageManager.sendAction("state", JSON.stringify(this.serialize())); }; @@ -111,7 +108,7 @@ GameManager.prototype.serialize = function () { }; // Save all tile positions and remove merger info -GameManager.prototype.prepareTiles = function () { +GameManager.prototype.prepareTiles = function (){ this.grid.eachCell(function (x, y, tile) { if (tile) { tile.mergedFrom = null; diff --git a/assets/js/html_actuator.js b/assets/js/html_actuator.js index 6b31f2d..f2e397c 100644 --- a/assets/js/html_actuator.js +++ b/assets/js/html_actuator.js @@ -1,8 +1,8 @@ -function HTMLActuator() { - this.tileContainer = document.querySelector(".tile-container"); - this.scoreContainer = document.querySelector(".score-container"); - this.bestContainer = document.querySelector(".best-container"); - this.messageContainer = document.querySelector(".game-message"); +function HTMLActuator(id) { + this.tileContainer = document.querySelector(".tile-container-"+id); + this.scoreContainer = document.querySelector(".score-container-"+id); + this.bestContainer = document.querySelector(".best-container-"+id); + this.messageContainer = document.querySelector(".game-message-"+id); this.score = 0; } diff --git a/assets/js/local_storage_manager.js b/assets/js/local_storage_manager.js deleted file mode 100644 index 2ca9cc3..0000000 --- a/assets/js/local_storage_manager.js +++ /dev/null @@ -1,63 +0,0 @@ -window.fakeStorage = { - _data: {}, - - setItem: function (id, val) { - return this._data[id] = String(val); - }, - - getItem: function (id) { - return this._data.hasOwnProperty(id) ? this._data[id] : undefined; - }, - - removeItem: function (id) { - return delete this._data[id]; - }, - - clear: function () { - return this._data = {}; - } -}; - -function LocalStorageManager() { - this.bestScoreKey = "bestScore"; - this.gameStateKey = "gameState"; - - var supported = this.localStorageSupported(); - this.storage = supported ? window.localStorage : window.fakeStorage; -} - -LocalStorageManager.prototype.localStorageSupported = function () { - var testKey = "test"; - - try { - var storage = window.localStorage; - storage.setItem(testKey, "1"); - storage.removeItem(testKey); - return true; - } catch (error) { - return false; - } -}; - -// Best score getters/setters -LocalStorageManager.prototype.getBestScore = function () { - return this.storage.getItem(this.bestScoreKey) || 0; -}; - -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; -}; - -LocalStorageManager.prototype.setGameState = function (gameState) { - this.storage.setItem(this.gameStateKey, JSON.stringify(gameState)); -}; - -LocalStorageManager.prototype.clearGameState = function () { - this.storage.removeItem(this.gameStateKey); -}; diff --git a/assets/js/remote_storage_manager.js b/assets/js/remote_storage_manager.js new file mode 100644 index 0000000..b1ce9b3 --- /dev/null +++ b/assets/js/remote_storage_manager.js @@ -0,0 +1,51 @@ +function RemoteStorageManager() { + this.storage = new WebSocket("ws://localhost/"); + openListeners = []; + dataListeners = []; + + this.bestScore = 0; + + this.storage.onopen = function(){ + this.connected = true; + openListeners.forEach(listener => listener()); + } + + this.storage.onmessage = function(e){ + let data = JSON.parse(e.data); + let list = dataListeners[data.game]; + if(list !== undefined) list.forEach(listener => listener(data)); + console.log(data); + + if(data.action === "bestScore"){ + this.bestScore = data.value; + } + } + + this.openListeners = openListeners; + this.dataListeners = dataListeners; +} + +RemoteStorageManager.prototype.onConnected = function(func){ + if(this.connected){ + func(); + return; + } + this.openListeners.push(func); +} + +RemoteStorageManager.prototype.onData = function(func, game){ + let listeners = this.dataListeners[game]; + if(listeners == undefined){ + listeners = []; + this.dataListeners[game] = listeners; + } + listeners.push(func); +} + +RemoteStorageManager.prototype.sendAction = function(action, value){ + this.storage.send(JSON.stringify(value === undefined ? {action:action} : {action:action,value:value})); +} + +RemoteStorageManager.prototype.getBestScore = function(){ + return this.bestScore; +} \ No newline at end of file diff --git a/assets/style/main.css b/assets/style/main.css index 0109624..3404642 100644 --- a/assets/style/main.css +++ b/assets/style/main.css @@ -116,8 +116,10 @@ hr { margin-bottom: 30px; } .container { - width: 500px; - margin: 0 auto; } + width: 40%; + margin: 0 auto; + display: inline-block; +} @-webkit-keyframes fade-in { 0% { diff --git a/index.html b/index.html index b25c4b8..9f6223a 100644 --- a/index.html +++ b/index.html @@ -18,12 +18,11 @@
-

2048

-
0
-
0
+
0
+
0
@@ -33,7 +32,7 @@
-
+

Keep going @@ -67,17 +66,55 @@
-
+
+
+
+ +
+
+

2048

+
+
0
+
0
-

- How to play: Use your arrow keys to move the tiles. When two tiles with the same number touch, they merge into one! -

-
-

- Note: This site is the official version of 2048. You can access it on your phone via the EndStorage Hub. -

+
+
+

+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -87,7 +124,7 @@ - +