首页 > 解决方案 > three.js 如何确保在加载模型后加载其他 javascript 文件

问题描述

所以我有一个调用负载管理器和场景管理器的 main.js。

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

在负载管理器内部

没有什么特别的功能只是加载 2 个模型一个玩家模型和一个敌人模型

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



}

在场景管理器里面

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);

我的逻辑很简单,加载负载管理器并加载模型,这样我就可以在我的场景管理器中使用它们。

但是在日志中我可以看到加载管理器首先调用它们而不是加载模型,它打开场景管理器,甚至在其他导入模块之前开始调用模型。

任何想法为什么会发生这种情况,我该如何解决这个问题,以便在调用场景管理器之前加载模型?对不起,我对 javascripts 有点陌生。

标签: javascriptthree.js

解决方案


问题是加载资产是一个异步操作,您不必等到加载完成后再访问玩家和敌人模型。

我建议你重构LoadManager一下并引入一个init()方法。此方法返回如下承诺:

init() {

    return new Promise( ( resolve ) => {

        this.loadingManager.onLoad = () => {

            resolve();
        };

    } );

}

在您的main.js中,您使用新方法,如下所示:

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

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

    // more logic

} );

还有其他方法可以实现此功能(例如通过async/ await),但对于开始它应该可以解决问题。


推荐阅读