Path: blob/main/projects/9007199254740992/js/game_manager.js
4626 views
function GameManager(size, InputManager, Actuator, ScoreManager) {1this.size = size; // Size of the grid2this.inputManager = new InputManager;3this.scoreManager = new ScoreManager;4this.actuator = new Actuator;56this.startTiles = 2;78this.inputManager.on("move", this.move.bind(this));9this.inputManager.on("restart", this.restart.bind(this));1011this.setup();12}1314// Restart the game15GameManager.prototype.restart = function () {16this.actuator.restart();17this.setup();18};1920// Set up the game21GameManager.prototype.setup = function () {22this.grid = new Grid(this.size);2324this.score = 0;25this.over = false;26this.won = false;2728// Add the initial tiles29this.addStartTiles();3031// Update the actuator32this.actuate();33};3435// Set up the initial tiles to start the game with36GameManager.prototype.addStartTiles = function () {37for (var i = 0; i < this.startTiles; i++) {38this.addRandomTile();39}40};4142// Adds a tile in a random position43GameManager.prototype.addRandomTile = function () {44if (this.grid.cellsAvailable()) {45var value = Math.random() < 0.9 ? 2 : 4;46var tile = new Tile(this.grid.randomAvailableCell(), value);4748this.grid.insertTile(tile);49}50};5152// Sends the updated grid to the actuator53GameManager.prototype.actuate = function () {54if (this.scoreManager.get() < this.score) {55this.scoreManager.set(this.score);56}5758this.actuator.actuate(this.grid, {59score: this.score,60over: this.over,61won: this.won,62bestScore: this.scoreManager.get()63});6465};6667// Save all tile positions and remove merger info68GameManager.prototype.prepareTiles = function () {69this.grid.eachCell(function (x, y, tile) {70if (tile) {71tile.mergedFrom = null;72tile.savePosition();73}74});75};7677// Move a tile and its representation78GameManager.prototype.moveTile = function (tile, cell) {79this.grid.cells[tile.x][tile.y] = null;80this.grid.cells[cell.x][cell.y] = tile;81tile.updatePosition(cell);82};8384// Move tiles on the grid in the specified direction85GameManager.prototype.move = function (direction) {86// 0: up, 1: right, 2:down, 3: left87var self = this;8889if (this.over || this.won) return; // Don't do anything if the game's over9091var cell, tile;9293var vector = this.getVector(direction);94var traversals = this.buildTraversals(vector);95var moved = false;9697// Save the current tile positions and remove merger information98this.prepareTiles();99100// Traverse the grid in the right direction and move tiles101traversals.x.forEach(function (x) {102traversals.y.forEach(function (y) {103cell = { x: x, y: y };104tile = self.grid.cellContent(cell);105106if (tile) {107var positions = self.findFarthestPosition(cell, vector);108var next = self.grid.cellContent(positions.next);109110// Only one merger per row traversal?111if (next && next.value === tile.value && !next.mergedFrom) {112var merged = new Tile(positions.next, tile.value * 2);113merged.mergedFrom = [tile, next];114115self.grid.insertTile(merged);116self.grid.removeTile(tile);117118// Converge the two tiles' positions119tile.updatePosition(positions.next);120121// Update the score122self.score += merged.value;123124// The mighty 2048 tile125if (merged.value === 9007199254740992) self.won = true;126} else {127self.moveTile(tile, positions.farthest);128}129130if (!self.positionsEqual(cell, tile)) {131moved = true; // The tile moved from its original cell!132}133}134});135});136137if (moved) {138this.addRandomTile();139140if (!this.movesAvailable()) {141this.over = true; // Game over!142}143144this.actuate();145}146};147148// Get the vector representing the chosen direction149GameManager.prototype.getVector = function (direction) {150// Vectors representing tile movement151var map = {1520: { x: 0, y: -1 }, // up1531: { x: 1, y: 0 }, // right1542: { x: 0, y: 1 }, // down1553: { x: -1, y: 0 } // left156};157158return map[direction];159};160161// Build a list of positions to traverse in the right order162GameManager.prototype.buildTraversals = function (vector) {163var traversals = { x: [], y: [] };164165for (var pos = 0; pos < this.size; pos++) {166traversals.x.push(pos);167traversals.y.push(pos);168}169170// Always traverse from the farthest cell in the chosen direction171if (vector.x === 1) traversals.x = traversals.x.reverse();172if (vector.y === 1) traversals.y = traversals.y.reverse();173174return traversals;175};176177GameManager.prototype.findFarthestPosition = function (cell, vector) {178var previous;179180// Progress towards the vector direction until an obstacle is found181do {182previous = cell;183cell = { x: previous.x + vector.x, y: previous.y + vector.y };184} while (this.grid.withinBounds(cell) &&185this.grid.cellAvailable(cell));186187return {188farthest: previous,189next: cell // Used to check if a merge is required190};191};192193GameManager.prototype.movesAvailable = function () {194return this.grid.cellsAvailable() || this.tileMatchesAvailable();195};196197// Check for available matches between tiles (more expensive check)198GameManager.prototype.tileMatchesAvailable = function () {199var self = this;200201var tile;202203for (var x = 0; x < this.size; x++) {204for (var y = 0; y < this.size; y++) {205tile = this.grid.cellContent({ x: x, y: y });206207if (tile) {208for (var direction = 0; direction < 4; direction++) {209var vector = self.getVector(direction);210var cell = { x: x + vector.x, y: y + vector.y };211212var other = self.grid.cellContent(cell);213214if (other && other.value === tile.value) {215return true; // These two tiles can be merged216}217}218}219}220}221222return false;223};224225GameManager.prototype.positionsEqual = function (first, second) {226return first.x === second.x && first.y === second.y;227};228229230