-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added changeScene API #4626
Added changeScene API #4626
Conversation
Project to test this PR with : https://playcanvas.com/project/979499 |
Right now in let url = sceneItem;
if (sceneItem instanceof SceneRegistryItem) {
url = sceneItem.url;
} else {
sceneItem = this.findByUrl(url);
if (!sceneItem) {
sceneItem = new SceneRegistryItem('Untitled', url);
}
} It could be shortened into this code: let url = sceneItem;
if (typeof sceneItem === 'string') {
sceneItem = this.findByUrl(url) || this.find(url) || new SceneRegistryItem('Untitled', url);
}
url = sceneItem.url; Then you can delete this code in if (!(sceneItem instanceof SceneRegistryItem)) {
sceneItem = this.find(sceneItem);
} Overall it removes lines of code and I don't know if scene names and scene URL's could conflict though (in my little testing everything worked as it should and the unit tests are also happy). |
I like the idea that loadScene* and changeScene can all take a name, URL or SceneRegistryItem and would make the loadScene* functions more flexible. Any opinions from the rest of the engine team? |
I've added @kungfooman's suggestion on being able to use the scene name and added a few more tests |
Thank you for the changes @yaustar Since changeScene(sceneItem, callback) {
/**
* This function is called before the new scene hierarchy is added.
*
* @param {SceneRegistryItem} sceneItem - The scene item
*/
const preface = (sceneItem) => {
const app = this._app;
// Destroy/Remove all nodes on the app.root
const rootChildren = app.root.children;
while (rootChildren.length > 0) {
const child = rootChildren[0];
child.reparent(null);
child.destroy?.();
}
app.applySceneSettings(sceneItem.data.settings);
};
this.loadSceneHierarchy(sceneItem, callback, preface);
}
loadSceneHierarchy(sceneItem, callback, preface) {
this._loadSceneData(sceneItem, false, (err, sceneItem) => {
if (err) {
if (callback) {
callback(err);
}
return;
}
if (preface) {
preface(sceneItem);
}
this._addHierarchyToScene(sceneItem.url, sceneItem.data, callback);
});
} Using arrow functions is reducing code size aswell, you don't need to worry about _proto.changeScene = function changeScene(sceneItem, callback) {
var _this2 = this;
var preface = function preface(sceneItem) {
var app = _this2._app;
var rootChildren = app.root.children;
while (rootChildren.length > 0) {
var child = rootChildren[0];
child.reparent(null);
child.destroy == null ? void 0 : child.destroy();
}
app.applySceneSettings(sceneItem.data.settings);
};
this.loadSceneHierarchy(sceneItem, callback, preface);
}; |
I'm not keen on use the preface as loadSceneHierarchy is existing public API and traditionally, the callback is the last param |
const app = this._app; | ||
|
||
const onBeforeAddHierarchy = (sceneItem) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This app
closure variable also has too much context and maybe add JSDoc?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is JSDoc needed here for a private function that is only used in the scope of the current class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess its not needed, I just use them as a mind crutch and when the types are checked, it can offer some insight about what is going wrong in which position
src/framework/scene-registry.js
Outdated
const app = this._app; | ||
|
||
this._loadSceneData(sceneItem, false, function (err, sceneItem) { | ||
this._loadSceneData(sceneItem, false, (err, sceneItem) => { | ||
if (!err) { | ||
self._app.applySceneSettings(sceneItem.data.settings); | ||
app.applySceneSettings(sceneItem.data.settings); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you are using arrow functions now, you can just use this
and move that closure variable into the arrow function itself. And since app
is only used once, it doesn't really need to be declared at all
I am running into an issue loading SeeMore as non-trivial scene and for some reason it doesn't destroy the old camera: (one camera rendering over the other) I can fix it by adding this to your app.scene?._activeCamera?.node?.destroy(); But I don't understand it, shouldn't the camera be in |
That's odd, there's no more than 1 scene in that project Edit: I just tried it with my branch and can't reproduce your issue? |
Testing with a Seemore fork with changing scenes with the existing stable engine and the double render is there too: https://playcanvas.com/project/983477/overview/f-seemore |
Thank you for testing, I downloaded SeeMore in 2019 but I also just tested the last version and it has the same issue.
const rootChildren = pc.root.children;
while (rootChildren.length > 0) {
const child = rootChildren[0];
child.reparent(null);
child.destroy?.();
}
The first cam seems to "survive" 🧟 |
I tried this with engine 1.56.0 (current stable) and loadSceneSettings + Hierarchy methods and the issue is there too. This means it's not a new issue that this PR introduces |
I am also not quite happy with The first step would be to move your scene clearing code into New method for clear() {
this.fire("clear");
const app = getApplication();
// Destroy/Remove all nodes on the app.root
const rootChildren = app.root.children;
while (rootChildren.length > 0) {
const child = rootChildren[0];
child.reparent(null);
child.destroy?.();
}
this?._activeCamera?.node?.destroy();
} (the last line with The changeScene(sceneItem, callback) {
const app = this._app;
app.scene.once("beforeAddHierarchy", (sceneItem) => {
app.scene.clear();
app.applySceneSettings(sceneItem.data.settings);
});
this.loadSceneHierarchy(sceneItem, callback);
}
Finally, in if (onBeforeAddHierarchy) {
onBeforeAddHierarchy(sceneItem);
}
const app = this._app; We simply have to fire the event while passing const app = this._app;
app.scene.fire("beforeAddHierarchy", sceneItem); |
I would not use |
Yes, I can imagine that, for testing I just needed a way to clear the entire scene, since deleting only |
I'm less keen to add an event into a system that hasn't used them before. It feels a bit overkill and would like to put a pin in it here for team review. In regards to Seemore, I will create a new ticket to investigate as that's odd but not introduced by this PR. Maybe due to the use of zones or portals? |
It's really strange the Camera component survives the scene hierarchy getting deleted. There must be some code re-adding it or similar? If you have a repro, it'd be interesting to trace layer composition:
at the point the hierarchy is deleted, I'd expect this to print no render actions - meaning no cameras are in the scene. |
@mvaligursky Ready to be reviewed :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
approving with small comments
Co-authored-by: Martin Valigursky <59932779+mvaligursky@users.noreply.github.com>
Updated: Tue 20 Sep 2022
This is to address the many topics for switching scene in PlayCanvas. The page and helper script I wrote doesn't seem to be enough https://developer.playcanvas.com/en/user-manual/packs/loading-scenes/
So I'm adding the most common use case to the API.
Changing scenes becomes a one liner with this change where it loads the scene data, destroys all entities under the
app.root
and adds the scene settings and hierarchy:This PR also adds support for loading scene settings/hierarchy by name, again reducing the extra boilerplate that the user needs to write.
I confirm I have read the contributing guidelines and signed the Contributor License Agreement.