PageSourceSearch

https://framagames.org/1597-master/js/game_manager.js

js framagames.org collected 2026-10-08 06:46:06 UTC 6,927 bytes, 264 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.