Ok so here is my workaround. I donāt call that a solution since it would imply writing a proper MultiFile loader. Still busy trying to figure that one out. At least it unblocks me releasing a beta demo of my little gameā¦
TL;DR;
Short version:
- donāt use loader.audio if Webkit is detected
- donāt allow update to process anything until further notice.
- on each audio asset: use a fetch ā convert to buffer ā decodeAudio as shown below.
- register a listener: this.sound.on(ādecodedā) to detect when resources are loaded. keep track of decoded count before allowing the update loop to process anything.
- donāt forget to unregister your ādecodedā event in the shutdown sequence of your scene.
Sorry @rich for desacrating your splendid code, but Iām not good enough (yet?) with Phaser to write a proper MultiFile implementation that properly works during the preload phaseā¦ I hope I can book a support session with you to help me implement a proper FileTypesManager.register("iOsCapacitorSafeAudio", ...)
Now the long version.
detecting webkit (capacitor or not, desktop or mobile, just does the trick):
window && typeof window.webkitConvertPointFromNodeToPage === "function"
ok,
This hack should help as a quick fix though.
Add these 5 members to the scene:
private doneNormalPreload = false;
private doneUglyPreload = false;
private countToDecode = 0;
private decodedCount = 0;
private canLoop = false;
preload
Preloading happens like usual: images, jsons, tilesets, etc. except for sounds, if Webkit is detected (canāt detect capacitor, so, this does the trick).
it must however also reset the following and register an event listener on the sceneās sound system:
this.doneNormalPreload = false;
this.doneUglyPreload = false;
this.decodedCount = 0;
this.canLoop = false;
// every time an audio file is decoded we increment the counter till we reach the desired amount
this.sound.on("decoded", (audiokey) => {
this.decodedCount++;
if (this.decodedCount === this.countToDecode) {
this.uglyLoadComplete();
}
});
// filter out the audio assets that are already loaded, otherwise the "decoded" event handler will run into trouble
const newAudioAssets = audioAssets.filter((asset) => !webAudiosoundManager.game.cache.audio.entries.entries[asset.key]);
// just in case the audio asset count to preload has dropped to 0
this.countToDecode = newAudioAssets.length;
if (this.countToDecode === 0) {
this.uglyLoadComplete();
}
Preloading what the audio files needs the fetch call as follows
newAudioAssets.map(({ key, url }) =>
fetch(url[0])
.then((response) => response.arrayBuffer())
.then((audioAsBuffer) => {
// console.log("decoding " + key);
return webAudiosoundManager.decodeAudio(key, audioAsBuffer);
})
);
create method
Move the contents of your create method in a new ācreateAfterSafeAudioPreloadā method.
Create should only contain this:
this.doneNormalPreload = true;
if (this.doneUglyPreload) {
this.createAfterSafeAudioPreload();
}
Now both doneNormalPreload
and doneUglyPreload
must have been set to true in order to call that createAfterSafeAudioPreload
Add the ugly load complete method to the sceneās body
This one makes sure to only start the game when normal preloading is done AND this hackish preloading is done:
private uglyLoadComplete() {
this.doneUglyPreload = true;
if (this.doneNormalPreload) {
this.createAfterSafeAudioPreload();
}
}
** Prevent the update() method from doing anything until told so
update(t: number, dt: number) {
if (this.canLoop) {
super.update(t, dt);
this.animatedTiles.updateAnimatedTiles();
this.playerInput.update();
this.processIrq();
}
}
This is because the create() method is called by the normal/clean preloader of Phaser and that schedules the scene update. So I made this ugly boolean check waste cycles every tick to prevent issuesā¦
** Donāt forget to unregister the listener **
In the shutdown method, donāt forget to unregister on the sound member the following:
this.sound.off("decoded");
NB make sure to do it on this.sound
, not this.events
!!!