I’ve read this documentation, and wanted to understand it a bit more.
I currently have a Ship class, for Starships in my game. Large amounts of enemy ships can be created, and the player’s ships are created once every scene.
In the class, I have this method:
This seems like the perfect place to use instances, since the models are exactly the same. Since the models are used across multiple scenes, could it be possible to simply create one for each ship type, then instantiate it when it’s needed? If so, how? I’m fully aware of (Mesh).createInstance, though that does not allow for a different scene.
Even if it would work (which I don’t think it will), I wouldn’t recommend trying to put an instance in a separate scene from the mesh from which it was instantiated. Meshes and instances share and rely on a lot of information that’s in their own scenes – materials, etc. – and I’m not sure what would be gained by trying to have those dependencies cross among many scenes. Furthermore, the lifetimes of scenes can be different, and the objects within a scene can only remain “alive” as long as the scenes that contain them persist. Instances with inter-scene dependencies would break this conception pretty significantly.
Instead of this, I’d recommend just creating one “instance prototype” for each scene that you’re using, then create the instances you use in that scene from that one. While the “instance prototype” will be loaded into the scene as many times as you have scenes, it won’t actually be downloaded multiple times because of caching mechanisms, so it should be pretty lightweight. This, I think, should give you pretty much all the benefits of using instances without requiring you to introduce dependencies across scene boundaries.
const Level = class extends Scene{ //creates a new solar system / level / scene
constructor(){ //ignoring the rest of the constructor code since it's not relavent
this.genericShips = {};
for(let i in ship.generic){
SceneLoader.LoadAssetContainer('','data:'+ship.generic[i].model, this, imported => {
this.genericShips[i] = Object.assign(imported.meshes[0], {
rotationQuaternion: null,
isVisible: false,
material: Object.assign(imported.materials[0],{
realTimeFiltering: true,
realTimeFilteringQuality: [2,8,32][+settings.render_quality],
reflectionTexture: scene.probe.cubeTexture,
roughness: 0,
metallic: 1
})
})
}
}
}
}
//inside the ship class:
addToScene(scene = game.scene()){
if(!scene instanceof Level) throw new TypeError('(Ship).addToScene(): scene must be a Level!')
this.meshes[scene.id] = scene.genericShips[this.type].createInstance(this.name);
}
Hm… This has been working ok, except for a timing issue. Oversimplified:
class Planet extends StarBody{
constructor(enemies = [], scene){
//create the planet and stuff
for(let e of enemies){
let enemy = new Ship(e, scene);
this.enemies.push(enemy);
}
}
}
class Level extends Scene{
constructor(){
//create a new scene and stuff
for(let i in ship.generic){
//load the ship template meshes into this.genericShips
}
for(let i in names){
this.planets.push(new Planet (...)); //fails since the models have not been loaded yet.
}
}
}
Maybe wrapping an async around it would work? Any other and/or better way to do this?
class Level extends Scene{
constructor(){
(async function() {
//do stuff
for(let i in ship.generic){
await SceneLoader.LoadAssetContainerAsync(...)
...
}
//create planets
})();
}
}