move-origin.html 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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>Move origin</h1>
  14. <h2>Demonstrate moving origin of Spine Gameobject, behaves like a sprite</h2>
  15. <h2>When you use matter physics, origin is reset, because the body always stays around the game object.
  16. Change game object size only after the object has been added to matter.</h2>
  17. </body>
  18. <script>
  19. let cursors;
  20. let spineboy;
  21. const levelWidth = 800;
  22. const levelHeight = 600;
  23. const gameobjects = []
  24. class BasicExample extends Phaser.Scene {
  25. preload() {
  26. this.load.spineBinary("spineboy-data", "/assets/spineboy-pro.skel");
  27. this.load.spineAtlas("spineboy-atlas", "/assets/spineboy-pma.atlas");
  28. this.load.image("block", "block.png");
  29. }
  30. create() {
  31. const graphics = this.add.graphics();
  32. const width = levelWidth / 5;
  33. const height = levelHeight / 4;
  34. let cells = [];
  35. for (let i = 0; i < levelWidth / width; i++) {
  36. for (let j = 0; j < levelHeight / height; j++) {
  37. const x = i * width;
  38. const y = j * height;
  39. cells.push({ x, y });
  40. graphics.lineStyle(1, 0x00ff00, .5);
  41. graphics.strokeRect(x, y, width, height);
  42. graphics.beginPath();
  43. graphics.moveTo(x, y);
  44. graphics.lineTo(x + width, y + height);
  45. graphics.moveTo(x + width, y);
  46. graphics.lineTo(x, y + height);
  47. graphics.closePath();
  48. graphics.strokePath();
  49. }
  50. }
  51. const physicsCells = cells.splice(cells.length - 2, 2);
  52. let animations = undefined;
  53. let prevWidth = 0;
  54. let prevHeight = 0;
  55. cells.forEach(({ x, y }, i) => {
  56. let gameobject;
  57. let animation;
  58. if (i % 2 === 1) {
  59. gameobject = this.add.image(x, y, "block");
  60. gameobject.displayWidth = prevWidth;
  61. gameobject.displayHeight = prevHeight;
  62. } else {
  63. animation = animations ? animations[i % animations.length].name : "aim";
  64. gameobject = this.add.spine(x, y, "spineboy-data", "spineboy-atlas", new spine.SkinsAndAnimationBoundsProvider(animation, undefined, undefined, true));
  65. if (!animations) animations = gameobject.skeleton.data.animations;
  66. gameobject.animationState.setAnimation(0, animation, true);
  67. let ratio = gameobject.width / gameobject.height;
  68. if (ratio > 1) {
  69. gameobject.displayHeight = height / ratio;
  70. gameobject.displayWidth = width;
  71. } else {
  72. gameobject.displayWidth = ratio * height;
  73. gameobject.displayHeight = height;
  74. }
  75. prevWidth = gameobject.displayWidth;
  76. prevHeight = gameobject.displayHeight;
  77. }
  78. gameobjects.push(gameobject)
  79. // moving origin at the center of the cell, we're still able to align spineboy and keep gameobject bounds align with the drawn skeleton
  80. const origin = 1 / (cells.length / 2 - 1) * Math.floor(i / 2)
  81. gameobject.setOrigin(origin)
  82. gameobject.x += width / 2 - gameobject.displayWidth * (0.5 - origin);
  83. gameobject.y += height / 2 - gameobject.displayHeight * (0.5 - origin);
  84. const graphics = this.add.graphics();
  85. const rect = new Phaser.Geom.Rectangle(
  86. gameobject.x - gameobject.displayOriginX * gameobject.scaleX,
  87. gameobject.y - gameobject.displayOriginY * gameobject.scaleY,
  88. gameobject.width * gameobject.scaleX,
  89. gameobject.height * gameobject.scaleY,
  90. );
  91. const defaultGraphicsElements = () => {
  92. graphics.clear();
  93. graphics.lineStyle(7, 0x0000ff, .75);
  94. graphics.strokeRectShape(rect);
  95. graphics.fillStyle(0xffff00, 10);
  96. graphics.fillCircle(gameobject.x, gameobject.y, 10);
  97. graphics.fillStyle(0xff5500, 1);
  98. graphics.fillCircle(gameobject.x - gameobject.displayOriginX * gameobject.scaleX, gameobject.y - gameobject.displayOriginY * gameobject.scaleY, 5);
  99. graphics.lineStyle(3, 0xffffff, 1);
  100. graphics.lineBetween(gameobject.x, gameobject.y, gameobject.x + gameobject.displayOriginX * gameobject.scaleX, gameobject.y + gameobject.displayOriginY * gameobject.scaleY);
  101. }
  102. defaultGraphicsElements();
  103. // interactions bounds are aligned with gameobject bounds
  104. gameobject.setInteractive();
  105. this.input.enableDebug(gameobject, 0xff00ff);
  106. gameobject.on("pointerover", () => {
  107. defaultGraphicsElements();
  108. graphics.fillStyle(0x00ff00, .25);
  109. graphics.fillRectShape(rect);
  110. graphics.fillStyle(0xff5500, 1);
  111. });
  112. gameobject.on("pointerout", () => defaultGraphicsElements());
  113. })
  114. const [physicsCell1, physicsCell2] = physicsCells;
  115. const spineboy = this.add.spine(0, 0, "spineboy-data", "spineboy-atlas");
  116. this.matter.add.gameObject(spineboy);
  117. spineboy.displayWidth = (spineboy.width / spineboy.height) * height * .5;
  118. spineboy.displayHeight = height * .5;
  119. spineboy.x = physicsCell1.x + spineboy.displayWidth;
  120. spineboy.y = physicsCell1.y + spineboy.displayHeight;
  121. spineboy.setInteractive();
  122. this.input.enableDebug(spineboy, 0xff00ff);
  123. spineboy.on("pointerover", () => {
  124. spineboy.y -= 50;
  125. spineboy.x += 10;
  126. });
  127. const block = this.add.image(0, 0, "block");
  128. this.matter.add.gameObject(block);
  129. block.displayWidth = (block.width / block.height) * height * .5;
  130. block.displayHeight = height * .5;
  131. block.x = physicsCell2.x + block.displayWidth;
  132. block.y = physicsCell2.y + block.displayHeight;
  133. block.setInteractive();
  134. this.input.enableDebug(block, 0xff00ff);
  135. block.on("pointerover", () => {
  136. block.y -= 50;
  137. block.x += 10;
  138. });
  139. this.matter.add.rectangle(levelWidth - width, levelHeight - height, levelWidth, 1, { isStatic: true });
  140. this.matter.add.rectangle(levelWidth - width, levelHeight - 2 * height, levelWidth, 1, { isStatic: true });
  141. this.matter.add.rectangle(levelWidth - width, levelHeight, levelWidth, 1, { isStatic: true });
  142. this.matter.add.rectangle(levelWidth - width, levelHeight - 2 * height, 1, height * 4, { isStatic: true });
  143. this.matter.add.rectangle(levelWidth, levelHeight - 2 * height, 1, height * 4, { isStatic: true });
  144. }
  145. update(params) {
  146. gameobjects.forEach((go) => {
  147. go.angle += 0.05;
  148. })
  149. }
  150. }
  151. new Phaser.Game({
  152. type: Phaser.AUTO,
  153. width: levelWidth,
  154. height: levelHeight,
  155. type: Phaser.WEBGL,
  156. scene: [BasicExample],
  157. physics: {
  158. default: 'matter',
  159. matter: {
  160. debug: true,
  161. gravity: { y: .15 },
  162. },
  163. },
  164. plugins: {
  165. scene: [
  166. {
  167. key: "spine.SpinePlugin",
  168. plugin: spine.SpinePlugin,
  169. mapping: "spine",
  170. },
  171. ],
  172. },
  173. });
  174. </script>
  175. </html>