[SOLVED] Camera not transitioning with scene change

Ok so we have 2 scenes, a movement test scene and a library with a portal. When you take the portal, delete the current scene and bring in the new scene, the camera will be stuck far away from the player. But you can still see the player and see them move around. We are unsure why this is happening.

Here is the portal code.

var PortalTrigger = pc.createScript('portalTrigger');

PortalTrigger.attributes.add('DestinationScene', {type: "string"});

// initialize code called once per entity
PortalTrigger.prototype.initialize = function() {    
    this.entity.collision.on('triggerenter', this.loadScene, this);
};

PortalTrigger.prototype.loadScene = function() {
    var oldHierarchy = this.app.root.findByName('Root');
    
    var scene = this.app.scenes.find(this.DestinationScene);
        
    this.app.scenes.loadSceneHierarchy(scene.url, function(error, parent) {
        if(!error) {
            oldHierarchy.destroy();
        } else {
            console.error(error);
        }
    });
};

Link to the project: PlayCanvas | HTML5 Game Engine

Hi @Aaron_B,

So, I gave it a try and here what happens when I step in through the portal:

The camera freezes and there is no player movement. I think that’s to be expected since the player/camera entity has been removed together with the old scene, right?

Going in the console and enabling the new player entity seems to fix the issue. I think that’s what missing, you do all the steps correctly, and only need to enable the player entity in the new scene.

Sorry, we forgot to re enable the player after some testing. Can you please try it again, and see that if the player is enabled then the camera just gets stuck.

1 Like

Not sure what the issue is here, if you keep the player entity disabled and enable it after the new scene has finished loading and adding the hierarchy in place, it works as expected.

I suspect the issue may be some event handlers of the first player controller aren’t properly removed. That won’t happen automatically when the entity is destroyed, for example these events need to be removed while you are destroying the first scene:

Check how the input handlers are being added/removed on the default orbit camera script, when creating a new model viewer project.

Thank you, Leonidas, you are incredibly helpful! That seems to work (enabling the player), can you help me understand why it’s necessary to re enable the player. Isn’t the old player supposed to be fully destroyed and the new player should take over completely?

I’ve found the issue.

There are a range of smaller issues that may cause problems later on such as use of global variables and events not being cleared up correctly but the one that was causing the issue is the use of app.root.findByName.

findByName will return the first entity in the hierarchy that it finds.

We have your cameraMovement script init function here:

// Called once after all resources are loaded and before the first update
CameraMovement.prototype.initialize = function () {
    this.eulers = new pc.Vec3();
    this.touchCoords = new pc.Vec2();

    var app = this.app;
    app.mouse.on("mousemove", this.onMouseMove, this);
    
    app.mouse.on("mousedown", function () {
        app.mouse.enablePointerLock();
    }, this);
    
    this.on('destroy', function() {
        this.app.off("mousedown", this.onMouseDown, this);
        this.app.off("mousemove", this.onMouseMove, this);
    }, this);
    
    this.rayEnd = app.root.findByName('RaycastEndPoint');
};

Note that it’s looking for RaycastEndPoint.

Consider your scene loading script:

PortalTrigger.prototype.loadScene = function() {
    var oldHierarchy = this.app.root.findByName('Root');
    
    var scene = this.app.scenes.find(this.DestinationScene);
        
    this.app.scenes.loadSceneHierarchy(scene.url, function(error, parent) {
        if(!error) {
            oldHierarchy.destroy();
        } else {
            console.error(error);
        }
    });
};

The order here is that it destroys the old hierarchy AFTER it has loaded the new scene.

So when the cameraMovement init function is called when the scene is loaded, BOTH scenes currently are loaded are therefore there are 2 instances of an entity named RaycastEndPoint.

The reason why enabling the player after the scene has loaded worked is because the old scene is destroyed before the player was enabled.

The fix is to change it so it’s searching within a smaller scope:

    this.rayEnd = this.entity.parent.findByName('RaycastEndPoint');

The fixed project is here: https://playcanvas.com/editor/scene/1150428

I’ve also cleaned up all the globals and callbacks.

2 Likes

Wow, thank you so much @yaustar. Solved our issue, thank you for explaining why it wasn’t working right. You totally didn’t have to but thanks for the cleanup as well!