Trying to LoadScene after http post

Hello,

I am trying to create a login page where once a user enters in a valid username and password they click a button and then go to the game scene.

I am having difficulty loading the game scene once the http post returns and has a valid username and password. A separate php file receives the http post and performs a SQL query and returns 0 if the query is valid.

Here is the script I am having trouble. It is attached to a button entity and once the user clicks and releases the post request is sent. I use timeout to have the function wait a certain amount of time for the request to return. This one will be a litter hard to debug for viewers of this post because the server the game posts to is on my machine.

The error I am getting is Uncaught TypeError: this.loadScene is not a function As of this post it is at line 65.

I am positive this is because the function loadScene is not defined within the onRelease function and can’t call it because of this. How should I change my code to load the game scene?

Much thanks in adavance. (code posted below)

var SceneChangeRL = pc.createScript('SceneChangeRL');
//Button for login and play
SceneChangeRL.attributes.add("sceneID",{type: 'string',default: "0",title: "Scene ID to Load"});
//SceneChangeRL.attributes.add("sceneIDR",{type: 'string',default: "0",title: "Scene ID to Load if Username Null"});

// initialize code called once per entity
SceneChangeRL.prototype.initialize = function() {
    this.entity.element.on("mouseenter",this.onEnter,this);
    this.entity.element.on("mousedown",this.onPress,this);
    this.entity.element.on("mouseup",this.onRelease,this);
    this.entity.element.on("mouseleave",this.onLeave,this);
    
    this.entity.element.on("touchstart",this.onPress,this);
    this.entity.element.on("touchend",this.onRelease,this);
};

// update code called every frame
SceneChangeRL.prototype.update = function(dt) {
};



SceneChangeRL.prototype.onRelease = function(event){
  //Initial check to ensure that login and password are correct length.
    if(pc.app.username.length < 8 && pc.app.password.length < 8){
//         this.loadScene(this.sceneIDR,function(){
        
//         });
        alert("No username OR username and/or password too short");
        
    }
    else{
//initialize new http request
        var go = new XMLHttpRequest();
//make request
        go = pc.http.post("http://localhost/sqlconnect/loginB.php",{"name" : pc.app.username,
                                                             
                                                             "password" : pc.app.password,
                                                             },function(err,response){
            
            
        });
        
//Wait one second for request to return and then parse responseText to see if query was valid
       setTimeout(function afterTwoSeconds() {
           if(go.responseText.split('\t',7)[0] == 0){
//THIS IS WHERE THE ERROR OCCURS - Uncaught TypeError: this.loadScene is not a function
               this.loadScene(this.sceneID,function(){
        
            });
        }else{
            alert(go.responseText);
        }
        }, 1000);
        
        
        
        
       
    }
};

//function that is being called to change scene if query is valid, return 0.
SceneChangeRL.prototype.loadScene = function(id,callback){
    var old = this.app.root.findByName('Root');
    var url = id + "json";
    
    
    //old.destroy();
    
    this.app.scenes.loadSceneHierarchy(url,function(err,parent){
       if(!err){
           old.destroy();
           //callback(parent);
       }else{
           //console.log("err");
           console.error(err);
       }
    });
};

Hi @hooymana,

Indeed this.loadScene() isn’t defined on the script. Instead use the scene registry to call it:

this.app.scenes.loadScene('scene url', function(){

}.bind(this));

Check the docs, there are other alternate methods available there, like load scene data or hierarchy by scene name:
https://developer.playcanvas.com/api/pc.SceneRegistry.html

2 Likes

Thank you for the reply @Leonidas !

I am still getting the following error:

Uncaught TypeError: Cannot read properties of undefined (reading ‘scenes’)

The code this error occurs is below.

Do I need to declare scenes within the afterTwoSeconds function?

setTimeout(function afterTwoSeconds() {
            //console.log(go.responseText.split('\t',7)[0]);
           if(go.responseText.split('\t',7)[0] == 0){
                //console.log(go.responseText.split('\t',7)[0]);

               this.app.scenes.loadScene('1234829.json', function(){

                }.bind(this));
        }else{
            alert(go.responseText);
        }
        }, 1000);

I think because you aren’t setting the context in your setTimeout callback. It should use .bind(this) as well, so this.app isn’t undefined.

setTimeout(function afterTwoSeconds() {
// ...
        }.bind(this), 1000);
2 Likes

And another correction, the callback in your timeout method should be anonymous, I don’t think you should be setting a name there:

setTimeout(function() {
// ...
        }.bind(this), 1000);
2 Likes

Hi @Leonidas,

This worked! Thank you. I also added code to destroy the old scene (see below). Once the new scene loaded the old scene was overlaid on top it.

setTimeout(function() {
//declare current scene
            var old = this.app.root.findByName('Root');
           if(go.responseText.split('\t',7)[0] == 0){
               this.app.scenes.loadScene('1234829.json', function(){

                }.bind(this));
//destroy current scene
               old.destroy();
        }else{
            alert(go.responseText);
        }
        }.bind(this), 1000);
1 Like

Hi @Leonidas

Quick follow-up, hopefully, related to this post. The new scene loads and the old scene is destoryed but I am now getting an error saying:

[movement.js?id=55699174&branchId=cadc9749-917a-43fd-95df-8ba3c255d79f:121]: Cannot set properties of undefined (setting ‘x’)

movement.js is attached to an entity for the new scene and x is referring to a force applied to the entity within the update method, this.force.x. The x is first defined in the initialize method within movement.js, this.force = new pc.Vec3(). It appears that initialize does not run prior to the update method, thus the error?

I have tried looking through the discussion boards and believed I should load the scene hierarchy but this turned chaotic, similar to this thread (code for my project below). Multiple entities load and still throwing the same error. Plus, when I try to change scenes after this point the old scene is no longer destroyed. The old thread talked about bind being the problem but referred to it as an event??

In short, how can I have initialize in movement.js run prior to update?

Also, I believe that with bind(this) on the load scene function will be called again when another scene is loaded, thus the old scenes not being destroyed??

Any help is appreciated!

from this script

setTimeout(function() {
            //console.log(go.responseText.split('\t',7)[0]);
           var old = this.app.root.findByName('Root');
            old.destroy();
           
           if(go.responseText.split('\t',7)[0] == 0){
                //console.log(go.responseText.split('\t',7)[0]);
                //var sceneItem = this.app.scenes.find("Scene Name");
//load scene hierarchy of next scene
             this.app.scenes.loadSceneHierarchy('1234829.json', function (err, entity) {
                    if (!err) {
//ball is name of entity with movement.js
                     var e = this.app.root.find("ball");
                    } else {
        // error
                    }
                }.bind(this));

               this.app.scenes.loadScene('1234829.json', function(){

                }.bind(this));
        
               
        }else{
            alert(go.responseText);
        }
        }.bind(this), 1000);