Phaser: how to load assets after preload? - javascript

I wonder whether it would be possible to load an asset dynamically at a given time in Phaser rather than loading everything in the preload function. The reason for this is simple: I have a game with three different levels, all of which have different background songs; and so I'd rather only load a single song at startup to reduce loading times.
Right now, my preload function looks like this:
preload: function()
{
game.load.audio('pixel_world',
['assets/music/pixel_world_lo.ogg', 'assets/music/pixel_world_lo.mp3']);
game.load.audio('second_source',
['assets/music/second_source_lo.ogg', 'assets/music/second_source_lo.mp3']);
game.load.audio('reboot_complete',
['assets/music/reboot_complete_lo.ogg', 'assets/music/reboot_complete_lo.mp3']);
game.load.image('pickup', 'assets/img/pickup.png');
}
I tried moving one of the game.load.audio() calls to the create function instead:
create: function()
{
game.load.audio('pixel_world',
['assets/music/pixel_world_lo.ogg', 'assets/music/pixel_world_lo.mp3']);
// good things follow...
}
However, the following calls fail:
this.cache.isSoundDecoded(level.song)
// Phaser.Cache.isSoundDecoded: Key "pixel_world" not found in Cache.
song = game.add.audio(level.song);
// Phaser.Cache.getSound: Key "pixel_world" not found in Cache.
Do you know how I can get this to work, or any other way to ensure that the three songs are not loaded at game startup? Thank you!

From the documentation, that big unknown for noobs like me:
audio(key, urls, autoDecode) → {Phaser.Loader}
Adds an audio file to the current load queue.
The file is not loaded immediately after calling this method. The file is added to the queue ready to be loaded when the loader starts.
So basically, game.load.audio() after preload isn't loading the song, just adding it to a queue for later. In order to load the song, I also need to invoke game.load.start():
create: function()
{
game.load.audio('pixel_world',
['assets/music/pixel_world_lo.ogg', 'assets/music/pixel_world_lo.mp3']);
game.load.start(); // THIS!
// good things follow...
}

Related

Javascript Phaser3 Assets Not Loading In Create Function

I'm trying to do what seems to be basic image loading into my phaser3 game outside Phaser's preload function, but nothing is working.
I tried:
Lazy loading function in my utils.js:
dynImgLoader(textureKey,x,y,asset)
{
let loader = new Phaser.Loader.LoaderPlugin(this.scene);
loader.image(textureKey,asset);
loader.once(Phaser.Loader.Events.COMPLETE, ()=>
{
console.log('sprite ready for usage');
})
loader.start();
}
When called it still gives me the default phaser asset image (not loaded)
I tried what this tutorial told me in index.js in create function:
this.load.image('arc_red', arc_red);
this.load.onLoadComplete.add(this);
this.load.start();
Still does not work.
Question:
How do I "dynamically" load assets for a multiplayer web socket game without using the preload function? And why is it that I am doing wrong?
If you use this code in the create function (or other non preload functions) it should work:.
this.load.image(key, url); // add task
this.load.once('complete', callback, scope); // add callback of 'complete' event
this.load.start(); // start loading
I got it from this documentation, and it works in my demo code.
Here a working example on Phaser.io

Call function without actually executing it

So I have such a weird question and I don't know if this is possible, but I will give it a shot anyways.
We have implemented OneTrust, which is a third-party cookie consent vendor and it works great and all, but we have one small hiccup that we are trying to resolve.
So within the below function:
toggleVideo: function (videoWrapper, src, cover, type, element) {
var videoElement = video.buildVideo(src, type);
// We build out video-player element
videoWrapper.html(videoElement);
// We define our variables
let onetrust = window.OneTrust;
let onetrust_obj = window.ONETRUST_MODULE;
let target = videoWrapper.html(videoElement).children('iframe');
console.log(onetrust.Close());
// Now we wait and observe for a src attribute and then show the video.
onetrust_obj.src_observer(target, function() {
video.toggle_show(videoWrapper, cover);
});
},
We have an <iframe> element that when clicked play, will wait for consent to execute - The problem is that it needs to "refresh" OneTrust so that it can change the data-src to src attribute (This is all handled using OneTrust JS, so I have no control).
When I add in the console.log(onetrust.Close());, it works just as intended and resumes playing the video when consent is given, the downfall is that it outputs an error in the console. If I remove it, the videos will not play after consent is given.
I don't want to actually execute the onetrust.Close() method as it will close the banner.
OneTrust doesn't have a proper way to "Refresh" their initialization, the techs told me that this was a one-off case, where they don't even know how to handle it.
My questions:
Is there a way that I can properly call onetrust.Close() (Seems to be the only call that actually engages the video to play after) without actually executing it?
If not, is there a way that I can somehow similarly log it, but not actually log it in the console?
Thanks all!
Strange one, may be a race-condition issue so making your code run in the next procedural iteration may resolve the issue - this can be done by adding a setTimeout with no timer value.
setTimeout(() => {
onetrust_obj.src_observer(target, function() {
video.toggle_show(videoWrapper, cover);
});
});
Alternatively, it may be worth digging into the onetrust.Close() method to see if there are any public utilities that may help 'refresh' the context you are working in.
Another idea would be to see what happens after if you ran the onetrust_obj.src_observer code block again.
EDIT: I would like to be clear that I'm just trying to help resolve debugging this, without seeing a working environment it's difficult to offer suggestions 😄

Looping audio in midijs?

I'm trying to use MIDIjs to play audio (specifically because I'm using WAD.js, which uses it). Unfortunately I can't figure out how to loop audio, there's a frustrating lack of documentation, and I'm not finding anything in the source code. At the very least I'd like to know when the file has naturally ended to restart using MIDIjs.play(), but I'm not even seeing anything for that.
I'd appreciate it if someone pointed me towards a solution, thank you.
Correct, there's no loop function (that's documented anywhere here).
However, we can at least simulate it with MIDIjs.player_callback, which is called every 100ms with an object that looks like { time : number }. This is time in seconds elapsed. We can combine this with get_duration to detect the end of playback.
function playAutoReset(url)
{
// get_duration requires a callback as it returns nothing.
MIDIjs.get_duration(url, function (duration)
{
console.info(`Duration: ${duration}`);
// Start the initial play
MIDIjs.play(url);
// This lets us keep track of current play time in seconds
MIDIjs.player_callback = function (mes)
{
if (mes.time / duration >= 1)
{
console.info('End reached');
// This plays the audio again
MIDIjs.play(url);
}
};
});
}
Note:
This does call play each time, so it will probably re-download the source (the docs seem to imply that this is always the case). If you want something more network-efficient, you may want to look into XHRs/AJAX and creating an object URL, as the docs do specify that play takes a URL. However, I thought this would be the simplest solution, and it does show what you have to do to play the midi track again when it ends.
I had this same issue and wasn't entirely satisfied with the workaround in the other answer because of how it reloaded the file every time the url was passed into a MIDIjs function and it seemed to loop slightly too early.
So, I started digging into the MIDIjs source, which also has a map file, but I didn't bother trying to maximize/deobfuscate it. I noticed a couple mentions of loop that are set by second parameter t in function X. I wasn't sure, but thought maybe X was play, so I tried it.
MIDIjs.play(url, true);
It worked!
Since I'm working with Kotlin/JS, here's my external code:
external object MIDIjs {
fun play(url: String, loop: Boolean = definedExternally)
fun stop()
}
Call it in Kotlin exactly the same way, without the semicolon.
MIDIjs.play(url, true)

Pybossa JS - taskLoaded() function executes twice when fetching 1 task

I am currently building a custom task presenter for my PYBOSSA project. I have almost implemented it, but am stuck at the following javascript function -
pybossa.taskLoaded(function(task, deferred) {
if ( !$.isEmptyObject(task) ) {
console.log("Hello from taskLoaded");
// load image from flickr
var img = $('<img />');
img.load(function() {
// continue as soon as the image is loaded
deferred.resolve(task);
pybossaNotify("", false, "loading");
});
img.attr('src', task.info.url).css('height', 460);
img.addClass('img-thumbnail');
task.info.image = img;
console.log("Task ##"+task.id);
}
else {
deferred.resolve(task);
}
});
According to the docs -
The pybossa.taskLoaded method will be in charge of adding new items to the JSON task object and resolve the deferred object once the data has been loaded (i.e. when an image has been downloaded), so another task for the current user can be pre-loaded.
But notice my function. I have logged the task ids, the function loads. It loads 2 tasks. After logging, the console shows -
Task ##256
Task ##257
Also I have tried various other statements. They also execute twice. What I think is that if now I try to insert question of the current task, the function of the next task will also be put along with its respective image. How do I resolve this?
You are seeing double for a good reason :-) PYBOSSA preloads the next task, so the final user does thinks that the next task loads really fast (actually instantly).
While for some projects this might not be a problem, in some cases the user needs to download big images, check other APIs, etc. so it takes 2 or 3 seconds (or even more) to get everything before presenting the task to the user.
PYBOSSA.JS handles this scenario, as soon as the data has been downloaded, it requests a new task, but instead of presenting it, you have it in your window. As you are building your own template, you will have to add that data into the dom (via hidden elements) and then in the pybossa.presentTask method, you will check which task is being loaded, and show/hide the previous one.
In pybossa.saveTask, you can delete the previous DOM elements.
I hope this is now more clear. If you don't want this, you can use jQuery or Axios to request a task, save it and load the next one when you want ;-)

CreateJS' PreloadJS progress event inaccurate

I'm trying to load some assets using the PreloadJS class from the CreateJS suite, but when very first progress event fired reports e.loaded and e.progress as 0.83, the numbers then decrease over the next few event before finally going back up again.
t.assets = new createjs.LoadQueue();
t.assets.installPlugin(createjs.Sound);
t.assets.setMaxConnections(10);
t.assets.addEventListener("progress", function(e){
console.log(e.loaded);
});
t.assets.addEventListener("complete", function(){
callback();
});
t.assets.loadManifest([
{ id: 'facebook_btn', src: 'img/ingame/facebook_white_btn.png' },
{ id: 'twitter_btn', src: 'img/ingame/twitter_white_btn.png' },
{ id: 'embed_btn', src: 'img/ingame/embed_white_btn.png' },
]);
I get these results in the console
0.8333333333333334
0.7142857142857143
0.625
0.5555555555555556
0.5
0.45454545454545453
0.4984983736293216
0.5894074645384125
0.6363636363636364
0.6663361591119469
0.7572452500210378
0.8261679748749072
0.9170770657839982
0.9390634318392196
1
Is this because it's working through the manifest initally and doesn't take into account everything right away?
Is checking the the progress is going the correct way before displaying these results in a preloader a good method of making sure it's sorted itself out?
Essentially the manifest is just providing a convienient way to deal with a batch of assets without you having to loop through them yourself. Have a look at the code, it's almost the same as the loadFile method, but loops through the array of objects. So it's not doing anything fancy in terms of better calculating the progress.
http://createjs.com/Docs/PreloadJS/files/.._src_preloadjs_LoadQueue.js.html#l898
You have a couple options though to make it look more accurate.
If you're not loading much and it's only going to take a few seconds you might just want to not use the progress event. Instead you can just catch load errors or other hangups.
If you are loading lots of things and it could take some time then consider waiting a few seconds before displaying the progress. That gives the manifest time to add enough stuff that it should just be moving in a positive direction towards 1.

Categories

Resources