Path: blob/main/projects/1/js/game_manager.js
1834 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));10this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));1112this.setup();13}1415// Restart the game16GameManager.prototype.restart = function () {17this.actuator.continue();18this.setup();19};2021// Keep playing after winning22GameManager.prototype.keepPlaying = function () {23this.keepPlaying = true;24this.actuator.continue();25};2627GameManager.prototype.isGameTerminated = function () {28if (this.over || (this.won && !this.keepPlaying)) {29return true;30} else {31return false;32}33};3435// Set up the game36GameManager.prototype.setup = function () {37this.grid = new Grid(this.size);3839this.score = 0;40this.over = false;41this.won = false;42this.keepPlaying = false;4344// Add the initial tiles45this.addStartTiles();4647// Update the actuator48this.actuate();49};5051// Set up the initial tiles to start the game with52GameManager.prototype.addStartTiles = function () {53for (var i = 0; i < this.startTiles; i++) {54this.addRandomTile();55}56};5758// Adds a tile in a random position59GameManager.prototype.addRandomTile = function () {60if (this.grid.cellsAvailable()) {61var value = Math.random() < 0.9 ? 2048 : 1024;62var tile = new Tile(this.grid.randomAvailableCell(), value);6364this.grid.insertTile(tile);65}66};6768// Sends the updated grid to the actuator69GameManager.prototype.actuate = function () {70if (this.scoreManager.get() < this.score) {71this.scoreManager.set(this.score);72}7374this.actuator.actuate(this.grid, {75score: this.score,76over: this.over,77won: this.won,78bestScore: this.scoreManager.get(),79terminated: this.isGameTerminated()80});8182};8384// Save all tile positions and remove merger info85GameManager.prototype.prepareTiles = function () {86this.grid.eachCell(function (x, y, tile) {87if (tile) {88tile.mergedFrom = null;89tile.savePosition();90}91});92};9394// Move a tile and its representation95GameManager.prototype.moveTile = function (tile, cell) {96this.grid.cells[tile.x][tile.y] = null;97this.grid.cells[cell.x][cell.y] = tile;98tile.updatePosition(cell);99};100101// Move tiles on the grid in the specified direction102GameManager.prototype.move = function (direction) {103// 0: up, 1: right, 2:down, 3: left104var self = this;105106if (this.isGameTerminated()) return; // Don't do anything if the game's over107108var cell, tile;109110var vector = this.getVector(direction);111var traversals = this.buildTraversals(vector);112var moved = false;113114// Save the current tile positions and remove merger information115this.prepareTiles();116117// Traverse the grid in the right direction and move tiles118traversals.x.forEach(function (x) {119traversals.y.forEach(function (y) {120cell = { x: x, y: y };121tile = self.grid.cellContent(cell);122123if (tile) {124var positions = self.findFarthestPosition(cell, vector);125var next = self.grid.cellContent(positions.next);126127// Only one merger per row traversal?128if (next && next.value === tile.value && !next.mergedFrom) {129var merged = new Tile(positions.next, tile.value / 2);130merged.mergedFrom = [tile, next];131132self.grid.insertTile(merged);133self.grid.removeTile(tile);134135// Converge the two tiles' positions136tile.updatePosition(positions.next);137138// Update the score139self.score += merged.value;140141// The mighty 2048 tile142if (merged.value === 1) self.won = true;143} else {144self.moveTile(tile, positions.farthest);145}146147if (!self.positionsEqual(cell, tile)) {148moved = true; // The tile moved from its original cell!149}150}151});152});153154if (moved) {155this.addRandomTile();156157if (!this.movesAvailable()) {158this.over = true; // Game over!159}160161this.actuate();162}163};164165// Get the vector representing the chosen direction166GameManager.prototype.getVector = function (direction) {167// Vectors representing tile movement168var map = {1690: { x: 0, y: -1 }, // up1701: { x: 1, y: 0 }, // right1712: { x: 0, y: 1 }, // down1723: { x: -1, y: 0 } // left173};174175return map[direction];176};177178// Build a list of positions to traverse in the right order179GameManager.prototype.buildTraversals = function (vector) {180var traversals = { x: [], y: [] };181182for (var pos = 0; pos < this.size; pos++) {183traversals.x.push(pos);184traversals.y.push(pos);185}186187// Always traverse from the farthest cell in the chosen direction188if (vector.x === 1) traversals.x = traversals.x.reverse();189if (vector.y === 1) traversals.y = traversals.y.reverse();190191return traversals;192};193194GameManager.prototype.findFarthestPosition = function (cell, vector) {195var previous;196197// Progress towards the vector direction until an obstacle is found198do {199previous = cell;200cell = { x: previous.x + vector.x, y: previous.y + vector.y };201} while (this.grid.withinBounds(cell) &&202this.grid.cellAvailable(cell));203204return {205farthest: previous,206next: cell // Used to check if a merge is required207};208};209210GameManager.prototype.movesAvailable = function () {211return this.grid.cellsAvailable() || this.tileMatchesAvailable();212};213214// Check for available matches between tiles (more expensive check)215GameManager.prototype.tileMatchesAvailable = function () {216var self = this;217218var tile;219220for (var x = 0; x < this.size; x++) {221for (var y = 0; y < this.size; y++) {222tile = this.grid.cellContent({ x: x, y: y });223224if (tile) {225for (var direction = 0; direction < 4; direction++) {226var vector = self.getVector(direction);227var cell = { x: x + vector.x, y: y + vector.y };228229var other = self.grid.cellContent(cell);230231if (other && other.value === tile.value) {232return true; // These two tiles can be merged233}234}235}236}237}238239return false;240};241242GameManager.prototype.positionsEqual = function (first, second) {243return first.x === second.x && first.y === second.y;244};245246