Ensuring that your additional JavaScript file loads after your models have been loaded in three.js

My main.js file calls a load manager and a scene manager.

//Load Manager
import { LoadManager } from './sceneSubjects/LoadManager.js';
//Scene Manager
import { SceneManager } from './SceneManager.js'

//Load manager
const loadmn = new LoadManager();

//Scene Manager
const canvas = document.getElementById("canvas");
const sceneManager = new SceneManager(canvas, loadmn);


bindEventListeners();
render();

function bindEventListeners() {
    window.onresize = resizeCanvas;
    resizeCanvas();
}

function resizeCanvas() {
    canvas.style.width = '100%';
    canvas.style.height = '100%';

    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;

    sceneManager.onWindowResize();
}

function render() {
    requestAnimationFrame(render);
    sceneManager.update();
}

In the load manager

The load manager contains functions related to loading two models: a player model and an enemy model.

import * as THREE from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="f08498829595b0c0dec1c1c8">[email protected]</a>/build/three.module.js';

//
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="60140812050520504e515158">[email protected]</a>/examples/jsm/loaders/GLTFLoader.js';

export class LoadManager {
  constructor() {
    console.log("hey hey LoadManager");
    //Load manager
    const loadingpage = document.getElementById('loading-screen');
    this.loadManager = new THREE.LoadingManager();
    this.loadManager.onProgress = function (item, loaded, total) {//display progress when loading
      // console.log('Loading file: ' + item, '.\n Loaded ' + loaded + ' of ' + total + ' files.');
      document.getElementById("loadingMessage").innerHTML = 'Loading file: ' + item;
      console.log('Loading file: ' + '.\n Loaded ' + loaded + ' of ' + total + ' files.');
      // document.getElementById("loadingMessage").innerHTML = loaded + ' of ' + total + ' files.';
    };
    this.loadManager.onError = function (item) {//display error when loading erroe appears
      console.log('There was an error loading ' + item);
      document.getElementById("loadingMessage").innerHTML = 'There was an error loading : ' + item;
    }
    this.loadManager.onLoad = function () {//loading complete
      console.log('Loading complete!');
      document.getElementById("loadingMessage").innerHTML = 'Loading complete!';
      loadingpage.style.display = 'none';
    };

    this.playerModel = null;
    this.enemyModel = null;

    //load the player and enemy ships
    const loader = new GLTFLoader(this.loadManager);
    loader.load(~~~
      this.playerModel = gltf.scene;
      console.log(" player model loaded");
    });
    loader.load(~~~
      this.enemyModel = gltf.scene;
      console.log(" enemy model loaded");
    });
  }

  get getPlayerModel() {
    return this.playerModel;
  }
  get getEnemyModel() {
    return this.enemyModel;
  }



}

In the scene manager

import * as THREE from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="c3b7abb1a6a683f3edf2f2fb">[email protected]</a>/build/three.module.js';
import * as YUKA from './libs/yuka.module.js';

//loader
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2f5b475d4a4a6f1f011e1e17">[email protected]</a>/examples/jsm/loaders/GLTFLoader.js';
//effect
import { EffectComposer } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="0f7b677d6a6a4f3f213e3e37">[email protected]</a>/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="bcc8d4ced9d9fc8c928d8d84">[email protected]</a>/examples/jsm/postprocessing/RenderPass.js';
import { ShaderPass } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="8cf8e4fee9e9ccbca2bdbdb4">[email protected]</a>/examples/jsm/postprocessing/ShaderPass.js';
import { UnrealBloomPass } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="37435f45525277071906060f">[email protected]</a>/examples/jsm/postprocessing/UnrealBloomPass.js';
import { GlitchPass } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="ff8b978d9a9abfcfd1cecec7">[email protected]</a>/examples/jsm/postprocessing/GlitchPass.js';
//lock the mouse pointer while in game
import { PointerLockControls } from 'https://cdn.jsdelivr.net/npm/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="75011d07101035455b44444d">[email protected]</a>/examples/jsm/controls/PointerLockControls.js';

//scene subjects
import { Player } from './sceneSubjects/Player.js';
import { Enemy } from './sceneSubjects/enemy.js';
import { EnemyBehaviour } from './sceneSubjects/enemyBehaviour.js';
import { World } from './sceneSubjects/world.js'


export function SceneManager(canvas, loadmn) {

    console.log("hey hey SceneManager")
    const entityManager = new YUKA.EntityManager();
    const clock = new THREE.Clock();
    const enemies = [];
    const gameState = ['running', 'paused', 'end'];
    let currgameState = null;

    const screenDimensions = {
        width: canvas.width,
        height: canvas.height
    }

    //Get models
    let playerModel = loadmn.getPlayerModel;
    console.log(playerModel);
    let enemyModel = loadmn.getEnemyModel;
    console.log(enemyModel);

I'm facing an issue where the load manager is being called before the models are loaded. I want to ensure that the models are loaded before the scene manager is called. Does anyone have any suggestions on how to fix this? I'm relatively new to JavaScript.

Answer №1

The issue lies in the fact that loading assets occurs asynchronously, leading to premature attempts to access player and enemy models before the loading process is complete.

To address this, I recommend refining the LoadManager by introducing an init() method. This method will return a promise as shown below:

init() {

    return new Promise( ( resolve ) => {

        this.loadingManager.onLoad = () => {

            resolve();
        };

    } );

}

In your main.js, you can utilize this new method in the following manner:

loadmn.init().then(() => {

    const canvas = document.getElementById("canvas");
    const sceneManager = new SceneManager(canvas, loadmn);

    // additional logic

});

While there are alternative approaches to implement this functionality (e.g. utilizing async/await), the suggested method should serve as a solid starting point.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Execute a JavaScript function repeatedly, with a specified delay incorporated into it

I am currently working on a JavaScript function that cycles through background images within a div. The function works well, but it stops once all the images have been displayed. How can I make it start over again after going through all the images? $(do ...

What is the best way to ensure that consecutive if blocks are executed in sequence?

I need to run two if blocks consecutively in TypeScript, with the second block depending on a flag set by the first block. The code below illustrates my scenario: export class Component { condition1: boolean; constructor(private confirmationServic ...

Unraveling the complexities of parsing multi-tiered JSON structures

I am struggling with indexing values from a multi-level JSON array. Here is the JSON data in question: { "items": [ { "snippet": { "title": "YouTube Developers Live: Embedded Web Player Customization" } ...

Tips for modifying the value of a JSON object using Javascript or Jquery

I am looking to retrieve the value of a specific key, potentially accessing nested values as well. For example, changing the value of "key1" to "value100" or "key11" to "value111. { "key1": "value1", "key2": "value2", ...

Choose particular text within the editorState

I'm in the process of developing a sophisticated text editor utilizing draftjs. Take a look at this basic codesandbox to get a better understanding of the issue at hand. One of the challenges I'm facing is with a helper function called getCurren ...

What is the process for removing a range of keys from indexeddb?

I need help deleting keys that start with tracklist/RANDOM_STRING and 'songBook/RANDOM_String'. I attempted to do this using IDBKeyRange but I am struggling to understand how it works. The documentation I referred to was somewhat confusing: Mdn ...

Utilize Node.js to encrypt data from an extensive file

Hello, this is my initial inquiry. English isn't my native language and I need some help. I have a large file with about 800K lines that I need to read and encrypt using the sjcl library. So far, I've only managed to write the following code snip ...

Utilize puppeteer by passing a function inside page.waitForFunction() for efficient automation processes

Below is the code I am using: function checkDataRefresh(pastAvgGain, currentAvgGain) { if (pastAvgGain !== currentAvgGain) { return true; } else { return false; } } async function fetchInformation(pair, page) { let pastAvgGain = C.AVG ...

The suggestions for auto-complete in jQuery are not showing up as expected

I am looking to implement a feature where suggestions from the database are automatically populated in a text box as I type. Additionally, when I select a suggestion, other related text fields should be filled automatically. Below is the code snippet: Vi ...

Converting a class into a cohesive JSON string within ASP.NET MVC

I have the following class: [Serializable] public class ApiRequestStatus :IEquatable<ApiRequestStatus> { public static readonly ApiRequestStatus Failure = new ApiRequestStatus("Failure"); public st ...

Using Jquery to select a specific id for an input element that is a checkbox

I've been working on a snippet of jQuery code that I'd like to tailor to be more specific for one of two different input elements on my HTML page. <script> // ensure only one box is checked at a time $(document).ready(function() { ...

Utilizing JavaScript to Extract JSON Information from Knockout.js

Incorporating knockout into my project has been a great help as I retrieve JSON objects using Ajax. One question that arises is how to effectively utilize this data in my custom JavaScript code: After receiving the mapped item from the ajax call, here is ...

Encounter error message "Angular-CLI: Karma-Webpack fails due to 'file or directory not found'"

After initially starting with the classic Angular/systemjs setup for the Tour of Heroes, I transitioned to using angular-client. The application now performs well in both development and production modes, except for when I try to run tests using ng test. A ...

Can the Twitter Bootstrap typeahead feature be used with an external data source?

Can the typeahead feature in version 2.0.3 of twitter-bootstrap work with a remote data source? You can check out the link for more information on the typeahead functionality: ...

Is it possible to display this code through printing rather than using an onclick event?

I have a puzzle website in the works where users select a puzzle to solve. I am looking for a way to display the puzzles directly on the website instead of using pop-up boxes. I am proficient in various coding languages, so any solution will work for me. ...

Alert received upon selecting the React icon button

In the login code below, I have utilized FaEye and FaEyeSlash react icons. However, every time I click on them, a warning message pops up. To avoid this issue, I attempted to switch from using tailwindcss to normal CSS. Login.jsx import { useContext, useS ...

Error: Unable to access the property 'fn' of an undefined object in electron version 2 using Angular 6

I am currently utilizing Angular 6.0.3 and electronjs 2.0.2 with the package.json configuration shown below: { "name": "test", "version": "1.0.0", "license": "MIT", "main": "electron-main.js", "author": { "name": "Moh ...

Guide on implementing register helpers with node.js and express handlebars

When loading a record, I have a select option on my form and want to pre-select the saved option. Here is the code: The Student.hbs file displays the form, with the act obj coming from the student.js route student.hbs <form> <div class="for ...

Create a personalized form with HTML and JQuery

Currently, the data is displayed on a page in the following format: AB123 | LHRLAX | J9 I7 C9 D9 A6 | -0655 0910 -------------------------------------------------------- CF1153 | LHRLAX | I7 J7 Z9 T9 V7 | -0910 1305 ---------------- ...

Is there a method to reference the HTML element without utilizing the tagname?

Here's a straightforward query: Is it possible to reference the HTML element in JavaScript without using: document.getElementsByTagName('HTML')[0] If you want to access the body element, you can use: document.body Any simpler methods ava ...