/*jshint esversion: 6 */
var ChangingScenes = pc.createScript('changingScenes');
ChangingScenes.attributes.add("sceneName", {type: "string", default: "", title: "Scene Name to Load"});
ChangingScenes.prototype.initialize = function(dt) {
// Change scenes in 1 second
var self = this;
setTimeout(function (){
self.loadScene(self.sceneName);
}, 1000);
};
ChangingScenes.prototype.loadScene = function (sceneName) {
// persist the Player entity so I can move it from scene to scene
if(!this.app.persist){
this.app.persist = {};
this.app.persist.player = this.app.root.findByName ('Root').findByName('Player');
p = this.app.persist.player.getPosition();
this.app.persist.player.setPosition(p.x, p.y + 2, p.z);
}
// remove the player before loading the new scene so it's not destroyed when I destroy the old scene
if(this.app.persist.player.parent) this.app.persist.player.parent.removeChild(this.app.persist.player);
// Get a reference to the scene's root object
var oldHierarchy = this.app.root.findByName ('Root');
// Get the path to the scene
var scene = this.app.scenes.find(sceneName);
// Load the scenes entity hierarchy
this.app.scenes.loadScene(scene.url, (err, scene) => {
if (!err) {
oldHierarchy.destroy();
pc.ComponentSystem.initialize(scene.root);
pc.ComponentSystem.postInitialize(scene.root);
// add the persisted player to the new scene
this.app.root.findByName ('Root').addChild(this.app.persist.player);
} else {
console.error('loadScene callback error: ', err);
}
});
};
Both scenes have an Entity named ‘Player’. Going from Scene 1 to Scene 2 would mean that when you are in Scene 2, you now have two Entities in the Scene Graph named ‘Player’.
I wanted to keep it super simple for the purposes of requesting help on this forum. In another version of this experiment I delete a player if there is already a player saved in this.app.persist, but it still has the same problem. Since, I only search by name a single time (if this.app.persist is not populated), having a Player in both scenes shouldn’t cause any name collisions. (Having a player in both scenes means that you can start in either scene 1 or scene 2 and it should still work.)
So far, I can’t even get the basics to work. Am I going about this wrong? If not, can you help me identify the bug that starts preventing this.app.persist.player from appearing in one of the scenes after a few scene switches?
Hmm, well, one thing you should consider if you really need another scene. Keep in mind, you will trigger the garbage collection on the scene switch. In most cases, it is simply enough to arrange your entities in “level 1”, “level 2” etc hierarchy of the same scene. Then simply enabling/disabling the required parent to switch the scenes, even though, technically, it is the same scene.
Nevertheless, one way to keep the “Player” entity is to reparent it to the app.root:
/*jshint esversion: 6 */
var ChangingScenes = pc.createScript('changingScenes');
ChangingScenes.attributes.add("sceneName", {type: "string", default: "", title: "Scene Name to Load"});
ChangingScenes.prototype.initialize = function(dt) {
// Change scenes in 1 second
this.timeout = 1;
if (!this.app.persist) {
var player = this.app.root.findByName('Player');
player.reparent(this.app.root);
player.setPosition(0, 2, 0);
player.enabled = true;
this.app.persist = {};
this.app.persist.player = player;
} else {
this.app.persist.player.enabled = true;
}
};
ChangingScenes.prototype.loadScene = function (sceneName) {
// Get a reference to the scene's root object
var oldHierarchy = this.app.root.findByName('Root');
// Get the path to the scene
var scene = this.app.scenes.find(sceneName);
// Load the scenes entity hierarchy
this.app.scenes.loadScene(scene.url, (err, scene) => {
if (!err) {
oldHierarchy.destroy();
pc.ComponentSystem.initialize(scene.root);
pc.ComponentSystem.postInitialize(scene.root);
} else {
console.error('loadScene callback error: ', err);
}
});
};
ChangingScenes.prototype.update = function(dt) {
this.timeout -= dt;
if (this.timeout < 0) {
this.timeout = 1;
this.loadScene(this.sceneName);
}
};
This way, when a new scene loads, it will be able to use references created by another scene. You should disable the original “Player” entity at start, so it won’t spawn when the scene is loaded again.
Because of the GUID system, when an entity with the same GUID is created when one already exists in the scene graph, thinks start to go wrong as the system can’t identify the correct set of data.
There are two ways around this that I can think of:
Use ‘prefabs’ and clone the objects at the start. The clone will have a new GUID and can be moved wherever with no clashes. When the template feature rolls into production, this will be much cleaner and easier to setup. Example project here: https://playcanvas.com/editor/scene/954585
Your suggestion not to do a scene switch is interesting. Perhaps I misunderstand the purpose of scenes. When WOULD it make sense, or be necessary, to use a new scene, if not for new levels?
Well, to be honest with you, I am yet to find a good use for scenes. Perhaps, if you have many levels, and you don’t want to hold them all in memory, could be one case. Someone with more experience than I do may give you a better example.