SpriteAtlas.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. class SpriteAtlas {
  2. constructor(assetsPath, xmlFilename) {
  3. this.assetsPath = assetsPath;
  4. this.xmlFilename = xmlFilename;
  5. this.xmlPath = `${assetsPath}/${xmlFilename}`;
  6. this.atlas = {};
  7. this.xmlData = {};
  8. this.spritesheetImage = new Image();
  9. this.cacheBusting = true;
  10. }
  11. load() {
  12. return new Promise((resolve, reject) => {
  13. var request = new XMLHttpRequest();
  14. request.addEventListener("load", (event) => this.xmlLoadComplete(event, resolve, reject));
  15. let url = this.xmlPath;
  16. if (this.cacheBusting) {
  17. url += "?v=" + new Date().getTime();
  18. }
  19. request.open("GET", url);
  20. request.setRequestHeader("Content-Type", "text/xml");
  21. request.send();
  22. });
  23. }
  24. xmlLoadComplete(event, resolve, reject) {
  25. var source = (new DOMParser()).parseFromString(event.target.responseText, "application/xml");
  26. this.xmlData = source;
  27. var textureAtlas = source.getElementsByTagName("TextureAtlas")[0];
  28. this.populateAtlas(source);
  29. var sheetsrc = `${this.assetsPath}/${textureAtlas.getAttribute("imagePath")}`;
  30. if (this.cacheBusting) {
  31. sheetsrc += "?v=" + new Date().getTime();
  32. }
  33. this.spritesheetImage.src = sheetsrc;
  34. this.spritesheetImage.addEventListener('load', resolve);
  35. };
  36. populateAtlas(source) {
  37. var subtextures = source.getElementsByTagName("SubTexture");
  38. for (var i = 0, subtexture = subtextures[0]; subtexture = subtextures[i]; i++) {
  39. this.atlas[subtexture.getAttribute("name")] = {
  40. name: subtexture.getAttribute("name"),
  41. x: parseInt(subtexture.getAttribute("x")),
  42. y: parseInt(subtexture.getAttribute("y")),
  43. width: parseInt(subtexture.getAttribute("width")),
  44. height: parseInt(subtexture.getAttribute("height"))
  45. };
  46. }
  47. };
  48. getSheet() {
  49. return this.spritesheetImage;
  50. }
  51. getSprite(name) {
  52. let imageLookup = this.atlas[name];
  53. if (!!imageLookup) {
  54. return imageLookup;
  55. }
  56. throw new Error(`Sprite ${name} not found in atlas ${this.xmlPath}`);
  57. }
  58. draw(context, name, position) {
  59. let imageLookup = this.getSprite(name);
  60. context.drawImage(this.spritesheetImage,
  61. imageLookup.x,
  62. imageLookup.y,
  63. imageLookup.width,
  64. imageLookup.height,
  65. position.x,
  66. position.y,
  67. imageLookup.width,
  68. imageLookup.height);
  69. };
  70. drawCentered(context, name, position) {
  71. let imageLookup = this.getSprite(name);
  72. context.drawImage(this.spritesheetImage,
  73. imageLookup.x,
  74. imageLookup.y,
  75. imageLookup.width,
  76. imageLookup.height,
  77. position.x - imageLookup.width / 2,
  78. position.y - imageLookup.height / 2,
  79. imageLookup.width,
  80. imageLookup.height);
  81. };
  82. drawBottomCentered(context, name, position) {
  83. let imageLookup = this.getSprite(name);
  84. context.drawImage(this.spritesheetImage,
  85. imageLookup.x,
  86. imageLookup.y,
  87. imageLookup.width,
  88. imageLookup.height,
  89. position.x - imageLookup.width / 2,
  90. position.y + imageLookup.height / 2,
  91. imageLookup.width,
  92. imageLookup.height);
  93. };
  94. getWidth(name) {
  95. return this.getSprite(name).width;
  96. };
  97. getHeight(name) {
  98. return this.getSprite(name).height;
  99. };
  100. }
  101. class Spritesheet {
  102. constructor(assetPath, filename, width, height, margin) {
  103. this.assetPath = assetPath;
  104. this.filename = filename;
  105. this.spritesheetImage = new Image();
  106. this.width = width;
  107. this.height = height;
  108. this.margin = margin;
  109. this.cacheBusting = true;
  110. }
  111. load() {
  112. return new Promise((resolve, reject) => {
  113. let url = this.assetPath + "/" + this.filename;
  114. this.spritesheetImage.src = url;
  115. this.spritesheetImage.addEventListener('load', (event) => this.loadComplete(event, resolve, reject));
  116. if (this.cacheBusting) {
  117. url += "?v=" + new Date().getTime();
  118. }
  119. });
  120. }
  121. loadComplete(event, resolve, reject) {
  122. resolve();
  123. }
  124. draw(context, spriteId, position) {
  125. let x = spriteId % (this.spritesheetImage.width / (this.width + this.margin));
  126. let y = Math.floor(spriteId / (this.spritesheetImage.width / (this.width + this.margin)));
  127. context.drawImage(this.spritesheetImage,
  128. (x * this.width) + (x * this.margin),
  129. (y * this.height) + (y * this.margin),
  130. this.width,
  131. this.height,
  132. position.x,
  133. position.y,
  134. this.width,
  135. this.height);
  136. };
  137. }
  138. class ColorSpriteCache {
  139. constructor(spritesheet) {
  140. this.spritesheet = spritesheet;
  141. this.sprites = {};
  142. }
  143. add(key, width, height, spriteId, foregroundColor = "white", backgroundColor = "transparent") {
  144. let background = document.createElement("canvas");
  145. background.width = width;
  146. background.height = height;
  147. let backgroundContext = background.getContext("2d");
  148. let canvas = document.createElement("canvas");
  149. canvas.width = width;
  150. canvas.height = height;
  151. let context = canvas.getContext("2d");
  152. this.spritesheet.draw(backgroundContext, spriteId, { x: 0, y: 0 });
  153. context.fillStyle = foregroundColor;
  154. context.beginPath();
  155. context.rect(0, 0, width, height);
  156. context.fill();
  157. context.globalCompositeOperation = "destination-atop";
  158. context.drawImage(background, 0, 0);
  159. context.globalCompositeOperation = "destination-over";
  160. context.fillStyle = backgroundColor;
  161. context.beginPath();
  162. context.rect(0, 0, width, height);
  163. context.fill();
  164. context.globalCompositeOperation = "source-over";
  165. this.sprites[key] = { image: canvas, width: width, height: height };
  166. }
  167. get(key) {
  168. return this.sprites[key];
  169. }
  170. drawOnGrid(context, key, coordinates, tileSize) {
  171. context.drawImage(this.get(key).image, coordinates.x * tileSize.width, coordinates.y * tileSize.height);
  172. }
  173. }