Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mamayaya1
GitHub Repository: mamayaya1/game
Path: blob/main/projects/9007199254740992/js/game_manager.js
4626 views
1
function GameManager(size, InputManager, Actuator, ScoreManager) {
2
this.size = size; // Size of the grid
3
this.inputManager = new InputManager;
4
this.scoreManager = new ScoreManager;
5
this.actuator = new Actuator;
6
7
this.startTiles = 2;
8
9
this.inputManager.on("move", this.move.bind(this));
10
this.inputManager.on("restart", this.restart.bind(this));
11
12
this.setup();
13
}
14
15
// Restart the game
16
GameManager.prototype.restart = function () {
17
this.actuator.restart();
18
this.setup();
19
};
20
21
// Set up the game
22
GameManager.prototype.setup = function () {
23
this.grid = new Grid(this.size);
24
25
this.score = 0;
26
this.over = false;
27
this.won = false;
28
29
// Add the initial tiles
30
this.addStartTiles();
31
32
// Update the actuator
33
this.actuate();
34
};
35
36
// Set up the initial tiles to start the game with
37
GameManager.prototype.addStartTiles = function () {
38
for (var i = 0; i < this.startTiles; i++) {
39
this.addRandomTile();
40
}
41
};
42
43
// Adds a tile in a random position
44
GameManager.prototype.addRandomTile = function () {
45
if (this.grid.cellsAvailable()) {
46
var value = Math.random() < 0.9 ? 2 : 4;
47
var tile = new Tile(this.grid.randomAvailableCell(), value);
48
49
this.grid.insertTile(tile);
50
}
51
};
52
53
// Sends the updated grid to the actuator
54
GameManager.prototype.actuate = function () {
55
if (this.scoreManager.get() < this.score) {
56
this.scoreManager.set(this.score);
57
}
58
59
this.actuator.actuate(this.grid, {
60
score: this.score,
61
over: this.over,
62
won: this.won,
63
bestScore: this.scoreManager.get()
64
});
65
66
};
67
68
// Save all tile positions and remove merger info
69
GameManager.prototype.prepareTiles = function () {
70
this.grid.eachCell(function (x, y, tile) {
71
if (tile) {
72
tile.mergedFrom = null;
73
tile.savePosition();
74
}
75
});
76
};
77
78
// Move a tile and its representation
79
GameManager.prototype.moveTile = function (tile, cell) {
80
this.grid.cells[tile.x][tile.y] = null;
81
this.grid.cells[cell.x][cell.y] = tile;
82
tile.updatePosition(cell);
83
};
84
85
// Move tiles on the grid in the specified direction
86
GameManager.prototype.move = function (direction) {
87
// 0: up, 1: right, 2:down, 3: left
88
var self = this;
89
90
if (this.over || this.won) return; // Don't do anything if the game's over
91
92
var cell, tile;
93
94
var vector = this.getVector(direction);
95
var traversals = this.buildTraversals(vector);
96
var moved = false;
97
98
// Save the current tile positions and remove merger information
99
this.prepareTiles();
100
101
// Traverse the grid in the right direction and move tiles
102
traversals.x.forEach(function (x) {
103
traversals.y.forEach(function (y) {
104
cell = { x: x, y: y };
105
tile = self.grid.cellContent(cell);
106
107
if (tile) {
108
var positions = self.findFarthestPosition(cell, vector);
109
var next = self.grid.cellContent(positions.next);
110
111
// Only one merger per row traversal?
112
if (next && next.value === tile.value && !next.mergedFrom) {
113
var merged = new Tile(positions.next, tile.value * 2);
114
merged.mergedFrom = [tile, next];
115
116
self.grid.insertTile(merged);
117
self.grid.removeTile(tile);
118
119
// Converge the two tiles' positions
120
tile.updatePosition(positions.next);
121
122
// Update the score
123
self.score += merged.value;
124
125
// The mighty 2048 tile
126
if (merged.value === 9007199254740992) self.won = true;
127
} else {
128
self.moveTile(tile, positions.farthest);
129
}
130
131
if (!self.positionsEqual(cell, tile)) {
132
moved = true; // The tile moved from its original cell!
133
}
134
}
135
});
136
});
137
138
if (moved) {
139
this.addRandomTile();
140
141
if (!this.movesAvailable()) {
142
this.over = true; // Game over!
143
}
144
145
this.actuate();
146
}
147
};
148
149
// Get the vector representing the chosen direction
150
GameManager.prototype.getVector = function (direction) {
151
// Vectors representing tile movement
152
var map = {
153
0: { x: 0, y: -1 }, // up
154
1: { x: 1, y: 0 }, // right
155
2: { x: 0, y: 1 }, // down
156
3: { x: -1, y: 0 } // left
157
};
158
159
return map[direction];
160
};
161
162
// Build a list of positions to traverse in the right order
163
GameManager.prototype.buildTraversals = function (vector) {
164
var traversals = { x: [], y: [] };
165
166
for (var pos = 0; pos < this.size; pos++) {
167
traversals.x.push(pos);
168
traversals.y.push(pos);
169
}
170
171
// Always traverse from the farthest cell in the chosen direction
172
if (vector.x === 1) traversals.x = traversals.x.reverse();
173
if (vector.y === 1) traversals.y = traversals.y.reverse();
174
175
return traversals;
176
};
177
178
GameManager.prototype.findFarthestPosition = function (cell, vector) {
179
var previous;
180
181
// Progress towards the vector direction until an obstacle is found
182
do {
183
previous = cell;
184
cell = { x: previous.x + vector.x, y: previous.y + vector.y };
185
} while (this.grid.withinBounds(cell) &&
186
this.grid.cellAvailable(cell));
187
188
return {
189
farthest: previous,
190
next: cell // Used to check if a merge is required
191
};
192
};
193
194
GameManager.prototype.movesAvailable = function () {
195
return this.grid.cellsAvailable() || this.tileMatchesAvailable();
196
};
197
198
// Check for available matches between tiles (more expensive check)
199
GameManager.prototype.tileMatchesAvailable = function () {
200
var self = this;
201
202
var tile;
203
204
for (var x = 0; x < this.size; x++) {
205
for (var y = 0; y < this.size; y++) {
206
tile = this.grid.cellContent({ x: x, y: y });
207
208
if (tile) {
209
for (var direction = 0; direction < 4; direction++) {
210
var vector = self.getVector(direction);
211
var cell = { x: x + vector.x, y: y + vector.y };
212
213
var other = self.grid.cellContent(cell);
214
215
if (other && other.value === tile.value) {
216
return true; // These two tiles can be merged
217
}
218
}
219
}
220
}
221
}
222
223
return false;
224
};
225
226
GameManager.prototype.positionsEqual = function (first, second) {
227
return first.x === second.x && first.y === second.y;
228
};
229
230