Compare commits

...

1 Commits

Author SHA1 Message Date
jeffcheasey88
b39c986e12 MultiPlayer V1, its a pure 1 vs 1 2023-03-25 19:34:30 +01:00
9 changed files with 176 additions and 129 deletions

4
.classpath Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="output" path="bin"/>
</classpath>

17
.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>endg-2048</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -1,4 +1,6 @@
// Wait till the browser is ready to render the game (avoids glitches) // Wait till the browser is ready to render the game (avoids glitches)
window.requestAnimationFrame(function () { window.requestAnimationFrame(function (){
new GameManager(4, KeyboardInputManager, HTMLActuator, LocalStorageManager); let storage = new RemoteStorageManager;
new GameManager(4, new KeyboardInputManager, new HTMLActuator("game1"), storage, "game1");
new GameManager(4, undefined, new HTMLActuator("game2"), storage, "game2");
}); });

View File

@ -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.size = size; // Size of the grid
this.inputManager = new InputManager; this.inputManager = InputManager;
this.storageManager = new StorageManager; this.storageManager = StorageManager;
this.actuator = new Actuator; this.actuator = Actuator;
this.game = game;
this.startTiles = 2; this.startTiles = 2;
if(this.inputManager){
this.inputManager.on("move", this.move.bind(this)); this.inputManager.on("move", this.move.bind(this));
this.inputManager.on("restart", this.restart.bind(this)); this.inputManager.on("restart", this.restart.bind(this));
this.inputManager.on("keepPlaying", this.keepPlaying.bind(this)); this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
}
this.setup(); this.setup();
} }
// Restart the game // Restart the game
GameManager.prototype.restart = function () { GameManager.prototype.restart = function () {
this.storageManager.clearGameState(); this.storageManager.sendAction("restart");
this.actuator.continueGame(); // Clear the game won/lost message this.actuator.continueGame(); // Clear the game won/lost message
this.setup(); this.setup();
}; };
@ -32,11 +35,12 @@ GameManager.prototype.isGameTerminated = function () {
}; };
// Set up the game // Set up the game
GameManager.prototype.setup = function () { GameManager.prototype.setup = function (){
var previousState = this.storageManager.getGameState(); this.storageManager.onData((data) => {
if(data.action === "state"){
// Reload the game from a previous game if present // Reload the game from a previous game if present
if (previousState) { if (data.value) {
var previousState = JSON.parse(data.value);
this.grid = new Grid(previousState.grid.size, this.grid = new Grid(previousState.grid.size,
previousState.grid.cells); // Reload grid previousState.grid.cells); // Reload grid
this.score = previousState.score; this.score = previousState.score;
@ -56,6 +60,8 @@ GameManager.prototype.setup = function () {
// Update the actuator // Update the actuator
this.actuate(); this.actuate();
}
}, this.game);
}; };
// Set up the initial tiles to start the game with // 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 // Sends the updated grid to the actuator
GameManager.prototype.actuate = function () { 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, { this.actuator.actuate(this.grid, {
score: this.score, score: this.score,
@ -97,6 +92,8 @@ GameManager.prototype.actuate = function () {
terminated: this.isGameTerminated() terminated: this.isGameTerminated()
}); });
this.storageManager.sendAction("state", JSON.stringify(this.serialize()));
}; };
// Represent the current game as an object // Represent the current game as an object
@ -111,7 +108,7 @@ GameManager.prototype.serialize = function () {
}; };
// 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) {
if (tile) { if (tile) {
tile.mergedFrom = null; tile.mergedFrom = null;

View File

@ -1,8 +1,8 @@
function HTMLActuator() { function HTMLActuator(id) {
this.tileContainer = document.querySelector(".tile-container"); this.tileContainer = document.querySelector(".tile-container-"+id);
this.scoreContainer = document.querySelector(".score-container"); this.scoreContainer = document.querySelector(".score-container-"+id);
this.bestContainer = document.querySelector(".best-container"); this.bestContainer = document.querySelector(".best-container-"+id);
this.messageContainer = document.querySelector(".game-message"); this.messageContainer = document.querySelector(".game-message-"+id);
this.score = 0; this.score = 0;
} }

View File

@ -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);
};

View File

@ -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;
}

View File

@ -116,8 +116,10 @@ hr {
margin-bottom: 30px; } margin-bottom: 30px; }
.container { .container {
width: 500px; width: 40%;
margin: 0 auto; } margin: 0 auto;
display: inline-block;
}
@-webkit-keyframes fade-in { @-webkit-keyframes fade-in {
0% { 0% {

View File

@ -18,12 +18,11 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<div class="heading"> <div class="heading">
<h1 class="title">2048</h1> <h1 class="title">2048</h1>
<div class="scores-container"> <div class="scores-container">
<div class="score-container">0</div> <div class="score-container score-container-game1">0</div>
<div class="best-container">0</div> <div class="best-container best-container-game1">0</div>
</div> </div>
</div> </div>
@ -33,7 +32,7 @@
</div> </div>
<div class="game-container"> <div class="game-container">
<div class="game-message"> <div class="game-message game-message-game1">
<p></p> <p></p>
<div class="lower"> <div class="lower">
<a class="keep-playing-button">Keep going</a> <a class="keep-playing-button">Keep going</a>
@ -67,17 +66,55 @@
<div class="grid-cell"></div> <div class="grid-cell"></div>
</div> </div>
</div> </div>
<div class="tile-container"> <div class="tile-container tile-container-game1"></div>
</div> </div>
</div> </div>
<p class="game-explanation"> <div class="container">
<strong class="important">How to play:</strong> Use your <strong>arrow keys</strong> to move the tiles. When two tiles with the same number touch, they <strong>merge into one!</strong> <div class="heading">
</p> <h1 class="title">2048</h1>
<hr> <div class="scores-container">
<p> <div class="score-container score-container-game2">0</div>
<strong class="important">Note:</strong> This site is the official version of 2048. You can access it on your phone via the <a href="https://hub.endmove.eu">EndStorage Hub</a>. <div class="best-container best-container-game2">0</div>
</p> </div>
</div>
<div class="game-container">
<div class="game-message game-message-game2">
<p></p>
<div class="lower">
<a class="keep-playing-button">Keep going</a>
<a class="retry-button">Try again</a>
</div>
</div>
<div class="grid-container">
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
<div class="grid-row">
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
<div class="grid-cell"></div>
</div>
</div>
<div class="tile-container tile-container-game2"></div>
</div>
</div> </div>
<script src="assets/js/bind_polyfill.js"></script> <script src="assets/js/bind_polyfill.js"></script>
@ -87,7 +124,7 @@
<script src="assets/js/html_actuator.js"></script> <script src="assets/js/html_actuator.js"></script>
<script src="assets/js/grid.js"></script> <script src="assets/js/grid.js"></script>
<script src="assets/js/tile.js"></script> <script src="assets/js/tile.js"></script>
<script src="assets/js/local_storage_manager.js"></script> <script src="assets/js/remote_storage_manager.js"></script>
<script src="assets/js/game_manager.js"></script> <script src="assets/js/game_manager.js"></script>
<script src="assets/js/application.js"></script> <script src="assets/js/application.js"></script>
</body> </body>