123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- function GameManager(size, InputManager, Actuator, StorageManager) {
- this.size = size; // Size of the grid
- this.inputManager = new InputManager;
- this.storageManager = new StorageManager;
- this.actuator = new Actuator;
- this.startTiles = 2;
- this.inputManager.on("move", this.move.bind(this));
- this.inputManager.on("restart", this.restart.bind(this));
- this.inputManager.on("keepPlaying", this.keepPlaying.bind(this));
- this.setup();
- }
- // Restart the game重新开始游戏
- GameManager.prototype.restart = function () {
- this.storageManager.clearGameState();
- this.actuator.continueGame(); // Clear the game won/lost message
- this.setup();
- };
- // document.onkeydown = function(event) {
- // var e = event || window.event || arguments.callee.caller.arguments[0];
- // if (e && e.keyCode == 27) { // 按 Esc
- //
- // //要做的事情
- // }
- //
- // if (e && e.keyCode == 13) { // enter 键
- // //要做的事情
- // }
- // };
- // Keep playing after winning (allows going over 2048)
- // 获胜后继续
- GameManager.prototype.keepPlaying = function () {
- this.keepPlaying = true;
- this.actuator.continueGame(); // Clear the game won/lost message清除游戏中获胜/丢失的消息
- };
- // Return true if the game is lost, or has won and the user hasn't kept playing
- // 如果游戏输了,或者已经赢了,并且用户没有继续玩下去,请返回true
- GameManager.prototype.isGameTerminated = function () {
- return this.over || (this.won && !this.keepPlaying);
- };
- // Set up the game
- // 设置游戏
- GameManager.prototype.setup = function () {
- var previousState = this.storageManager.getGameState();
- // Reload the game from a previous game if present
- // 如果存在,则从以前的游戏中重新加载游戏。
- if (previousState) {
- this.grid = new Grid(previousState.grid.size,
- previousState.grid.cells); // Reload grid
- // 再装填栅格
- this.score = previousState.score;
- this.over = previousState.over;
- this.won = previousState.won;
- this.keepPlaying = previousState.keepPlaying;
- } else {
- this.grid = new Grid(this.size);
- this.score = 0;
- this.over = false;
- this.won = false;
- this.keepPlaying = false;
- // Add the initial tiles
- // 添加初始化
- this.addStartTiles();
- }
- // Update the actuator
- // 更新执行器
- this.actuate();
- };
- // Set up the initial tiles to start the game with
- // 设置参数以开始游戏
- GameManager.prototype.addStartTiles = function () {
- for (var i = 0; i < this.startTiles; i++) {
- this.addRandomTile();
- }
- };
- // Adds a tile in a random position
- // 将目标添加到任意位置
- GameManager.prototype.addRandomTile = function () {
- if (this.grid.cellsAvailable()) {
- var value = Math.random() < 0.9 ? 2 : 4;
- var tile = new Tile(this.grid.randomAvailableCell(), value);
- this.grid.insertTile(tile);
- }
- };
- // Sends the updated grid to the actuator
- // 将更新的网格发送给执行器。
- GameManager.prototype.actuate = function () {
- if (this.storageManager.getBestScore() < this.score) {
- this.storageManager.setBestScore(this.score);
- }
- // Clear the state when the game is over (game over only, not win)
- // 游戏结束后清除状态
- if (this.over) {
- this.storageManager.clearGameState();
- } else {
- this.storageManager.setGameState(this.serialize());
- }
- this.actuator.actuate(this.grid, {
- score: this.score,
- over: this.over,
- won: this.won,
- bestScore: this.storageManager.getBestScore(),
- terminated: this.isGameTerminated()
- });
- };
- // Represent the current game as an object
- // 将当前游戏表示为对象
- GameManager.prototype.serialize = function () {
- return {
- grid: this.grid.serialize(),
- score: this.score,
- over: this.over,
- won: this.won,
- keepPlaying: this.keepPlaying
- };
- };
- // Save all tile positions and remove merger info
- // 保存所有tile位置并删除合并信息
- GameManager.prototype.prepareTiles = function () {
- this.grid.eachCell(function (x, y, tile) {
- if (tile) {
- tile.mergedFrom = null;
- tile.savePosition();
- }
- });
- };
- // Move a tile and its representation
- // 移动tile及其表示
- GameManager.prototype.moveTile = function (tile, cell) {
- this.grid.cells[tile.x][tile.y] = null;
- this.grid.cells[cell.x][cell.y] = tile;
- tile.updatePosition(cell);
- };
- // Move tiles on the grid in the specified direction
- // 按指定的方向移动网格上的元素
- GameManager.prototype.move = function (direction) {
- // 0: up, 1: right, 2: down, 3: left
- var self = this;
- if (this.isGameTerminated()) return; // Don't do anything if the game's over
- // 如果游戏结束了,什么都不要做
- var cell, tile;
- var vector = this.getVector(direction);
- var traversals = this.buildTraversals(vector);
- var moved = false;
- // Save the current tile positions and remove merger information 保存当前的元素位置并删除合并信息。
- this.prepareTiles();
- // Traverse the grid in the right direction and move tiles
- // 沿着正确的方向遍历网格并移动元素
- traversals.x.forEach(function (x) {
- traversals.y.forEach(function (y) {
- cell = { x: x, y: y };
- tile = self.grid.cellContent(cell);
- if (tile) {
- var positions = self.findFarthestPosition(cell, vector);
- var next = self.grid.cellContent(positions.next);
- // Only one merger per row traversal?每行遍历只有一次合并?
- if (next && next.value === tile.value && !next.mergedFrom) {
- var merged = new Tile(positions.next, tile.value * 2);
- merged.mergedFrom = [tile, next];
- self.grid.insertTile(merged);
- self.grid.removeTile(tile);
- // Converge the two tiles' positions
- // 收敛两个元素的位置
- tile.updatePosition(positions.next);
- // Update the score
- // 会聚两个元素的位置-更新分数
- self.score += merged.value;
- // The mighty 2048 tile
- if (merged.value === 2048) self.won = true;
- } else {
- self.moveTile(tile, positions.farthest);
- }
- if (!self.positionsEqual(cell, tile)) {
- moved = true; // The tile moved from its original cell!
- // 元素从原来的网格里移动了!
- }
- }
- });
- });
- if (moved) {
- this.addRandomTile();
- if (!this.movesAvailable()) {
- this.over = true; // 你输啦!
- }
- this.actuate();
- }
- };
- // Get the vector representing the chosen direction
- // 获取表示所选方向的向量
- GameManager.prototype.getVector = function (direction) {
- // Vectors representing tile movement
- // 表示平铺运动的矢量
- var map = {
- 0: { x: 0, y: -1 }, // Up
- 1: { x: 1, y: 0 }, // Right
- 2: { x: 0, y: 1 }, // Down
- 3: { x: -1, y: 0 } // Left
- };
- return map[direction];
- };
- // Build a list of positions to traverse in the right order
- // 按正确的顺序建立要遍历的位置列表。
- GameManager.prototype.buildTraversals = function (vector) {
- var traversals = { x: [], y: [] };
- for (var pos = 0; pos < this.size; pos++) {
- traversals.x.push(pos);
- traversals.y.push(pos);
- }
- // Always traverse from the farthest cell in the chosen direction 总是沿着选择的方向从最远的网格中走过。
- if (vector.x === 1) traversals.x = traversals.x.reverse();
- if (vector.y === 1) traversals.y = traversals.y.reverse();
- return traversals;
- };
- GameManager.prototype.findFarthestPosition = function (cell, vector) {
- var previous;
- // Progress towards the vector direction until an obstacle is found 向矢量方向前进,直到发现障碍
- do {
- previous = cell;
- cell = { x: previous.x + vector.x, y: previous.y + vector.y };
- } while (this.grid.withinBounds(cell) &&
- this.grid.cellAvailable(cell));
- return {
- farthest: previous,
- next: cell // Used to check if a merge is required用于检查是否需要合并。
- };
- };
- GameManager.prototype.movesAvailable = function () {
- return this.grid.cellsAvailable() || this.tileMatchesAvailable();
- };
- // Check for available matches between tiles (more expensive check)检查平铺之间的可用匹配
- GameManager.prototype.tileMatchesAvailable = function () {
- var self = this;
- var tile;
- for (var x = 0; x < this.size; x++) {
- for (var y = 0; y < this.size; y++) {
- tile = this.grid.cellContent({ x: x, y: y });
- if (tile) {
- for (var direction = 0; direction < 4; direction++) {
- var vector = self.getVector(direction);
- var cell = { x: x + vector.x, y: y + vector.y };
- var other = self.grid.cellContent(cell);
- if (other && other.value === tile.value) {
- return true; // These two tiles can be merged这两个元素可以合并。
- }
- }
- }
- }
- }
- return false;
- };
- GameManager.prototype.positionsEqual = function (first, second) {
- return first.x === second.x && first.y === second.y;
- };
|