Hello, i’m trying to create a code which changes scenes in my game project. Actually i managed to change scenes but not exactly as i wanted to be. Here’s the problem; i have two scenes in my project, menu screen and the game screen. I can switch from menu to game and from game to menu just fine however i can’t go switch from menu to game again. In the menu scene i have switchScene script attached to the button entity
and this is the contents of the switchScenes script:
SwitchScene.prototype.loadScene = function () {
var oldSceneRootEntity = this.app.root.findByName('Root');
var sceneItem = this.app.scenes.find('Shooting Range');
this.entity.button.on('click', function (event) {
this.app.scenes.loadSceneHierarchy(sceneItem, function (err, loadedSceneRootEntity) {
if (err) {
console.error(err);
} else {
// Scene hierachary has successfully been loaded
oldSceneRootEntity.destroy();
}
});
}, this);
this function was inside update before but when it runs in update, it duplicates the entities of the game scene so i decided to move it inside a seperate function and call it when the button is pressed but it’s not working right now
In the game scene, i have a Game Manager entity and attached to it is a gameManager script :
GameManager.prototype.update = function (dt) {
this.loadScene();
};
GameManager.prototype.loadScene = function () {
var oldSceneRootEntity = this.app.root.findByName('Root');
var app = this.app;
if (this.app.keyboard.isPressed(pc.KEY_ESCAPE)) {
this.app.scenes.loadSceneHierarchy('Menu Screen', function (err, loadedSceneRootEntity) {
if (err) {
console.error(err);
} else {
// Scene hierachary has successfully been loaded
oldSceneRootEntity.destroy();
}
});
}
};
this is for switching from game to menu by pressing the escape key.
As far as i understand the loadSceneHierarchy function shouldn’t run inside init or update methods. It should run once when i press on start button and hit escape. I couldn’t figure out the right way to do this, can anyone help me ?
Checking for a key press can basically only in the update function. Below I replaced your key press check. I think it’s also better to use wasReleased instead of isPressed, to prevent it’s running repeatedly when the user press the key to long.
GameManager.prototype.update = function (dt) {
if (this.app.keyboard.wasReleased(pc.KEY_ESCAPE)) {
this.loadScene();
}
};
GameManager.prototype.loadScene = function () {
var oldSceneRootEntity = this.app.root.findByName('Root');
var app = this.app;
this.app.scenes.loadSceneHierarchy('Menu Screen', function (err, loadedSceneRootEntity) {
if (err) {
console.error(err);
} else {
// Scene hierachary has successfully been loaded
oldSceneRootEntity.destroy();
}
});
};
Thank you very much for your reply. What about this one
SwitchScene.prototype.loadScene = function () {
var oldSceneRootEntity = this.app.root.findByName('Root');
var sceneItem = this.app.scenes.find('Shooting Range');
this.entity.button.on('click', function (event) {
this.app.scenes.loadSceneHierarchy(sceneItem, function (err, loadedSceneRootEntity) {
if (err) {
console.error(err);
} else {
// Scene hierachary has successfully been loaded
oldSceneRootEntity.destroy();
}
});
}, this);
i want to call this function by pressing on the start game button but it doesn’t work this way
What you do here is checking if the button is pressed inside the function you want to call when the button is pressed. So that will not work. Since you want to use the button event, you should replace line 4 and 15 (line 16 is missing) to the initialize function and call this.loadScene() with it.
YESSSSS!!! THANK GOD OR WHATEVER CREATED THE UNIVERSE BUT THANK YOU ABOVE ALL OF THEM. I’ve been working to do this for 3-4 days. I was almost going to give up. I really want to cry now. Thanks a million times friend and pls excuse my antics, but i’m really emotional right now
i know i’m asking too much but do you have any idea why this isn’t working on a HTML menu? Same thing happens, it loads the game first time but cannot switch back to the game again. This is the code:
witchScene.prototype.initialize = function () {
document.getElementById('start-button').addEventListener('click', () => {
if (document.getElementById('name-input').value !== '') {
document.querySelector('.container').classList.add('hidden');
this.loadScene();
}
});
};
I think the problem is that when you switch the scene you hide all html elements, but when you switch back you create everything again. So my guess is that all html elements are duplicated. I was be able to avoid this with some changes in your Ui.js script.
var Ui = pc.createScript('ui');
var initialized = false;
Ui.attributes.add('html', {
type: 'asset',
assetType: 'html'
});
Ui.attributes.add('css', {
type: 'asset',
assetType: 'css'
});
// initialize code called once per entity
Ui.prototype.initialize = function () {
if (!initialized) {
initialized = true;
var div = document.createElement("div");
div.id = "ui";
div.innerHTML = this.html.resource;
document.body.appendChild(div);
style = pc.createStyle(this.css.resource);
document.head.appendChild(style);
}
else {
document.querySelector('.container').classList.remove('hidden');
}
};
For some reason switching to your game scene for the second time duplicates everything, but I’m not sure why. Replacing this.loadScene(); with the new API solves this problem.
Replacing this.loadScene(); with the new API solves this problem.
I use the new API. loadScene function contains this:
SwitchScene.prototype.loadScene = function () {
var oldSceneRootEntity = this.app.root.findByName('Root');
var sceneItem = this.app.scenes.find('Shooting Range');
this.app.scenes.loadSceneHierarchy(sceneItem, function (err) {
if (err) {
console.error(err);
} else {
// Scene hierachary has successfully been loaded
oldSceneRootEntity.destroy();
}
});
};
Only i use loadSceneHierarchy instead of changeScene. It shouldn’t be duplicating the entities bcs of this line “oldSceneRootEntity.destroy();” The last time i tried it wasn’t duplicating anything, it worked as it was meant to be
I checked your project and I see you don’t use my script. You only use some parts of my script.
Sry i noticed my mistake later but it didn’t work after i fixed that either.
I really don’t understand what you mean by New API. I wrote that script by completely looking at this link: https://developer.playcanvas.com/en/user-manual/packs/loading-scenes/
the same link you shared with me. This is the code used to load the hierarchy of the new scene and destroy the root on scene change:
// Find the Scene Registry Item by the name of the scene
var sceneItem = this.app.scenes.find('Some Scene Name');
// Assume the old scene hierarchy's root entity is named 'Root' which is the default name
var oldSceneRootEntity = this.app.root.findByName('Root');
// Load the scene hierarchy with a callback when it has finished
this.app.scenes.loadSceneHierarchy(sceneItem, function (err, loadedSceneRootEntity) {
if (err) {
console.error(err);
} else {
// Scene hierachary has successfully been loaded
oldSceneRootEntity.destroy();
}
});
I used the exact same code. I did everything by the book. Plus there’s no duplication issue when i use the PC’s button element, it only happens on HTML menu. Pls try it now: https://launch.playcanvas.com/1604404?debug=true
Anyway my boss told me i can ditch the HTML menu, he said PC button element is fine. So we don’t have to deal with that anymore. Thanks a million for all your help again !!
Below the new API, it destroys the old hierarchy and load the new hierarchy.
Ok but it doesn’t say anywhere that it’s the old API. My supervisor had told me that i need to do it with loadSceneHierarchy. Before this I used fire events to change scenes and get a “deprecated” warning in the console. So i thought that was the old API. Also they show the “oldSceneRootEntity.destroy();” command with the “loadSceneHierarchy” function in the PC manual. The whole thing is pretty confusing if you’re not very experienced with Play Canvas.
PS: If it’s the old API, i think they need to update the manual to prevent confusion
The new API has been developed at my request to make it all a bit easier. Since it is easier to use, I therefore recommend using it. The other API’s are not necessarily old, but less easy to use. Problems arise if you start using methods interchangeably.
Its not old or deprecated API. The changeScene function was added to make the process of ‘changing scenes’ much easier for most people.
The existing API such as loadSceneHierarchy and others still have their uses that the user manual page goes in full detail into with examples.
Which is why on that page, the very first thing we sure and say to use is the changeScene function. If your instructor is saying not to use a function that makes ‘changing scenes’ as simple as possible, then that’s a problem with your course/instructor.