Javascript Phaser3 Assets Not Loading In Create Function - javascript

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

Related

Image onload not being called in vue

I am trying to build a Vue App and I am new to Vue, I am trying to load an image at runtime in Js/Ts with the code below
console.log("code is being called");
let image = new Image();
image.onload = (event) => {
console.log("image loaded");
}
image.src = "static/prison_tileset.png";
The code works fine on a regular html file, in Vue however, the onload method isn't being called. The first console.log is being called. I am sure that the image is found because if I manipulate the path to something wrong on purpose I get an error that the file isn't being found. It's just that the onload event isn't being firied.
I'd be very happy if somebody could help me with that!
I've gotten it to work now! I will answer the question myself as best as I can. To use local assets in view you have to load them via Webpack like this:
const Logo = require("../assets/logo.png");
this.image.src = Logo;
If you also happen to use electron you have to set the webSecurity in your entry file to false for electron to be allowed to access local files.

Using require.js to load something before onload

I see this question was asked here
load javascript file before onload with requirejs
But the solution there doesn't fit my situation and so I'm wondering if there is a different solution. I can't build with deps and make my code come last because I'm making a library/utility, not an app.
I'm working on the WebGL-Inspector. It works by wrapping HTMLCanvasElement.prototype.getContext and if it sees a "webgl" it then does its thing wrapping the context and allowing you to inspect it.
The WebGL-Inspector works in 3 modes
As a browser extension
As a loader + large compiled script
As a loader + original source (many many scripts)
To use it in modes #2 or #3 above you just insert
<script src="core/embed.js"></script>
Somewhere in the top of your HTML. Because it loads synchronously~ish it will have wrapped HTMLCanvasElement.prototype.getContext before whatever scripts come after it.
These last 2 modes are mostly for debugging/development of the WebGL-Inspector itself. Especially mode #3 because we can edit the inspector's code and refresh the page immediately to see the result, no build step.
I'm in the process of switching to using AMD for all of the WebGL-Inspector. We're using this because we can use webpack to make #2 but still follow the same dev workflow allowing us it use mode #3 above just change the script tag to
<script src="core/require.js" data-main="core/embed.js"></script>
The problem is this no longer works because whatever other code unrelated to the WebGL-Inspector itself runs before core/embed.js has loaded and so calls someCanvas.getContext before we've had a chance to wrap it.
My current solution is sadly to hack in a delay of 1.5 seconds on whatever demo we're using
<script src="core/require.js" data-main="core/embed.js"></script>
<script>
// wait 1.5 seconds for embed.js to load and pray :(
window.onload = setTimeout(reallyRunWebGLCode, 1500);
...
</script>
The previous non-AMD loader doesn't have this async issue. Somehow it manages to load 60 or so .js files before window.onload fires. Is there a way to get require.js to do the same? Or maybe I need to write my own loader?
To put it another way, the issue is as it is now the user adds a single <script> line and makes no other changes to their code and it works. When they're done they remove the single script line.
Switching to AMD/require.js the user is now required to add a single script and re-write code. In my tests went from
window.onload = myapp;
to
require.config({ baseUrl: "/core" });
require("./embed", myapp);
It's minor but now the app is broken when you remove the <script> tag and has to be put back as it was. Requiring those changes is what I'm trying to avoid if possible. In fact with the original style you don't even have to remove the script tag, just run your app in an environment where the script doesn't exist, it will fail to load and your app will run as normal where as with the require method it will fail if the script doesn't exist.
I can require even more code
if (typeof require === 'function' && typeof define === 'function' and define.amd) {
require.config({ baseUrl: "/core" });
require("./embed", myapp);
} else {
window.onload = myapp;
}
But that's even uglier. We went from adding a single script to requiring modifying your app.
Actually it gets even worse in the app I'm currently testing with. It uses a different loader for itself. When I run require version of the code above it fails because in this case require runs myapp before window.onload (strange). I end up having to do this
var tryRunCount = 0;
function tryRunApp() {
++tryRunCount;
// check that tryRunApp has been called twice so we know
// both onload and require have returned
if (tryRunCount === 2) {
myApp();
}
}
window.onload = tryRunApp;
require.config({ baseUrl: "/core" });
require("./embed", tryRunApp);
That's way way more changes than I want to require users to make.

Phaser: how to load assets after preload?

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...
}

How can I access the DOM of a <webview> in Electron?

I'm just getting started with Electron, with prior experience with node-webkit (nw.js).
In nw.js, I was able to create iframes and then access the DOM of said iframe in order to grab things like the title, favicon, &c. When I picked up Electron a few days ago to port my nw.js app to it, I saw advice to use webviews instead of iframes, simply because they were better. Now, the functionality I mentioned above was relatively easy to do in nw.js, but I don't know how to do it in Electron (and examples are slim to none). Can anyone help?
Also, I have back/forward buttons for my webview (and I intend on having more than one). I saw in the documentation that I could call functions for doing so on a webview, but nothing I have tried worked either (and, I haven't found examples of them being used in the wild).
I dunno who voted to close my question, but I'm glad it didn't go through. Other people have this question elsewhere online too. I also explained what I wanted to achieve, but w/e.
I ended up using ipc-message. The documentation could use more examples/explanations for the layperson, but hey, I figured it out. My code is here and here, but I will also post examples below should my code disappear for whatever reason.
This code is in aries.js, and this file is included in the main renderer page, which is index.html.
var ipc = require("ipc");
var webview = document.getElementsByClassName("tabs-pane active")[0];
webview.addEventListener("ipc-message", function (e) {
if (e.channel === "window-data") {
// console.log(e.args[0]);
$(".tab.active .tab-favicon").attr("src", e.args[0].favicon);
$(".tab.active .tab-title").html(e.args[0].title);
$("#url-bar").val(e.args[0].url);
$("#aries-titlebar h1").html("Aries | " + e.args[0].title);
}
// TODO
// Make this better...cancel out setTimeout?
var timer;
if (e.channel === "mouseover-href") {
// console.log(e.args[0]);
$(".linker").html(e.args[0]).stop().addClass("active");
clearTimeout(timer);
timer = setTimeout(function () {
$(".linker").stop().removeClass("active");
}, 1500);
}
});
This next bit of code is in browser.js, and this file gets injected into my <webview>.
var ipc = require("ipc");
document.addEventListener("mouseover", function (e) {
var hoveredEl = e.target;
if (hoveredEl.tagName !== "A") {
return;
}
ipc.sendToHost("mouseover-href", hoveredEl.href);
});
document.addEventListener("DOMContentLoaded", function () {
var data = {
"title": document.title,
"url": window.location.href,
// need to make my own version, can't rely on Google forever
// maybe have this URL fetcher hosted on hikar.io?
"favicon": "https://www.google.com/s2/favicons?domain=" + window.location.href
};
ipc.sendToHost("window-data", data);
});
I haven't found a reliable way to inject jQuery into <webview>s, and I probably shouldn't because the page I would be injecting might already have it (in case you're wondering why my main code is jQuery, but there's also regular JavaScript).
Besides guest to host IPC calls as NetOperatorWibby, it is also very useful to go from host to guest. The only way to do this at present is to use the <webview>.executeJavaScript(code, userGesture). This api is a bit crude but it works.
If you are working with a remote guest, like "extending" a third party web page, you can also utilize webview preload attribute which executes your custom script before any other scripts are run on the page. Just note that the preload api, for security reasons, will nuke any functions that are created in the root namespace of your custom JS file when your custom script finishes, however this custodial process will not nuke any objects you declare in the root. So if you want your custom functions to persist, bundle them into a singleton object and your custom APIs will persist after the page fully loads.
[update] Here is a simple example that I just finished writing: Electron-Webview-Host-to-Guest-RPC-Sample
This relates to previous answer (I am not allowed to comment): Important info regarding ipc module for users of Electron 1.x:
The ipc module was split into two separate modules:
ipcMain for the main process
ipcRenderer for the renderer process
So, the above examples need to be corrected, instead of
// Outdated - doesn't work in 1.x
var ipc = require("ipc");
use:
// In main process.
var ipcMain = require('electron').ipcMain
And:
// In renderer process.
var ipcRenderer = require('electron').ipcRenderer
See: http://electron.atom.io/blog/2015/11/17/electron-api-changes section on 'Splitting the ipc module'

How to deal with asynchronous loading of assets? Accessing right away returns undefined

I am loading my assets into an array with a function LoadJSON() that uses THREE.ObjectLoader() (assets are JSON files) . If I try to access the members of the array shortly after calling LoadJSON() it returns undefined and my program fails to run. Some research revealed that the assets are being loaded asynchronously which is why I can't access the assets in my array right away ( they are still loading ). To confirm this I did a test accessing the members of the array after a short time delay and they work.
My question: Is there a way to make sure the assets are loaded before doing anything else? I looked at the THREE.ObjectLoader code and couldn't seem to find a solution there ( though I may be missing it ). Setting a time delay seems like a bad/inconsistent solution.
link to THREE.ObjectLoader on github
load functions have a callback.
var loader = new THREE.OBJLoader( manager );
loader.load( 'obj/male02/male02.obj', function ( object ) {
//this happens after load object being what is loaded.
} );
for more info see the example

Categories

Resources