I am trying to familiarize myself with Phaser 3 by creating a project that can display a Spine animation and should then give the option to upload a folder with Spine files inside it and load this object with its animations. (I know Spine has their own web player already that you can embed, however this project is for my own learning which is why I want to try get it working). I have got the initial Spine object and animations that load with the page working perfectly fine however after trying for about 3 days, I cannot upload the files and get the new Spine displaying. The closest success I've had to this just returns an undefined object.
I'm currently uploading the files using an HTML input tag with webkitdirectory as per below code.
<div id="dropZone">
<input
type="file"
id="fileInputControl"
webkitdirectory="true"
multiple
/>
</div>
I have console logged and can confirm that the files are uploading correctly to the page after I use the file upload input and I highly suspect that the issue is coming with how I load and add the Spine object. I have tried to use Drop Zone to upload the folder but didn't have success with that so I'm back to using HTML as I believe it's simpler to use and the file upload isn't the issue. Below is the source code of my preload, create, and update functions as well as my functions that load and add Spines just to give an idea of how I've written my code. All of the code here is in my class that extends Phaser.Scene.
I have tried to setTimeout() on loadSpineData() inside the update function to 60 seconds (after I've tried promise.then()) just to try hack this and get it working but after the 60 seconds, the console.log(animationsData) still returns an undefined object indicating I'm doing something wrong with my Spine file loading.
preload() {
this.load.setPath(spinePath);
this.loadSpineData();
}
create() {
fileInputControl.addEventListener("change", () => {
fileLoaded = true;
});
this.initializeAnimationSelect();
this.setupSpineObject();
}
update() {
if (fileLoaded) {
selectedFiles = fileInputControl.files;
keyName = selectedFiles?.[0]?.name.split(".")[0] || keyName;
this.loadSpineData();
this.initializeAnimationSelect();
fileLoaded = false;
}
}
changeAnimation() {
return this.animationSelect.value;
}
initializeAnimationSelect() {
let animationsData = this.cache.json.get(keyName)?.animations;
console.log(animationsData);
this.animationSelect = document.getElementById("animationSelect");
this.animationSelect.innerHTML = "";
for (let animationName in animationsData) {
if (animationsData.hasOwnProperty(animationName)) {
let option = document.createElement("option");
option.value = animationName;
option.text = animationName;
this.animationSelect.add(option);
}
}
}
loadSpineData() {
let atlasName = keyName + ".atlas";
let jsonName = keyName + ".json";
console.log("JSON name: " +jsonName);
console.log("Atlas name: " + atlasName);
this.load.spine({
key: keyName,
jsonURL: jsonName,
atlasURL: [atlasName],
preMultipliedAlpha: false,
});
this.selectedAnimation = this.animationSelect?.options[0]?.value || "";
}
setupSpineObject() {
let spineObject = this.add.spine(
400,
300,
keyName,
[this.selectedAnimation],
true
);
this.animationSelect.addEventListener("change", () => {
this.selectedAnimation = this.changeAnimation();
spineObject.setAnimation(0, this.selectedAnimation, true);
});
}
I'm quite new to both JavaScript and Phaser as well as being in my first job as a software developer so my current code may be quite bad which is why I'm trying to learn now where I'm going wrong.
The short answer:
It might be possible but I don't really recommend it.
The long answer:
After rethinking the whole situation and doing some test and checking the spinePlugins - Code (On github is a interesting read), and what you want to do is not as trivial as one would might initially think. You would have to write your own file preloading for the spine files and putting them into the phaser cache.
Since the files you are "uploading" are locally and stay locally and because phaser doesn't allow local Url-loading, you would have to read the files with a HTMLImage/FileReader and then put them into the phaser-cache (or reuse some functions in the SpinePlugin).
For more details you would have to read through the Code of the plugin.