three.js how to make sure your other javascript file load after your models was loaded

Viewed 198

So i have a main.js that calls a loadmanager and a scenemanager.

//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();
}

inside the load manager

there is nothing special just function relating to loading 2 models a player model and a enemy model

import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js';

//
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118/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;
  }



}

inside the scenemanager

import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.118/build/three.module.js';
import * as YUKA from './libs/yuka.module.js';

//loader
import { GLTFLoader } from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/loaders/GLTFLoader.js';
//effect
import { EffectComposer } from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/postprocessing/RenderPass.js';
import { ShaderPass } from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/postprocessing/ShaderPass.js';
import { UnrealBloomPass } from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/postprocessing/UnrealBloomPass.js';
import { GlitchPass } from 'https://cdn.jsdelivr.net/npm/three@0.118/examples/jsm/postprocessing/GlitchPass.js';
//lock the mouse pointer while in game
import { PointerLockControls } from 'https://cdn.jsdelivr.net/npm/three@0.118/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);

And my logic here is simple, load the loadmanager and get the models loaded so i can use them in my scene manager.

However in the log i can see that load manager was indead called first them instead of loading the models, it open scenemanager, and start calling for the models even before other imports modules.

any idead why is this happening and how can i fix this so that the models are loaded before scenemanager was called ?sorry i am kind of new to javascripts.

1 Answers

The problem is that loading assets is an asynchronous operation and you do not wait with accessing player and enemy model until the loading has finished.

I suggest you refactor the LoadManager a bit an introduce an init() method. This method returns a promise like so:

init() {

    return new Promise( ( resolve ) => {

        this.loadingManager.onLoad = () => {

            resolve();
        };

    } );

}

In your main.js, you use the new method like so:

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

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

    // more logic

} );

There are other ways to implement this feature (e.g. via async/await) but for starts it should do the trick.

Related