6 Commits

Author SHA1 Message Date
jeffcheasey88
b39c986e12 MultiPlayer V1, its a pure 1 vs 1 2023-03-25 19:34:30 +01:00
Jérémi N ‘EndMove’
c59a35cf62 Merge pull request 'fixing mobile compatibility' (#3) from dev into master
Reviewed-on: #3
2022-10-23 20:16:20 +00:00
30c70b597b fixing mobile compatibility 2022-10-23 22:14:15 +02:00
le FAST
61a098e7a8 Merge pull request 'Alors, tiens tiens tiens' (#2) from jeffcheasey88-patch-1 into master
Reviewed-on: #2
Reviewed-by: Jérémi N ‘EndMove’ <endmove@noreply@endmove.eu>
2022-10-18 07:00:15 +00:00
le FAST
6a92e289af Alors, tiens tiens tiens
ajout d'un console.log pour voir le score finale
2022-10-18 06:57:32 +00:00
le FAST
0e2ba86c10 Merge pull request 'refactor archi' (#1) from dev into master
Reviewed-on: #1
Reviewed-by: le FAST <jeffcheasey88@noreply@endmove.eu>
2022-10-18 06:16:09 +00:00
12 changed files with 313 additions and 261 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

@@ -10,4 +10,6 @@ The production version is available at [https://2048.g.endmove.eu](https://2048.
## To contribut ## To contribut
Run `npm install` in the repository directory. To build SCSS run `npm run build`. **<!> WARN <!>**: don't edit ``.css`` file but only ``.scss``. ~~Run `npm install` in the repository directory. To build SCSS run `npm run build`. **<!> WARN <!>**: don't edit ``.css`` file but only ``.scss``.~~
> Warning: The SCSS is old and needs to be rebuilt from scratch, please do not build it with npm run build, it destroys the mobile compatibility.

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;
this.inputManager.on("move", this.move.bind(this)); if(this.inputManager){
this.inputManager.on("restart", this.restart.bind(this)); this.inputManager.on("move", this.move.bind(this));
this.inputManager.on("keepPlaying", this.keepPlaying.bind(this)); this.inputManager.on("restart", this.restart.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,30 +35,33 @@ 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
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;
// Reload the game from a previous game if present // Add the initial tiles
if (previousState) { this.addStartTiles();
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 // Update the actuator
this.addStartTiles(); this.actuate();
} }
}, this.game);
// Update the actuator
this.actuate();
}; };
// Set up the initial tiles to start the game with // Set up the initial tiles to start the game with
@@ -77,16 +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) {
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,
@@ -96,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
@@ -110,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

@@ -52,7 +52,7 @@
transform: $args; transform: $args;
} }
//Keyframe animations // Keyframe animations
//it's normal if var is undefined ;-) //it's normal if var is undefined ;-)
@mixin keyframes($animation-name) { @mixin keyframes($animation-name) {
@-webkit-keyframes $animation-name { @-webkit-keyframes $animation-name {

View File

@@ -3,7 +3,7 @@ html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;
background: #faf8ef; background: #faf8ef;
color: #776E65; color: #776e65;
font-family: "Clear Sans", "Helvetica Neue", Arial, sans-serif; font-family: "Clear Sans", "Helvetica Neue", Arial, sans-serif;
font-size: 18px; } font-size: 18px; }
@@ -22,30 +22,30 @@ h1.title {
display: block; display: block;
float: left; } float: left; }
@-webkit-keyframes $animation-name { @-webkit-keyframes move-up {
0% { 0% {
top: 25px; top: 25px;
opacity: 1; } opacity: 1; }
100% { 100% {
top: -50px; top: -50px;
opacity: 0; } } opacity: 0; } }
@-moz-keyframes move-up {
@-moz-keyframes $animation-name {
0% { 0% {
top: 25px; top: 25px;
opacity: 1; } opacity: 1; }
100% { 100% {
top: -50px; top: -50px;
opacity: 0; } } opacity: 0; } }
@keyframes move-up {
@keyframes $animation-name {
0% { 0% {
top: 25px; top: 25px;
opacity: 1; } opacity: 1; }
100% { 100% {
top: -50px; top: -50px;
opacity: 0; } } opacity: 0; } }
.scores-container { .scores-container {
float: right; float: right;
text-align: right; } text-align: right; }
@@ -101,7 +101,7 @@ p {
line-height: 1.65; } line-height: 1.65; }
a { a {
color: #776E65; color: #776e65;
font-weight: bold; font-weight: bold;
text-decoration: underline; text-decoration: underline;
cursor: pointer; } cursor: pointer; }
@@ -116,27 +116,29 @@ hr {
margin-bottom: 30px; } margin-bottom: 30px; }
.container { .container {
width: 500px; width: 40%;
margin: 0 auto; } margin: 0 auto;
display: inline-block;
}
@-webkit-keyframes $animation-name { @-webkit-keyframes fade-in {
0% { 0% {
opacity: 0; } opacity: 0; }
100% { 100% {
opacity: 1; } } opacity: 1; } }
@-moz-keyframes fade-in {
@-moz-keyframes $animation-name {
0% { 0% {
opacity: 0; } opacity: 0; }
100% { 100% {
opacity: 1; } } opacity: 1; } }
@keyframes fade-in {
@keyframes $animation-name {
0% { 0% {
opacity: 0; } opacity: 0; }
100% { 100% {
opacity: 1; } } opacity: 1; } }
.game-container { .game-container {
margin-top: 40px; margin-top: 40px;
position: relative; position: relative;
@@ -232,97 +234,81 @@ hr {
width: 107px; width: 107px;
height: 107px; height: 107px;
line-height: 107px; } line-height: 107px; }
.tile.tile-position-1-1 { .tile.tile-position-1-1 {
-webkit-transform: translate(0px, 0px); -webkit-transform: translate(0px, 0px);
-moz-transform: translate(0px, 0px); -moz-transform: translate(0px, 0px);
-ms-transform: translate(0px, 0px); -ms-transform: translate(0px, 0px);
transform: translate(0px, 0px); } transform: translate(0px, 0px); }
.tile.tile-position-1-2 { .tile.tile-position-1-2 {
-webkit-transform: translate(0px, 121px); -webkit-transform: translate(0px, 121px);
-moz-transform: translate(0px, 121px); -moz-transform: translate(0px, 121px);
-ms-transform: translate(0px, 121px); -ms-transform: translate(0px, 121px);
transform: translate(0px, 121px); } transform: translate(0px, 121px); }
.tile.tile-position-1-3 { .tile.tile-position-1-3 {
-webkit-transform: translate(0px, 242px); -webkit-transform: translate(0px, 242px);
-moz-transform: translate(0px, 242px); -moz-transform: translate(0px, 242px);
-ms-transform: translate(0px, 242px); -ms-transform: translate(0px, 242px);
transform: translate(0px, 242px); } transform: translate(0px, 242px); }
.tile.tile-position-1-4 { .tile.tile-position-1-4 {
-webkit-transform: translate(0px, 363px); -webkit-transform: translate(0px, 363px);
-moz-transform: translate(0px, 363px); -moz-transform: translate(0px, 363px);
-ms-transform: translate(0px, 363px); -ms-transform: translate(0px, 363px);
transform: translate(0px, 363px); } transform: translate(0px, 363px); }
.tile.tile-position-2-1 { .tile.tile-position-2-1 {
-webkit-transform: translate(121px, 0px); -webkit-transform: translate(121px, 0px);
-moz-transform: translate(121px, 0px); -moz-transform: translate(121px, 0px);
-ms-transform: translate(121px, 0px); -ms-transform: translate(121px, 0px);
transform: translate(121px, 0px); } transform: translate(121px, 0px); }
.tile.tile-position-2-2 { .tile.tile-position-2-2 {
-webkit-transform: translate(121px, 121px); -webkit-transform: translate(121px, 121px);
-moz-transform: translate(121px, 121px); -moz-transform: translate(121px, 121px);
-ms-transform: translate(121px, 121px); -ms-transform: translate(121px, 121px);
transform: translate(121px, 121px); } transform: translate(121px, 121px); }
.tile.tile-position-2-3 { .tile.tile-position-2-3 {
-webkit-transform: translate(121px, 242px); -webkit-transform: translate(121px, 242px);
-moz-transform: translate(121px, 242px); -moz-transform: translate(121px, 242px);
-ms-transform: translate(121px, 242px); -ms-transform: translate(121px, 242px);
transform: translate(121px, 242px); } transform: translate(121px, 242px); }
.tile.tile-position-2-4 { .tile.tile-position-2-4 {
-webkit-transform: translate(121px, 363px); -webkit-transform: translate(121px, 363px);
-moz-transform: translate(121px, 363px); -moz-transform: translate(121px, 363px);
-ms-transform: translate(121px, 363px); -ms-transform: translate(121px, 363px);
transform: translate(121px, 363px); } transform: translate(121px, 363px); }
.tile.tile-position-3-1 { .tile.tile-position-3-1 {
-webkit-transform: translate(242px, 0px); -webkit-transform: translate(242px, 0px);
-moz-transform: translate(242px, 0px); -moz-transform: translate(242px, 0px);
-ms-transform: translate(242px, 0px); -ms-transform: translate(242px, 0px);
transform: translate(242px, 0px); } transform: translate(242px, 0px); }
.tile.tile-position-3-2 { .tile.tile-position-3-2 {
-webkit-transform: translate(242px, 121px); -webkit-transform: translate(242px, 121px);
-moz-transform: translate(242px, 121px); -moz-transform: translate(242px, 121px);
-ms-transform: translate(242px, 121px); -ms-transform: translate(242px, 121px);
transform: translate(242px, 121px); } transform: translate(242px, 121px); }
.tile.tile-position-3-3 { .tile.tile-position-3-3 {
-webkit-transform: translate(242px, 242px); -webkit-transform: translate(242px, 242px);
-moz-transform: translate(242px, 242px); -moz-transform: translate(242px, 242px);
-ms-transform: translate(242px, 242px); -ms-transform: translate(242px, 242px);
transform: translate(242px, 242px); } transform: translate(242px, 242px); }
.tile.tile-position-3-4 { .tile.tile-position-3-4 {
-webkit-transform: translate(242px, 363px); -webkit-transform: translate(242px, 363px);
-moz-transform: translate(242px, 363px); -moz-transform: translate(242px, 363px);
-ms-transform: translate(242px, 363px); -ms-transform: translate(242px, 363px);
transform: translate(242px, 363px); } transform: translate(242px, 363px); }
.tile.tile-position-4-1 { .tile.tile-position-4-1 {
-webkit-transform: translate(363px, 0px); -webkit-transform: translate(363px, 0px);
-moz-transform: translate(363px, 0px); -moz-transform: translate(363px, 0px);
-ms-transform: translate(363px, 0px); -ms-transform: translate(363px, 0px);
transform: translate(363px, 0px); } transform: translate(363px, 0px); }
.tile.tile-position-4-2 { .tile.tile-position-4-2 {
-webkit-transform: translate(363px, 121px); -webkit-transform: translate(363px, 121px);
-moz-transform: translate(363px, 121px); -moz-transform: translate(363px, 121px);
-ms-transform: translate(363px, 121px); -ms-transform: translate(363px, 121px);
transform: translate(363px, 121px); } transform: translate(363px, 121px); }
.tile.tile-position-4-3 { .tile.tile-position-4-3 {
-webkit-transform: translate(363px, 242px); -webkit-transform: translate(363px, 242px);
-moz-transform: translate(363px, 242px); -moz-transform: translate(363px, 242px);
-ms-transform: translate(363px, 242px); -ms-transform: translate(363px, 242px);
transform: translate(363px, 242px); } transform: translate(363px, 242px); }
.tile.tile-position-4-4 { .tile.tile-position-4-4 {
-webkit-transform: translate(363px, 363px); -webkit-transform: translate(363px, 363px);
-moz-transform: translate(363px, 363px); -moz-transform: translate(363px, 363px);
@@ -348,40 +334,40 @@ hr {
background: #eee4da; background: #eee4da;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); }
.tile.tile-4 .tile-inner { .tile.tile-4 .tile-inner {
background: #eee1c9; background: #ede0c8;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); } box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0), inset 0 0 0 1px rgba(255, 255, 255, 0); }
.tile.tile-8 .tile-inner { .tile.tile-8 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #f3b27a; } background: #f2b179; }
.tile.tile-16 .tile-inner { .tile.tile-16 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #f69664; } background: #f59563; }
.tile.tile-32 .tile-inner { .tile.tile-32 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #f77c5f; } background: #f67c5f; }
.tile.tile-64 .tile-inner { .tile.tile-64 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #f75f3b; } background: #f65e3b; }
.tile.tile-128 .tile-inner { .tile.tile-128 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #edd073; background: #edcf72;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.238095), inset 0 0 0 1px rgba(255, 255, 255, 0.142857); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.2381), inset 0 0 0 1px rgba(255, 255, 255, 0.14286);
font-size: 45px; } font-size: 45px; }
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
.tile.tile-128 .tile-inner { .tile.tile-128 .tile-inner {
font-size: 25px; } } font-size: 25px; } }
.tile.tile-256 .tile-inner { .tile.tile-256 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #edcc62; background: #edcc61;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.190476); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.31746), inset 0 0 0 1px rgba(255, 255, 255, 0.19048);
font-size: 45px; } font-size: 45px; }
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
.tile.tile-256 .tile-inner { .tile.tile-256 .tile-inner {
font-size: 25px; } } font-size: 25px; } }
.tile.tile-512 .tile-inner { .tile.tile-512 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #edc950; background: #edc850;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.396825), inset 0 0 0 1px rgba(255, 255, 255, 0.238095); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.39683), inset 0 0 0 1px rgba(255, 255, 255, 0.2381);
font-size: 45px; } font-size: 45px; }
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
.tile.tile-512 .tile-inner { .tile.tile-512 .tile-inner {
@@ -389,7 +375,7 @@ hr {
.tile.tile-1024 .tile-inner { .tile.tile-1024 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #edc53f; background: #edc53f;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.285714); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.47619), inset 0 0 0 1px rgba(255, 255, 255, 0.28571);
font-size: 35px; } font-size: 35px; }
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
.tile.tile-1024 .tile-inner { .tile.tile-1024 .tile-inner {
@@ -397,61 +383,61 @@ hr {
.tile.tile-2048 .tile-inner { .tile.tile-2048 .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #edc22e; background: #edc22e;
box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.555556), inset 0 0 0 1px rgba(255, 255, 255, 0.333333); box-shadow: 0 0 30px 10px rgba(243, 215, 116, 0.55556), inset 0 0 0 1px rgba(255, 255, 255, 0.33333);
font-size: 35px; } font-size: 35px; }
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
.tile.tile-2048 .tile-inner { .tile.tile-2048 .tile-inner {
font-size: 15px; } } font-size: 15px; } }
.tile.tile-super .tile-inner { .tile.tile-super .tile-inner {
color: #f9f6f2; color: #f9f6f2;
background: #3c3a33; background: #3c3a32;
font-size: 30px; } font-size: 30px; }
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
.tile.tile-super .tile-inner { .tile.tile-super .tile-inner {
font-size: 10px; } } font-size: 10px; } }
@-webkit-keyframes $animation-name { @-webkit-keyframes appear {
0% { 0% {
opacity: 0; opacity: 0;
-webkit-transform: scale(0); -webkit-transform: scale(0);
-moz-transform: scale(0); -moz-transform: scale(0);
-ms-transform: scale(0); -ms-transform: scale(0);
transform: scale(0); } transform: scale(0); }
100% { 100% {
opacity: 1; opacity: 1;
-webkit-transform: scale(1); -webkit-transform: scale(1);
-moz-transform: scale(1); -moz-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); } } transform: scale(1); } }
@-moz-keyframes appear {
@-moz-keyframes $animation-name {
0% { 0% {
opacity: 0; opacity: 0;
-webkit-transform: scale(0); -webkit-transform: scale(0);
-moz-transform: scale(0); -moz-transform: scale(0);
-ms-transform: scale(0); -ms-transform: scale(0);
transform: scale(0); } transform: scale(0); }
100% { 100% {
opacity: 1; opacity: 1;
-webkit-transform: scale(1); -webkit-transform: scale(1);
-moz-transform: scale(1); -moz-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); } } transform: scale(1); } }
@keyframes appear {
@keyframes $animation-name {
0% { 0% {
opacity: 0; opacity: 0;
-webkit-transform: scale(0); -webkit-transform: scale(0);
-moz-transform: scale(0); -moz-transform: scale(0);
-ms-transform: scale(0); -ms-transform: scale(0);
transform: scale(0); } transform: scale(0); }
100% { 100% {
opacity: 1; opacity: 1;
-webkit-transform: scale(1); -webkit-transform: scale(1);
-moz-transform: scale(1); -moz-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); } } transform: scale(1); } }
.tile-new .tile-inner { .tile-new .tile-inner {
-webkit-animation: appear 200ms ease 100ms; -webkit-animation: appear 200ms ease 100ms;
-moz-animation: appear 200ms ease 100ms; -moz-animation: appear 200ms ease 100ms;
@@ -460,57 +446,60 @@ hr {
-moz-animation-fill-mode: backwards; -moz-animation-fill-mode: backwards;
animation-fill-mode: backwards; } animation-fill-mode: backwards; }
@-webkit-keyframes $animation-name { @-webkit-keyframes pop {
0% { 0% {
-webkit-transform: scale(0); -webkit-transform: scale(0);
-moz-transform: scale(0); -moz-transform: scale(0);
-ms-transform: scale(0); -ms-transform: scale(0);
transform: scale(0); } transform: scale(0); }
50% { 50% {
-webkit-transform: scale(1.2); -webkit-transform: scale(1.2);
-moz-transform: scale(1.2); -moz-transform: scale(1.2);
-ms-transform: scale(1.2); -ms-transform: scale(1.2);
transform: scale(1.2); } transform: scale(1.2); }
100% { 100% {
-webkit-transform: scale(1); -webkit-transform: scale(1);
-moz-transform: scale(1); -moz-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); } } transform: scale(1); } }
@-moz-keyframes pop {
@-moz-keyframes $animation-name {
0% { 0% {
-webkit-transform: scale(0); -webkit-transform: scale(0);
-moz-transform: scale(0); -moz-transform: scale(0);
-ms-transform: scale(0); -ms-transform: scale(0);
transform: scale(0); } transform: scale(0); }
50% { 50% {
-webkit-transform: scale(1.2); -webkit-transform: scale(1.2);
-moz-transform: scale(1.2); -moz-transform: scale(1.2);
-ms-transform: scale(1.2); -ms-transform: scale(1.2);
transform: scale(1.2); } transform: scale(1.2); }
100% { 100% {
-webkit-transform: scale(1); -webkit-transform: scale(1);
-moz-transform: scale(1); -moz-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); } } transform: scale(1); } }
@keyframes pop {
@keyframes $animation-name {
0% { 0% {
-webkit-transform: scale(0); -webkit-transform: scale(0);
-moz-transform: scale(0); -moz-transform: scale(0);
-ms-transform: scale(0); -ms-transform: scale(0);
transform: scale(0); } transform: scale(0); }
50% { 50% {
-webkit-transform: scale(1.2); -webkit-transform: scale(1.2);
-moz-transform: scale(1.2); -moz-transform: scale(1.2);
-ms-transform: scale(1.2); -ms-transform: scale(1.2);
transform: scale(1.2); } transform: scale(1.2); }
100% { 100% {
-webkit-transform: scale(1); -webkit-transform: scale(1);
-moz-transform: scale(1); -moz-transform: scale(1);
-ms-transform: scale(1); -ms-transform: scale(1);
transform: scale(1); } } transform: scale(1); } }
.tile-merged .tile-inner { .tile-merged .tile-inner {
z-index: 20; z-index: 20;
-webkit-animation: pop 200ms ease 100ms; -webkit-animation: pop 200ms ease 100ms;
@@ -549,36 +538,44 @@ hr {
@media screen and (max-width: 520px) { @media screen and (max-width: 520px) {
html, body { html, body {
font-size: 15px; } font-size: 15px; }
body { body {
margin: 20px 0; margin: 20px 0;
padding: 0 20px; } padding: 0 20px; }
h1.title { h1.title {
font-size: 27px; font-size: 27px;
margin-top: 15px; } margin-top: 15px; }
.container { .container {
width: 280px; width: 280px;
margin: 0 auto; } margin: 0 auto; }
.score-container, .best-container { .score-container, .best-container {
margin-top: 0; margin-top: 0;
padding: 15px 10px; padding: 15px 10px;
min-width: 40px; } min-width: 40px; }
.heading { .heading {
margin-bottom: 10px; } margin-bottom: 10px; }
.game-intro { .game-intro {
width: 55%; width: 55%;
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
line-height: 1.65; } line-height: 1.65; }
.restart-button { .restart-button {
width: 42%; width: 42%;
padding: 0; padding: 0;
display: block; display: block;
box-sizing: border-box; box-sizing: border-box;
margin-top: 2px; } margin-top: 2px; }
.game-container { .game-container {
margin-top: 40px; margin-top: 17px;
position: relative; position: relative;
padding: 15px; padding: 10px;
cursor: default; cursor: default;
-webkit-touch-callout: none; -webkit-touch-callout: none;
-ms-touch-callout: none; -ms-touch-callout: none;
@@ -589,8 +586,8 @@ hr {
touch-action: none; touch-action: none;
background: #bbada0; background: #bbada0;
border-radius: 6px; border-radius: 6px;
width: 500px; width: 280px;
height: 500px; height: 280px;
-webkit-box-sizing: border-box; -webkit-box-sizing: border-box;
-moz-box-sizing: border-box; -moz-box-sizing: border-box;
box-sizing: border-box; } box-sizing: border-box; }
@@ -638,115 +635,122 @@ hr {
display: inline-block; } display: inline-block; }
.game-container .game-message.game-won, .game-container .game-message.game-over { .game-container .game-message.game-won, .game-container .game-message.game-over {
display: block; } display: block; }
.grid-container { .grid-container {
position: absolute; position: absolute;
z-index: 1; } z-index: 1; }
.grid-row { .grid-row {
margin-bottom: 15px; } margin-bottom: 10px; }
.grid-row:last-child { .grid-row:last-child {
margin-bottom: 0; } margin-bottom: 0; }
.grid-row:after { .grid-row:after {
content: ""; content: "";
display: block; display: block;
clear: both; } clear: both; }
.grid-cell { .grid-cell {
width: 106.25px; width: 57.5px;
height: 106.25px; height: 57.5px;
margin-right: 15px; margin-right: 10px;
float: left; float: left;
border-radius: 3px; border-radius: 3px;
background: rgba(238, 228, 218, 0.35); } background: rgba(238, 228, 218, 0.35); }
.grid-cell:last-child { .grid-cell:last-child {
margin-right: 0; } margin-right: 0; }
.tile-container { .tile-container {
position: absolute; position: absolute;
z-index: 2; } z-index: 2; }
.tile, .tile .tile-inner { .tile, .tile .tile-inner {
width: 107px; width: 58px;
height: 107px; height: 58px;
line-height: 107px; } line-height: 58px; }
.tile.tile-position-1-1 { .tile.tile-position-1-1 {
-webkit-transform: translate(0px, 0px); -webkit-transform: translate(0px, 0px);
-moz-transform: translate(0px, 0px); -moz-transform: translate(0px, 0px);
-ms-transform: translate(0px, 0px); -ms-transform: translate(0px, 0px);
transform: translate(0px, 0px); } transform: translate(0px, 0px); }
.tile.tile-position-1-2 { .tile.tile-position-1-2 {
-webkit-transform: translate(0px, 121px); -webkit-transform: translate(0px, 67px);
-moz-transform: translate(0px, 121px); -moz-transform: translate(0px, 67px);
-ms-transform: translate(0px, 121px); -ms-transform: translate(0px, 67px);
transform: translate(0px, 121px); } transform: translate(0px, 67px); }
.tile.tile-position-1-3 { .tile.tile-position-1-3 {
-webkit-transform: translate(0px, 242px); -webkit-transform: translate(0px, 135px);
-moz-transform: translate(0px, 242px); -moz-transform: translate(0px, 135px);
-ms-transform: translate(0px, 242px); -ms-transform: translate(0px, 135px);
transform: translate(0px, 242px); } transform: translate(0px, 135px); }
.tile.tile-position-1-4 { .tile.tile-position-1-4 {
-webkit-transform: translate(0px, 363px); -webkit-transform: translate(0px, 202px);
-moz-transform: translate(0px, 363px); -moz-transform: translate(0px, 202px);
-ms-transform: translate(0px, 363px); -ms-transform: translate(0px, 202px);
transform: translate(0px, 363px); } transform: translate(0px, 202px); }
.tile.tile-position-2-1 { .tile.tile-position-2-1 {
-webkit-transform: translate(121px, 0px); -webkit-transform: translate(67px, 0px);
-moz-transform: translate(121px, 0px); -moz-transform: translate(67px, 0px);
-ms-transform: translate(121px, 0px); -ms-transform: translate(67px, 0px);
transform: translate(121px, 0px); } transform: translate(67px, 0px); }
.tile.tile-position-2-2 { .tile.tile-position-2-2 {
-webkit-transform: translate(121px, 121px); -webkit-transform: translate(67px, 67px);
-moz-transform: translate(121px, 121px); -moz-transform: translate(67px, 67px);
-ms-transform: translate(121px, 121px); -ms-transform: translate(67px, 67px);
transform: translate(121px, 121px); } transform: translate(67px, 67px); }
.tile.tile-position-2-3 { .tile.tile-position-2-3 {
-webkit-transform: translate(121px, 242px); -webkit-transform: translate(67px, 135px);
-moz-transform: translate(121px, 242px); -moz-transform: translate(67px, 135px);
-ms-transform: translate(121px, 242px); -ms-transform: translate(67px, 135px);
transform: translate(121px, 242px); } transform: translate(67px, 135px); }
.tile.tile-position-2-4 { .tile.tile-position-2-4 {
-webkit-transform: translate(121px, 363px); -webkit-transform: translate(67px, 202px);
-moz-transform: translate(121px, 363px); -moz-transform: translate(67px, 202px);
-ms-transform: translate(121px, 363px); -ms-transform: translate(67px, 202px);
transform: translate(121px, 363px); } transform: translate(67px, 202px); }
.tile.tile-position-3-1 { .tile.tile-position-3-1 {
-webkit-transform: translate(242px, 0px); -webkit-transform: translate(135px, 0px);
-moz-transform: translate(242px, 0px); -moz-transform: translate(135px, 0px);
-ms-transform: translate(242px, 0px); -ms-transform: translate(135px, 0px);
transform: translate(242px, 0px); } transform: translate(135px, 0px); }
.tile.tile-position-3-2 { .tile.tile-position-3-2 {
-webkit-transform: translate(242px, 121px); -webkit-transform: translate(135px, 67px);
-moz-transform: translate(242px, 121px); -moz-transform: translate(135px, 67px);
-ms-transform: translate(242px, 121px); -ms-transform: translate(135px, 67px);
transform: translate(242px, 121px); } transform: translate(135px, 67px); }
.tile.tile-position-3-3 { .tile.tile-position-3-3 {
-webkit-transform: translate(242px, 242px); -webkit-transform: translate(135px, 135px);
-moz-transform: translate(242px, 242px); -moz-transform: translate(135px, 135px);
-ms-transform: translate(242px, 242px); -ms-transform: translate(135px, 135px);
transform: translate(242px, 242px); } transform: translate(135px, 135px); }
.tile.tile-position-3-4 { .tile.tile-position-3-4 {
-webkit-transform: translate(242px, 363px); -webkit-transform: translate(135px, 202px);
-moz-transform: translate(242px, 363px); -moz-transform: translate(135px, 202px);
-ms-transform: translate(242px, 363px); -ms-transform: translate(135px, 202px);
transform: translate(242px, 363px); } transform: translate(135px, 202px); }
.tile.tile-position-4-1 { .tile.tile-position-4-1 {
-webkit-transform: translate(363px, 0px); -webkit-transform: translate(202px, 0px);
-moz-transform: translate(363px, 0px); -moz-transform: translate(202px, 0px);
-ms-transform: translate(363px, 0px); -ms-transform: translate(202px, 0px);
transform: translate(363px, 0px); } transform: translate(202px, 0px); }
.tile.tile-position-4-2 { .tile.tile-position-4-2 {
-webkit-transform: translate(363px, 121px); -webkit-transform: translate(202px, 67px);
-moz-transform: translate(363px, 121px); -moz-transform: translate(202px, 67px);
-ms-transform: translate(363px, 121px); -ms-transform: translate(202px, 67px);
transform: translate(363px, 121px); } transform: translate(202px, 67px); }
.tile.tile-position-4-3 { .tile.tile-position-4-3 {
-webkit-transform: translate(363px, 242px); -webkit-transform: translate(202px, 135px);
-moz-transform: translate(363px, 242px); -moz-transform: translate(202px, 135px);
-ms-transform: translate(363px, 242px); -ms-transform: translate(202px, 135px);
transform: translate(363px, 242px); } transform: translate(202px, 135px); }
.tile.tile-position-4-4 { .tile.tile-position-4-4 {
-webkit-transform: translate(363px, 363px); -webkit-transform: translate(202px, 202px);
-moz-transform: translate(363px, 363px); -moz-transform: translate(202px, 202px);
-ms-transform: translate(363px, 363px); -ms-transform: translate(202px, 202px);
transform: translate(363px, 363px); } transform: translate(202px, 202px); }
.tile .tile-inner { .tile .tile-inner {
font-size: 35px; } font-size: 35px; }
.game-message p { .game-message p {
font-size: 30px !important; font-size: 30px !important;
height: 30px !important; height: 30px !important;

View File

@@ -32,7 +32,7 @@ html, body {
} }
body { body {
margin: 40px 0; margin: 80px 0;
} }
.heading { .heading {

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 class="container">
<div class="heading">
<h1 class="title">2048</h1>
<div class="scores-container">
<div class="score-container score-container-game2">0</div>
<div class="best-container best-container-game2">0</div>
</div> </div>
</div> </div>
<p class="game-explanation"> <div class="game-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="game-message game-message-game2">
</p> <p></p>
<hr> <div class="lower">
<p> <a class="keep-playing-button">Keep going</a>
<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>. <a class="retry-button">Try again</a>
</p> </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>