[SOLVED] Extends not working because the child class wasn't in the same file

Screenshot 2021-05-24 121439

This one is pretty straightforward. soldier2ai extends soldier2. I have a ParentClass and ChildClass test that works beautifully, but for some reason it won’t work on this AI script.

soldier2.js

class Soldier2 extends pc.ScriptType {
    initialize() {
        console.log('soldier 2 initialized');
    }
}

pc.registerScript(Soldier2, 'soldier2');

// ...attributes

soldier2ai.js

class Soldier2ai extends Soldier2 {
    initialize() {
        console.log('soldier 2 ai initialized');
    }
}

pc.registerScript(Soldier2ai, 'soldier2ai');

// ...attributes

Both console messages are still called, but I can’t select any attributes for the ai because of this.

Lastly, soldier2.js comes before soldier2ai.js in the Scripts Loading Order, as it should.

There’s a limitation on parsing where it only considers the file that the script type is in. As the parent class is in another file, it won’t find it on parsing.

I see, thanks for the clarification.

I had a short question still. Consider this:

parent.js

class Parent extends pc.ScriptType {}

pc.registerScript(Parent , 'parent ');

Parent.attributes.add('thing', {
    type: 'entity',
});

// -----------------------------------

class Child extends Parent {
    initialize() {
        console.log(this.thing); // undefined
    }
}

pc.registerScript(Child , 'child ');

How can I get the attribute thing in the Child class?

I haven’t use inheritance/extends myself on script types. @LeXXik or @Leonidas, have you done work on this?

Nevermind, I get how it works now.

From what I read in another post is that if you extend a class, you need to add both scripts to an object in order for it to work, like this:

Screenshot 2021-05-24 152028

Seems alright. But when you think about it, there isn’t just 1 attribute of the head anymore. There’s actually 2: one for the soldier2, and one for the soldier2ai, which is left undefined.

So the solution is to do this:

class Soldier2ai extends Soldier2 {
    initialize() {
        var soldier2 = this.entity.script.soldier2;
        this.head = soldier2.head;

        console.log(this.head); // prints the head entity.
    }
}

Slowly wandering off to C# inheritance dreamland

But yes: fixed.

1 Like

Right, there is no direct access to the script attributes of the parent, unfortunately.

What I tend to do is avoiding attributes on parents (and children in general). Instead I have a shared entity with a ScriptType script. For example, “Settings” that holds some attributes with game settings. I then add it to the base class, and all children have access to it:

// Settings
class Settings extends pc.ScriptType {}
pc.registerScript(Settings, 'settings');
Settings.attributes.add(points, { type: 'number' });


// Parent
class Parent extends pc.ScriptType {
    initialize() {
        this.settings = this.app.root.findByName('Settings').script.settings;
    }
}
pc.registerScript(Parent, 'parent');


// Child
class Child extends Parent {
    initialize() {
        // this is fine and uses attribute exposed in Editor
        const points = this.settings.points;
    }
}
pc.registerScript(Child, 'child');
2 Likes

A workaround for having classes in different script files working with PlayCanvas Editor could be something like this:

Vehicle.js

class Vehicle extends pc.ScriptType {
    static addAttributes() {
        this.attributes.add('speed', {type: 'number', title: 'Speed'});
    }

    constructor(...args) {
        super(...args);
    }

    initialize() {

    }

    update(dt) {

    }
}

pc.registerScript(Vehicle, 'vehicle');
pc.Vehicle = Vehicle;
pc.Vehicle.addAttributes();

Car.js

var Parent = pc.Vehicle ?? pc.ScriptType;

class Car extends Parent {
    static addAttributes() {
        this.attributes.add('speed', {type: 'number', title: 'Speed'});
        this.attributes.add('wheels', {type: 'number', precision: 0, title: 'Wheels'});
    }

    constructor(...args) {
        super(...args);
    }

    initialize() {
        super.initialize();
    }

    update(dt) {
        super.update(dt);
    }
}

pc.registerScript(Car, 'car');
pc.Car = Car;
pc.Car.addAttributes();

You will still need to copy the attributes from the parent to the child, but at least this gives you an option for having classes in their own script file.

There is no need in that. They can be in different files. Simply make sure the base class script is loaded first in the project scripts loading order.