html_actuator.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. function HTMLActuator() {
  2. this.tileContainer = document.querySelector(".tile-container");
  3. this.scoreContainer = document.querySelector(".score-container");
  4. this.bestContainer = document.querySelector(".best-container");
  5. this.messageContainer = document.querySelector(".game-message");
  6. this.score = 0;
  7. }
  8. HTMLActuator.prototype.actuate = function (grid, metadata) {
  9. var self = this;
  10. window.requestAnimationFrame(function () {
  11. self.clearContainer(self.tileContainer);
  12. grid.cells.forEach(function (column) {
  13. column.forEach(function (cell) {
  14. if (cell) {
  15. self.addTile(cell);
  16. }
  17. });
  18. });
  19. self.updateScore(metadata.score);
  20. self.updateBestScore(metadata.bestScore);
  21. if (metadata.terminated) {
  22. if (metadata.over) {
  23. self.message(false); // You lose
  24. } else if (metadata.won) {
  25. self.message(true); // You win!
  26. }
  27. }
  28. });
  29. };
  30. // Continues the game (both restart and keep playing)
  31. HTMLActuator.prototype.continueGame = function () {
  32. this.clearMessage();
  33. };
  34. HTMLActuator.prototype.clearContainer = function (container) {
  35. while (container.firstChild) {
  36. container.removeChild(container.firstChild);
  37. }
  38. };
  39. HTMLActuator.prototype.addTile = function (tile) {
  40. var self = this;
  41. var wrapper = document.createElement("div");
  42. var inner = document.createElement("div");
  43. var position = tile.previousPosition || { x: tile.x, y: tile.y };
  44. var positionClass = this.positionClass(position);
  45. // We can't use classlist because it somehow glitches when replacing classes
  46. var classes = ["tile", "tile-" + tile.value, positionClass];
  47. if (tile.value > 2048) classes.push("tile-super");
  48. this.applyClasses(wrapper, classes);
  49. inner.classList.add("tile-inner");
  50. inner.textContent = tile.value;
  51. if (tile.previousPosition) {
  52. // Make sure that the tile gets rendered in the previous position first
  53. window.requestAnimationFrame(function () {
  54. classes[2] = self.positionClass({ x: tile.x, y: tile.y });
  55. self.applyClasses(wrapper, classes); // Update the position
  56. });
  57. } else if (tile.mergedFrom) {
  58. classes.push("tile-merged");
  59. this.applyClasses(wrapper, classes);
  60. // Render the tiles that merged
  61. tile.mergedFrom.forEach(function (merged) {
  62. self.addTile(merged);
  63. });
  64. } else {
  65. classes.push("tile-new");
  66. this.applyClasses(wrapper, classes);
  67. }
  68. // Add the inner part of the tile to the wrapper
  69. wrapper.appendChild(inner);
  70. // Put the tile on the board
  71. this.tileContainer.appendChild(wrapper);
  72. };
  73. HTMLActuator.prototype.applyClasses = function (element, classes) {
  74. element.setAttribute("class", classes.join(" "));
  75. };
  76. HTMLActuator.prototype.normalizePosition = function (position) {
  77. return { x: position.x + 1, y: position.y + 1 };
  78. };
  79. HTMLActuator.prototype.positionClass = function (position) {
  80. position = this.normalizePosition(position);
  81. return "tile-position-" + position.x + "-" + position.y;
  82. };
  83. HTMLActuator.prototype.updateScore = function (score) {
  84. this.clearContainer(this.scoreContainer);
  85. var difference = score - this.score;
  86. this.score = score;
  87. this.scoreContainer.textContent = this.score;
  88. if (difference > 0) {
  89. var addition = document.createElement("div");
  90. addition.classList.add("score-addition");
  91. addition.textContent = "+" + difference;
  92. this.scoreContainer.appendChild(addition);
  93. }
  94. };
  95. HTMLActuator.prototype.updateBestScore = function (bestScore) {
  96. this.bestContainer.textContent = bestScore;
  97. };
  98. HTMLActuator.prototype.message = function (won) {
  99. var type = won ? "game-won" : "game-over";
  100. var message = won ? "You win!" : "Game over!";
  101. this.messageContainer.classList.add(type);
  102. this.messageContainer.getElementsByTagName("p")[0].textContent = message;
  103. };
  104. HTMLActuator.prototype.clearMessage = function () {
  105. // IE only takes one value to remove at a time.
  106. this.messageContainer.classList.remove("game-won");
  107. this.messageContainer.classList.remove("game-over");
  108. };