|
@@ -0,0 +1,173 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+ <head>
|
|
|
+ <meta charset="UTF-8" />
|
|
|
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
|
+ <script src="//cdn.jsdelivr.net/npm/[email protected]/dist/phaser.js"></script>
|
|
|
+ <script src="../dist/iife/spine-phaser.js"></script>
|
|
|
+ <link rel="stylesheet" href="../../index.css" />
|
|
|
+ <title>Spine Phaser Example</title>
|
|
|
+ </head>
|
|
|
+
|
|
|
+ <body class="p-4 flex flex-col items-center">
|
|
|
+ <h1>Inline loading example</h1>
|
|
|
+ </body>
|
|
|
+
|
|
|
+<script>
|
|
|
+
|
|
|
+const png0 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAF0lEQVR4XmNgGAWDGPwHAnSxUTAKaAYAuNkD/UsHnp0AAAAASUVORK5CYII=";
|
|
|
+const png1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGklEQVR4XmNgGAWDGPyHAnRxogHFBoyCEQUAsVwP8T2BZi4AAAAASUVORK5CYII=";
|
|
|
+const atlasString =
|
|
|
+`spine.png
|
|
|
+size:16,16
|
|
|
+filter:Linear,Linear
|
|
|
+pma:true
|
|
|
+pixel1
|
|
|
+bounds:6,6,1,1
|
|
|
+
|
|
|
+spine_2.png
|
|
|
+size:16,16
|
|
|
+filter:Linear,Linear
|
|
|
+pma:true
|
|
|
+pixel2
|
|
|
+bounds:6,6,2,2
|
|
|
+`
|
|
|
+
|
|
|
+const skeletonJson = {
|
|
|
+ "skeleton": {
|
|
|
+ "hash": "Xgvriu12nCE",
|
|
|
+ "spine": "0.0.00",
|
|
|
+ "x": -150,
|
|
|
+ "y": -50,
|
|
|
+ "width": 300,
|
|
|
+ "height": 100,
|
|
|
+ "images": "./images/",
|
|
|
+ "audio": "./audio"
|
|
|
+ },
|
|
|
+ "bones": [
|
|
|
+ { "name": "root", "scaleX": 50, "scaleY": 50 }
|
|
|
+ ],
|
|
|
+ "slots": [
|
|
|
+ { "name": "1", "bone": "root", "attachment": "pixel1" },
|
|
|
+ { "name": "2", "bone": "root", "attachment": "pixel2" }
|
|
|
+ ],
|
|
|
+ "skins": [
|
|
|
+ {
|
|
|
+ "name": "default",
|
|
|
+ "attachments": {
|
|
|
+ "1": {
|
|
|
+ "pixel1": { "x": 1, "width": 1, "height": 1 }
|
|
|
+ },
|
|
|
+ "2": {
|
|
|
+ "pixel2": { "x": -1, "width": 2, "height": 2 }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "animations": {
|
|
|
+ "animation": {
|
|
|
+ "slots": {
|
|
|
+ "1": {
|
|
|
+ "rgba": [
|
|
|
+ { "color": "3f00ffff" },
|
|
|
+ { "time": 0.3333, "color": "ffffffff" },
|
|
|
+ { "time": 0.6667, "color": "3f00ffff" }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ "2": {
|
|
|
+ "rgba": [
|
|
|
+ { "color": "ff0000ff" },
|
|
|
+ { "time": 0.3333, "color": "ffffffff" },
|
|
|
+ { "time": 0.6667, "color": "ff0000ff" }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class BasicExample extends Phaser.Scene {
|
|
|
+
|
|
|
+ atlasKey = "spineboy-atlas";
|
|
|
+
|
|
|
+ async preload() {
|
|
|
+ // manually add the text atlas to the game cache
|
|
|
+ this.game.cache.text.add(this.atlasKey, { data: atlasString, premultipliedAlpha: true });
|
|
|
+
|
|
|
+ // manually add the json skeleton to the game cache
|
|
|
+ this.game.cache.json.add("spineboy-data", skeletonJson);
|
|
|
+ }
|
|
|
+
|
|
|
+ async create() {
|
|
|
+
|
|
|
+ // associate the base64 encoded pngs to their name in the text atlas
|
|
|
+ const texturesMap = {
|
|
|
+ "spine.png": png0,
|
|
|
+ "spine_2.png": png1,
|
|
|
+ }
|
|
|
+
|
|
|
+ const loadedTexturePromises = [];
|
|
|
+ const textureCallbackList = [];
|
|
|
+ const textureCallback = (resolve, combinedKey) => key => {
|
|
|
+ if (combinedKey === key) resolve()
|
|
|
+ }
|
|
|
+
|
|
|
+ // loop over the pngs to load
|
|
|
+ Object.entries(texturesMap).forEach(([keyTexture, value]) => {
|
|
|
+
|
|
|
+ // the cache key that spine plugin will search
|
|
|
+ const combinedKey = `${this.atlasKey}!${keyTexture}`;
|
|
|
+
|
|
|
+ // addBase64 is async and we should wait for the ADD event before starting the game
|
|
|
+ this.textures.addBase64(combinedKey, value);
|
|
|
+ const promise = new Promise((resolve) => {
|
|
|
+ const cb = textureCallback(resolve, combinedKey);
|
|
|
+ textureCallbackList.push(cb);
|
|
|
+ this.textures.on(Phaser.Textures.Events.ADD, cb);
|
|
|
+ });
|
|
|
+
|
|
|
+ // collecting all promises waiting for the ADD event
|
|
|
+ loadedTexturePromises.push(promise);
|
|
|
+ })
|
|
|
+
|
|
|
+ // wait for all pngs to be decoded and loaded
|
|
|
+ await Promise.all(loadedTexturePromises);
|
|
|
+
|
|
|
+ // unregister the listener to the textures since we're done at listenting at texture events
|
|
|
+ textureCallbackList.forEach(cb => this.textures.off(Phaser.Textures.Events.ADD, cb));
|
|
|
+
|
|
|
+ // now all assets are loaded, create the game object as usual
|
|
|
+ const spineboy = this.add.spine(
|
|
|
+ 400,
|
|
|
+ 300,
|
|
|
+ "spineboy-data",
|
|
|
+ "spineboy-atlas"
|
|
|
+ );
|
|
|
+ spineboy.setInteractive();
|
|
|
+ spineboy.displayWidth = 200;
|
|
|
+ spineboy.displayHeight = (spineboy.height / spineboy.width) * 200;
|
|
|
+ this.input.enableDebug(spineboy, 0xff00ff);
|
|
|
+ spineboy.animationState.setAnimation(0, "animation", true);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+new Phaser.Game({
|
|
|
+type: Phaser.AUTO,
|
|
|
+width: 800,
|
|
|
+height: 600,
|
|
|
+type: Phaser.WEBGL,
|
|
|
+scene: [BasicExample],
|
|
|
+plugins: {
|
|
|
+ scene: [
|
|
|
+ {
|
|
|
+ key: "spine.SpinePlugin",
|
|
|
+ plugin: spine.SpinePlugin,
|
|
|
+ mapping: "spine",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+},
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+</html>
|