schooluk-2048 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,139 @@
1
+ function HTMLActuator() {
2
+ this.tileContainer = document.querySelector(".tile-container");
3
+ this.scoreContainer = document.querySelector(".score-container");
4
+ this.bestContainer = document.querySelector(".best-container");
5
+ this.messageContainer = document.querySelector(".game-message");
6
+
7
+ this.score = 0;
8
+ }
9
+
10
+ HTMLActuator.prototype.actuate = function (grid, metadata) {
11
+ var self = this;
12
+
13
+ window.requestAnimationFrame(function () {
14
+ self.clearContainer(self.tileContainer);
15
+
16
+ grid.cells.forEach(function (column) {
17
+ column.forEach(function (cell) {
18
+ if (cell) {
19
+ self.addTile(cell);
20
+ }
21
+ });
22
+ });
23
+
24
+ self.updateScore(metadata.score);
25
+ self.updateBestScore(metadata.bestScore);
26
+
27
+ if (metadata.terminated) {
28
+ if (metadata.over) {
29
+ self.message(false); // You lose
30
+ } else if (metadata.won) {
31
+ self.message(true); // You win!
32
+ }
33
+ }
34
+
35
+ });
36
+ };
37
+
38
+ // Continues the game (both restart and keep playing)
39
+ HTMLActuator.prototype.continueGame = function () {
40
+ this.clearMessage();
41
+ };
42
+
43
+ HTMLActuator.prototype.clearContainer = function (container) {
44
+ while (container.firstChild) {
45
+ container.removeChild(container.firstChild);
46
+ }
47
+ };
48
+
49
+ HTMLActuator.prototype.addTile = function (tile) {
50
+ var self = this;
51
+
52
+ var wrapper = document.createElement("div");
53
+ var inner = document.createElement("div");
54
+ var position = tile.previousPosition || { x: tile.x, y: tile.y };
55
+ var positionClass = this.positionClass(position);
56
+
57
+ // We can't use classlist because it somehow glitches when replacing classes
58
+ var classes = ["tile", "tile-" + tile.value, positionClass];
59
+
60
+ if (tile.value > 2048) classes.push("tile-super");
61
+
62
+ this.applyClasses(wrapper, classes);
63
+
64
+ inner.classList.add("tile-inner");
65
+ inner.textContent = tile.value;
66
+
67
+ if (tile.previousPosition) {
68
+ // Make sure that the tile gets rendered in the previous position first
69
+ window.requestAnimationFrame(function () {
70
+ classes[2] = self.positionClass({ x: tile.x, y: tile.y });
71
+ self.applyClasses(wrapper, classes); // Update the position
72
+ });
73
+ } else if (tile.mergedFrom) {
74
+ classes.push("tile-merged");
75
+ this.applyClasses(wrapper, classes);
76
+
77
+ // Render the tiles that merged
78
+ tile.mergedFrom.forEach(function (merged) {
79
+ self.addTile(merged);
80
+ });
81
+ } else {
82
+ classes.push("tile-new");
83
+ this.applyClasses(wrapper, classes);
84
+ }
85
+
86
+ // Add the inner part of the tile to the wrapper
87
+ wrapper.appendChild(inner);
88
+
89
+ // Put the tile on the board
90
+ this.tileContainer.appendChild(wrapper);
91
+ };
92
+
93
+ HTMLActuator.prototype.applyClasses = function (element, classes) {
94
+ element.setAttribute("class", classes.join(" "));
95
+ };
96
+
97
+ HTMLActuator.prototype.normalizePosition = function (position) {
98
+ return { x: position.x + 1, y: position.y + 1 };
99
+ };
100
+
101
+ HTMLActuator.prototype.positionClass = function (position) {
102
+ position = this.normalizePosition(position);
103
+ return "tile-position-" + position.x + "-" + position.y;
104
+ };
105
+
106
+ HTMLActuator.prototype.updateScore = function (score) {
107
+ this.clearContainer(this.scoreContainer);
108
+
109
+ var difference = score - this.score;
110
+ this.score = score;
111
+
112
+ this.scoreContainer.textContent = this.score;
113
+
114
+ if (difference > 0) {
115
+ var addition = document.createElement("div");
116
+ addition.classList.add("score-addition");
117
+ addition.textContent = "+" + difference;
118
+
119
+ this.scoreContainer.appendChild(addition);
120
+ }
121
+ };
122
+
123
+ HTMLActuator.prototype.updateBestScore = function (bestScore) {
124
+ this.bestContainer.textContent = bestScore;
125
+ };
126
+
127
+ HTMLActuator.prototype.message = function (won) {
128
+ var type = won ? "game-won" : "game-over";
129
+ var message = won ? "You win!" : "Game over!";
130
+
131
+ this.messageContainer.classList.add(type);
132
+ this.messageContainer.getElementsByTagName("p")[0].textContent = message;
133
+ };
134
+
135
+ HTMLActuator.prototype.clearMessage = function () {
136
+ // IE only takes one value to remove at a time.
137
+ this.messageContainer.classList.remove("game-won");
138
+ this.messageContainer.classList.remove("game-over");
139
+ };
@@ -0,0 +1,144 @@
1
+ function KeyboardInputManager() {
2
+ this.events = {};
3
+
4
+ if (window.navigator.msPointerEnabled) {
5
+ //Internet Explorer 10 style
6
+ this.eventTouchstart = "MSPointerDown";
7
+ this.eventTouchmove = "MSPointerMove";
8
+ this.eventTouchend = "MSPointerUp";
9
+ } else {
10
+ this.eventTouchstart = "touchstart";
11
+ this.eventTouchmove = "touchmove";
12
+ this.eventTouchend = "touchend";
13
+ }
14
+
15
+ this.listen();
16
+ }
17
+
18
+ KeyboardInputManager.prototype.on = function (event, callback) {
19
+ if (!this.events[event]) {
20
+ this.events[event] = [];
21
+ }
22
+ this.events[event].push(callback);
23
+ };
24
+
25
+ KeyboardInputManager.prototype.emit = function (event, data) {
26
+ var callbacks = this.events[event];
27
+ if (callbacks) {
28
+ callbacks.forEach(function (callback) {
29
+ callback(data);
30
+ });
31
+ }
32
+ };
33
+
34
+ KeyboardInputManager.prototype.listen = function () {
35
+ var self = this;
36
+
37
+ var map = {
38
+ 38: 0, // Up
39
+ 39: 1, // Right
40
+ 40: 2, // Down
41
+ 37: 3, // Left
42
+ 75: 0, // Vim up
43
+ 76: 1, // Vim right
44
+ 74: 2, // Vim down
45
+ 72: 3, // Vim left
46
+ 87: 0, // W
47
+ 68: 1, // D
48
+ 83: 2, // S
49
+ 65: 3 // A
50
+ };
51
+
52
+ // Respond to direction keys
53
+ document.addEventListener("keydown", function (event) {
54
+ var modifiers = event.altKey || event.ctrlKey || event.metaKey ||
55
+ event.shiftKey;
56
+ var mapped = map[event.which];
57
+
58
+ if (!modifiers) {
59
+ if (mapped !== undefined) {
60
+ event.preventDefault();
61
+ self.emit("move", mapped);
62
+ }
63
+ }
64
+
65
+ // R key restarts the game
66
+ if (!modifiers && event.which === 82) {
67
+ self.restart.call(self, event);
68
+ }
69
+ });
70
+
71
+ // Respond to button presses
72
+ this.bindButtonPress(".retry-button", this.restart);
73
+ this.bindButtonPress(".restart-button", this.restart);
74
+ this.bindButtonPress(".keep-playing-button", this.keepPlaying);
75
+
76
+ // Respond to swipe events
77
+ var touchStartClientX, touchStartClientY;
78
+ var gameContainer = document.getElementsByClassName("game-container")[0];
79
+
80
+ gameContainer.addEventListener(this.eventTouchstart, function (event) {
81
+ if ((!window.navigator.msPointerEnabled && event.touches.length > 1) ||
82
+ event.targetTouches.length > 1) {
83
+ return; // Ignore if touching with more than 1 finger
84
+ }
85
+
86
+ if (window.navigator.msPointerEnabled) {
87
+ touchStartClientX = event.pageX;
88
+ touchStartClientY = event.pageY;
89
+ } else {
90
+ touchStartClientX = event.touches[0].clientX;
91
+ touchStartClientY = event.touches[0].clientY;
92
+ }
93
+
94
+ event.preventDefault();
95
+ });
96
+
97
+ gameContainer.addEventListener(this.eventTouchmove, function (event) {
98
+ event.preventDefault();
99
+ });
100
+
101
+ gameContainer.addEventListener(this.eventTouchend, function (event) {
102
+ if ((!window.navigator.msPointerEnabled && event.touches.length > 0) ||
103
+ event.targetTouches.length > 0) {
104
+ return; // Ignore if still touching with one or more fingers
105
+ }
106
+
107
+ var touchEndClientX, touchEndClientY;
108
+
109
+ if (window.navigator.msPointerEnabled) {
110
+ touchEndClientX = event.pageX;
111
+ touchEndClientY = event.pageY;
112
+ } else {
113
+ touchEndClientX = event.changedTouches[0].clientX;
114
+ touchEndClientY = event.changedTouches[0].clientY;
115
+ }
116
+
117
+ var dx = touchEndClientX - touchStartClientX;
118
+ var absDx = Math.abs(dx);
119
+
120
+ var dy = touchEndClientY - touchStartClientY;
121
+ var absDy = Math.abs(dy);
122
+
123
+ if (Math.max(absDx, absDy) > 10) {
124
+ // (right : left) : (down : up)
125
+ self.emit("move", absDx > absDy ? (dx > 0 ? 1 : 3) : (dy > 0 ? 2 : 0));
126
+ }
127
+ });
128
+ };
129
+
130
+ KeyboardInputManager.prototype.restart = function (event) {
131
+ event.preventDefault();
132
+ this.emit("restart");
133
+ };
134
+
135
+ KeyboardInputManager.prototype.keepPlaying = function (event) {
136
+ event.preventDefault();
137
+ this.emit("keepPlaying");
138
+ };
139
+
140
+ KeyboardInputManager.prototype.bindButtonPress = function (selector, fn) {
141
+ var button = document.querySelector(selector);
142
+ button.addEventListener("click", fn.bind(this));
143
+ button.addEventListener(this.eventTouchend, fn.bind(this));
144
+ };
@@ -0,0 +1,63 @@
1
+ window.fakeStorage = {
2
+ _data: {},
3
+
4
+ setItem: function (id, val) {
5
+ return this._data[id] = String(val);
6
+ },
7
+
8
+ getItem: function (id) {
9
+ return this._data.hasOwnProperty(id) ? this._data[id] : undefined;
10
+ },
11
+
12
+ removeItem: function (id) {
13
+ return delete this._data[id];
14
+ },
15
+
16
+ clear: function () {
17
+ return this._data = {};
18
+ }
19
+ };
20
+
21
+ function LocalStorageManager() {
22
+ this.bestScoreKey = "bestScore";
23
+ this.gameStateKey = "gameState";
24
+
25
+ var supported = this.localStorageSupported();
26
+ this.storage = supported ? window.localStorage : window.fakeStorage;
27
+ }
28
+
29
+ LocalStorageManager.prototype.localStorageSupported = function () {
30
+ var testKey = "test";
31
+
32
+ try {
33
+ var storage = window.localStorage;
34
+ storage.setItem(testKey, "1");
35
+ storage.removeItem(testKey);
36
+ return true;
37
+ } catch (error) {
38
+ return false;
39
+ }
40
+ };
41
+
42
+ // Best score getters/setters
43
+ LocalStorageManager.prototype.getBestScore = function () {
44
+ return this.storage.getItem(this.bestScoreKey) || 0;
45
+ };
46
+
47
+ LocalStorageManager.prototype.setBestScore = function (score) {
48
+ this.storage.setItem(this.bestScoreKey, score);
49
+ };
50
+
51
+ // Game state getters/setters and clearing
52
+ LocalStorageManager.prototype.getGameState = function () {
53
+ var stateJSON = this.storage.getItem(this.gameStateKey);
54
+ return stateJSON ? JSON.parse(stateJSON) : null;
55
+ };
56
+
57
+ LocalStorageManager.prototype.setGameState = function (gameState) {
58
+ this.storage.setItem(this.gameStateKey, JSON.stringify(gameState));
59
+ };
60
+
61
+ LocalStorageManager.prototype.clearGameState = function () {
62
+ this.storage.removeItem(this.gameStateKey);
63
+ };
package/js/tile.js ADDED
@@ -0,0 +1,27 @@
1
+ function Tile(position, value) {
2
+ this.x = position.x;
3
+ this.y = position.y;
4
+ this.value = value || 2;
5
+
6
+ this.previousPosition = null;
7
+ this.mergedFrom = null; // Tracks tiles that merged together
8
+ }
9
+
10
+ Tile.prototype.savePosition = function () {
11
+ this.previousPosition = { x: this.x, y: this.y };
12
+ };
13
+
14
+ Tile.prototype.updatePosition = function (position) {
15
+ this.x = position.x;
16
+ this.y = position.y;
17
+ };
18
+
19
+ Tile.prototype.serialize = function () {
20
+ return {
21
+ position: {
22
+ x: this.x,
23
+ y: this.y
24
+ },
25
+ value: this.value
26
+ };
27
+ };
Binary file
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "schooluk-2048",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "type": "commonjs"
13
+ }