174 lines
4.1 KiB
HTML

<!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/phaser@3.60.0/dist/phaser.js"></script>
<script src="../dist/iife/spine-phaser-v3.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>