Cannot read property 'root' of undefined

Hey guys, today i collided with a new problem, does anybody know whats wrong with my code? the similiar code works in another script, but somehow this one has an issue.

Everything else is working in those lines except this two trying to find object by name

Yes, you need to pass this as the third parameter to this.entity.collision.on at line 33.

2 Likes

Thank you so much, may i know or can u relate me to any topic or article where i can find something about that? Because im not really sure when i do need to use this as third parameter and when i dont need to. Or should i put this everytime to avoid such issues witch accessing objects?

Hi @smokys,

That’s a Javascript concept used when writing code inside methods that are part of an object instance.

In general you use this in Playcanvas scripts when you refer to a property or method that is part of that script. You will observe in many examples things like:

this.entity;
// or
this.app;

Those references to properties that this script instance holds. There isn’t a simple rule but you will get used to it slowly.

Try studying online some Javascript tutorials on how object oriented programming works in this language and you will start feeling more comfortable.

3 Likes

Thanks, im actually getting used to it slowly. I also learn a lot when i put topic here :stuck_out_tongue: because many people trying to help with the actuall isssue but also give an advices to avoid issues. anyway thanks for help i again learnt something new. love this forum <3

2 Likes

I think mostly it is easy to grasp when to use this keyword, considering there are a number of examples here.

Most of the Playcanvas scripts are an instance of an object, so when you use this inside a script, you want to access some property of that script. Just be careful when you have inline functions, like in your example, in initialize() you pass a function (function(entity) {...}) inside on() method. If you use this inisde that function, it will point to the instance that function belongs to, which would be the global scope (window). Since window doesn’t have an app property (only the script has), you get the undefined error. That is why on() method has a third parameter you can pass, as Will mentioned, which will define the scope of the keyword this, in case it would be used inside that function.

Here is an example:

Script.prototype.initialize = function() {
    var myArray = [1, 2, 3];
    myArray.forEach(function(value) {
        this.print(value);  // error, "this" points to window here, which has no "print" property
    });
};

Script.prototype.print = function(value) {
    console.log(value);
};

Most of the built in functions, like .forEach() in Javascript accept an optional argument that specifies where this should point to. Just like the event system in Playcanvas. You can google js array foreach and check MDN resource to see what arguments it takes. In case of an above example, it can be fixed by:

    ...
    myArray.forEach(function(value) {
        this.print(value);  // no error, "this" points to instance of Script, which has "print" property
    }, this);
    ...

If a method doesn’t accept a scope argument, you can always “bind” the function to use the scope of your choosing. We can write it in this way instead:

    ...
    myArray.forEach(function(value) {
        this.print(value);  // no error, "this" points to instance of Script, because of binding
    }.bind(this));
    ...

One common practice in ES5 was to save the scope in some variable and access it, instead of using this. For example, we could write it differently:

    ...
    var self = this;
    myArray.forEach(function(value) {
        self.print(value);  // no error, "self" variable stores the correct scope of the Script instance
    });
    ...

And lastly, if you use Javascript ES6 syntax, the new standard introduced arrow functions, which don’t have a problem with understanding the scope they are executed from. So, the following could be then written:

    ...
    myArray.forEach((value) => {
        this.print(value);  // no error, "this" points to instance of Script, because arrow function is clever
    });
    ...
4 Likes