Switching scenes when player contacts an object

I am trying to have the scene to switch when the player comes in contact with an object.
For example, when the player completes the objective of the first level then the level is switched to the next level of the game.

This is my project:
https://playcanvas.com/project/727834/overview/first-project

this is the code for the object that the player has to touch in order to switch scenes

var ContactScene = pc.createScript('contactScene');

var x = 0;

// initialize code called once per entity
ContactScene.prototype.initialize = function() {
    if (this.target) {
        // Subscribe to the triggerenter event of this entity's collision component.
        // This will be fired when a rigid body enters this collision volume.
        this.entity.collision.on('triggerenter', this.onTriggerEnter, this);
    }
};

ContactScene.prototype.OntriggerEnter = function (){
    var x = 1; 
    console.log(x);
};

ContactScene.prototype.update = function (){
    this.app.fire('contactScene:move', x);
   };

This is the code to switch scenes

var ChangingScenes = pc.createScript('changingScenes');

ChangingScenes.attributes.add("sceneId", {type: "string", default: "0", title: "Scene ID to Load"});

ChangingScenes.prototype.initialize = function() {
    var oncontactSceneMove = function(x) {
        console.log(x);
    };

    // listen for the player:move event
    this.app.on('contactScene:move', oncontactSceneMove);
};

ChangingScenes.prototype.update = function(dt) {
    if (x == 1) {
        this.changeScenes();
    }
};



ChangingScenes.prototype.changeScenes = function() {
    // Get a reference to the current root object
    var oldHierarchy = this.app.root.findByName ('Root');
    
    // Load the new scene. The scene ID is found by loading the scene in the editor and 
    // taking the number from the URL
    // e.g. If the URL when Scene 1 is loaded is: https://playcanvas.com/editor/scene/475211
    // The ID is the number on the end (475211)
    this.loadScene (this.sceneId, function () {
        // Once the new scene has been loaded, destroy the old one
        oldHierarchy.destroy ();
    });
};

ChangingScenes.prototype.loadScene = function (id, callback) {
    // Get the path to the scene
    var url = id  + ".json";
    
    // Load the scenes entity hierarchy
    this.app.loadSceneHierarchy(url, function (err, parent) {
        if (!err) {
            callback(parent);
        } else {
            console.error (err);
        }
    });
};

Hi @RoaringLegend456,

You have a typo in your code, JS is a case sensitive lang. Here your onTriggerEnter method doesn’t use the same name with the event handler:

ContactScene.prototype.OntriggerEnter = function (){
    var x = 1; 
    console.log(x);
};

Change that and your callback will fire. Then as a next step try your changeScenes method on the other script using global events.

@Leonidas
thank you for noticing the typo.

but I am not sure what you mean about using global events.
I’m still a bit new to coding.

Good, so you have two different scripts, one being responsible for listening to the trigger event and the other for chancing the current scene.

You need to find a way to communicate when that will happen. Here is a manual page on how scripts can communicate, it can be quite helpful in your case:

https://developer.playcanvas.com/en/user-manual/scripting/communication/

@Leonidas

I was looking at that page and tried to incorporate it in but I don’t think I understand it fully and I think I’m doing it wrong

Is there a way to see what script is having the problem.

As i’m not sure if the first script is working and the second script is getting the information.

What error are you getting?

To check if your onTriggerEnter method is working try adding a log to the browser console and then open it to check if it fires or not.

@Leonidas

I’m not getting any errors but nothing happens when the player comes in contact with the object.
do you use

console.log()

if so it gives me an error when I use it to print something in the console or it doesn’t work

when I use
console.log(information);
it gives an error message saying (information is not defined)
and when I define it using a variable it doesn’t show up
var information = 1;

edit:
I found out how to fix this

I figured out what is not working but couldn’t figure out how to fix it

here is the code that is not working

ContactScene.prototype.initialize = function() {
    if (this.target) {
        // Subscribe to the triggerenter event of this entity's collision component.
        // This will be fired when a rigid body enters this collision volume.
        this.entity.collision.on('triggerenter', this.OnTriggerEnter, this);
    }
    
};

ContactScene.prototype.OnTriggerEnter = function (){
    var x = 1; 

};

there not communicating with each other.

So, here is how I’d update your code to make the two scripts communicate a change scene event:

contact scene.js

var ContactScene = pc.createScript('contactScene');

// initiali;ze code called once per entity
ContactScene.prototype.initialize = function() {
    this.entity.collision.on('triggerenter', this.OnTriggerEnter, this);    
};

ContactScene.prototype.OnTriggerEnter = function (){

    this.app.fire('contactScene:move');
};

changing-scenes.js

var ChangingScenes = pc.createScript('changingScenes');

ChangingScenes.attributes.add("sceneId", {type: "string", default: "0", title: "Scene ID to Load"});
ChangingScenes.attributes.add('playerEntity', { type: 'entity' });

ChangingScenes.prototype.initialize = function() {

    // listen for the player:move event
    this.app.on('contactScene:move', this.changeScenes, this);
    
    this.on('destroy', function() {
        this.app.off('contactScene:move',this.changeScenes, this);
    });
};

ChangingScenes.prototype.changeScenes = function() {
    // Get a reference to the current root object
    var oldHierarchy = this.app.root.findByName ('Root');
    
    console.log(this.sceneId);
    
    // Load the new scene. The scene ID is found by loading the scene in the editor and 
    // taking the number from the URL
    // e.g. If the URL when Scene 1 is loaded is: https://playcanvas.com/editor/scene/475211
    // The ID is the number on the end (475211)
    this.loadScene (this.sceneId, function () {
        // Once the new scene has been loaded, destroy the old one
        oldHierarchy.destroy ();
    });
};

ChangingScenes.prototype.loadScene = function (id, callback) {
    // Get the path to the scene
    var url = id  + ".json";
    
    // Load the scenes entity hierarchy
    this.app.loadSceneHierarchy(url, function (err, parent) {
        if (!err) {
            callback(parent);
        } else {
            console.error (err);
        }
    });
};
3 Likes

thanks the script communication works but the scene changing gives an error on line 28 of changing-scenes.js
So the scene doesn’t change fully.

error message:
Uncaught TypeError: Cannot read property ‘destroy’ of null

This is the line of code

  oldHierarchy.destroy ();

I tried fixing it by myself but I couldn’t figure it out so I put it back to the original of your code.

That is because this is the first time you load a scene, there isn’t an older hierarchy to remove. Try putting a guard if in place so it doesn’t throw an error:

ChangingScenes.prototype.changeScenes = function() {
    // Get a reference to the current root object
    var oldHierarchy = this.app.root.findByName ('Root');
    
    // Load the new scene. The scene ID is found by loading the scene in the editor and 
    // taking the number from the URL
    // e.g. If the URL when Scene 1 is loaded is: https://playcanvas.com/editor/scene/475211
    // The ID is the number on the end (475211)
    this.loadScene (this.sceneId, function () {
        // Once the new scene has been loaded, destroy the old one
        if( oldHierarchy ){
            oldHierarchy.destroy ();            
        }
    });
};

This gets rid of the error but doesn’t get rid of the old scene

here is my project again just run it so you can see the error
https://playcanvas.com/editor/scene/1009882

Ah your issue is that you’ve changed the name of your base scene from Root to scene. Change that back to Root and your code will work and remove the old scene.

image

image

1 Like

thanks, it works now.
thankyou for your help.
I really appreciated it

for anybody who wants this code here is the updated/working code.

contact-scene.js

var ContactScene = pc.createScript('contactScene');

// detects if the entity contacts/collides with the object.
ContactScene.prototype.initialize = function() {
    this.entity.collision.on('triggerenter', this.OnTriggerEnter, this);    
};

ContactScene.prototype.OnTriggerEnter = function (){
// sends a message to changing-scenes.js
    this.app.fire('contactScene:move');
};

changing-scenes.js

var ChangingScenes = pc.createScript('changingScenes');

ChangingScenes.attributes.add("sceneId", {type: "string", default: "0", title: "Scene ID to Load"});
ChangingScenes.attributes.add('playerEntity', { type: 'entity' });

ChangingScenes.prototype.initialize = function() {

    // listen for the contactScene:move event
    this.app.on('contactScene:move', this.changeScenes, this);
    
    this.on('destroy', function() {
        this.app.off('contactScene:move',this.changeScenes, this);
    });
};

ChangingScenes.prototype.changeScenes = function() {
    // Get a reference to the current root object
    var oldHierarchy = this.app.root.findByName ('Root');
    
    console.log(this.sceneId);
    
    // Load the new scene. The scene ID is found by loading the scene in the editor and 
    // taking the number from the URL
    // e.g. If the URL when Scene 1 is loaded is: https://playcanvas.com/editor/scene/475211
    // The ID is the number on the end (475211)
    this.loadScene (this.sceneId, function () {
        // Once the new scene has been loaded, destroy the old one
        if( oldHierarchy ){
            oldHierarchy.destroy ();
        }
    });
};

ChangingScenes.prototype.loadScene = function (id, callback) {
    // Get the path to the scene
    var url = id  + ".json";
    
    // Load the scenes entity hierarchy
    this.app.loadSceneHierarchy(url, function (err, parent) {
        if (!err) {
            callback(parent);
        } else {
            console.error (err);
        }
    });
};

credit goes to @Leonidas for helping

3 Likes