three.js 如何确保在加载模型后加载其他 javascript 文件
three.js how to make sure your other javascript file load after your models was loaded
所以我有一个 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);
我的逻辑很简单,加载负载管理器并加载模型,这样我就可以在我的场景管理器中使用它们。
但是在日志中我可以看到负载管理器首先调用它们而不是加载模型,它打开场景管理器,甚至在其他导入模块之前就开始调用模型。
知道为什么会这样吗?我该如何解决这个问题,以便在调用 scenemanager 之前加载模型?抱歉,我是 javascript 的新手。
问题是加载资产是一个异步操作,您不会等到加载完成才访问玩家和敌人模型。
我建议您稍微重构 LoadManager
并引入 init()
方法。这种方法 returns 像这样的承诺:
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
),但一开始它应该可以解决问题。
所以我有一个 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);
我的逻辑很简单,加载负载管理器并加载模型,这样我就可以在我的场景管理器中使用它们。
但是在日志中我可以看到负载管理器首先调用它们而不是加载模型,它打开场景管理器,甚至在其他导入模块之前就开始调用模型。
知道为什么会这样吗?我该如何解决这个问题,以便在调用 scenemanager 之前加载模型?抱歉,我是 javascript 的新手。
问题是加载资产是一个异步操作,您不会等到加载完成才访问玩家和敌人模型。
我建议您稍微重构 LoadManager
并引入 init()
方法。这种方法 returns 像这样的承诺:
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
),但一开始它应该可以解决问题。