inline-loading.html 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
  8. <script src="../dist/iife/spine-phaser-v3.js"></script>
  9. <link rel="stylesheet" href="../../index.css" />
  10. <title>Spine Phaser Example</title>
  11. </head>
  12. <body class="p-4 flex flex-col items-center">
  13. <h1>Inline loading example</h1>
  14. </body>
  15. <script>
  16. const png0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAF0lEQVR4XmNgGAWDGPwHAnSxUTAKaAYAuNkD/UsHnp0AAAAASUVORK5CYII=";
  17. const png1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGklEQVR4XmNgGAWDGPyHAnRxogHFBoyCEQUAsVwP8T2BZi4AAAAASUVORK5CYII=";
  18. const atlasString =
  19. `spine.png
  20. size:16,16
  21. filter:Linear,Linear
  22. pma:true
  23. pixel1
  24. bounds:6,6,1,1
  25. spine_2.png
  26. size:16,16
  27. filter:Linear,Linear
  28. pma:true
  29. pixel2
  30. bounds:6,6,2,2
  31. `
  32. const skeletonJson = {
  33. "skeleton": {
  34. "hash": "Xgvriu12nCE",
  35. "spine": "0.0.00",
  36. "x": -150,
  37. "y": -50,
  38. "width": 300,
  39. "height": 100,
  40. "images": "./images/",
  41. "audio": "./audio"
  42. },
  43. "bones": [
  44. { "name": "root", "scaleX": 50, "scaleY": 50 }
  45. ],
  46. "slots": [
  47. { "name": "1", "bone": "root", "attachment": "pixel1" },
  48. { "name": "2", "bone": "root", "attachment": "pixel2" }
  49. ],
  50. "skins": [
  51. {
  52. "name": "default",
  53. "attachments": {
  54. "1": {
  55. "pixel1": { "x": 1, "width": 1, "height": 1 }
  56. },
  57. "2": {
  58. "pixel2": { "x": -1, "width": 2, "height": 2 }
  59. }
  60. }
  61. }
  62. ],
  63. "animations": {
  64. "animation": {
  65. "slots": {
  66. "1": {
  67. "rgba": [
  68. { "color": "3f00ffff" },
  69. { "time": 0.3333, "color": "ffffffff" },
  70. { "time": 0.6667, "color": "3f00ffff" }
  71. ]
  72. },
  73. "2": {
  74. "rgba": [
  75. { "color": "ff0000ff" },
  76. { "time": 0.3333, "color": "ffffffff" },
  77. { "time": 0.6667, "color": "ff0000ff" }
  78. ]
  79. }
  80. }
  81. }
  82. }
  83. }
  84. class BasicExample extends Phaser.Scene {
  85. atlasKey = "spineboy-atlas";
  86. async preload() {
  87. // manually add the text atlas to the game cache
  88. this.game.cache.text.add(this.atlasKey, { data: atlasString, premultipliedAlpha: true });
  89. // manually add the json skeleton to the game cache
  90. this.game.cache.json.add("spineboy-data", skeletonJson);
  91. }
  92. async create() {
  93. // associate the base64 encoded pngs to their name in the text atlas
  94. const texturesMap = {
  95. "spine.png": png0,
  96. "spine_2.png": png1,
  97. }
  98. const loadedTexturePromises = [];
  99. const textureCallbackList = [];
  100. const textureCallback = (resolve, combinedKey) => key => {
  101. if (combinedKey === key) resolve()
  102. }
  103. // loop over the pngs to load
  104. Object.entries(texturesMap).forEach(([keyTexture, value]) => {
  105. // the cache key that spine plugin will search
  106. const combinedKey = `${this.atlasKey}!${keyTexture}`;
  107. // addBase64 is async and we should wait for the ADD event before starting the game
  108. this.textures.addBase64(combinedKey, value);
  109. const promise = new Promise((resolve) => {
  110. const cb = textureCallback(resolve, combinedKey);
  111. textureCallbackList.push(cb);
  112. this.textures.on(Phaser.Textures.Events.ADD, cb);
  113. });
  114. // collecting all promises waiting for the ADD event
  115. loadedTexturePromises.push(promise);
  116. })
  117. // wait for all pngs to be decoded and loaded
  118. await Promise.all(loadedTexturePromises);
  119. // unregister the listener to the textures since we're done at listenting at texture events
  120. textureCallbackList.forEach(cb => this.textures.off(Phaser.Textures.Events.ADD, cb));
  121. // now all assets are loaded, create the game object as usual
  122. const spineboy = this.add.spine(
  123. 400,
  124. 300,
  125. "spineboy-data",
  126. "spineboy-atlas"
  127. );
  128. spineboy.setInteractive();
  129. spineboy.displayWidth = 200;
  130. spineboy.displayHeight = (spineboy.height / spineboy.width) * 200;
  131. this.input.enableDebug(spineboy, 0xff00ff);
  132. spineboy.animationState.setAnimation(0, "animation", true);
  133. }
  134. }
  135. new Phaser.Game({
  136. type: Phaser.AUTO,
  137. width: 800,
  138. height: 600,
  139. type: Phaser.WEBGL,
  140. scene: [BasicExample],
  141. plugins: {
  142. scene: [
  143. {
  144. key: "spine.SpinePlugin",
  145. plugin: spine.SpinePlugin,
  146. mapping: "spine",
  147. },
  148. ],
  149. },
  150. });
  151. </script>
  152. </html>