so I want both âProductDialogueâ and âQuickNavigationDialogueâ to inherit from âDialogueBaseâ
such that I remove the same attributes mentioned in all classes.
I found this post:
which has some useful info, but still canât figure out what to do.
Mainly the syntax is confusing, we donât have a constructor.
Any hints or examples please
So rather than having a âbaseâ, think of it as a collection of behaviours.
In this case, I would have the Dialogue as itâs own component with all the references and then have ProductDialogue keep a reference to the Dialogue internally. This will allow you to use common behaviour from the Dialogue while allowing for customised behaviour.
I understand yaustar 's point that PlayCanvas is entity based more than OOP based. I see that as a point of view and not a technical limitation. Thus, both entity-component architecture and OOP architecture can coexist. As a Unity Developer with 8 years of full-time experience, I cannot imagine creating a professional project without âextending MonoBehaviourâ (the equivalent of the subject of this post). It would be a foolish restriction for Unity to ignore it and thus I think its a unnecessary restriction to impose on PlayCanvas.
So again, how can we accomplish Vasken 's request?
You should look into using TypeScript. It has both advantages and drawbacks in the context of PlayCanvas, but one of the advantages is that TypeScript supports language features youâll recognize from C# such as inheritance.
Yes, TypeScript is a superset of JavaScript and works fine with PlayCanvas when itâs compiled to vanilla JavaScript. You can see the code to extend a script in the link I posted above.
With TypeScript youâll work with an offline editor and upload the code to PlayCanvas. Currently, an official workflow for this hasnât been released yet, but itâs coming. So, working with TypeScript right now requires a bit of a hack, but it does work and many developers think itâs worth the effort. Weâre currently finalizing our third commercial game written in TypeScript, and all future productions will be in TypeScript as well.
Great. Your example does not include PlayCanvas. How would your example connect with the existing api such as createScript?
For example, completely replace this code with code to make TheSuperClass as well as an inheriting TheSubClass. The following is PlayCanvas compliant code which compiles and runs.
var TheSuperClass= pc.createScript('theSuperClass');
TheSuperClass.prototype.initialize = function() {
};
Iâm not 100% ES5 JavaScript supports inheritance in the same way you would expect in C++ or C#. Thereâs pc.extend that âmergesâ two object prototypes together but not sure if that works with the scriptType system and I donât think it allows you to call the base class functions.
You can check what the pc.createScript call does behind the scenes:
extending the script object with prototype methods and script attributes
registers the new script type to the application script registry
You could create an intermediate class in Typescript that handles the pc.createScript call and extend that class in your code, to keep everything pretty and in one place. Much like in Unity you usually extend the MonoBehaviour class.
@yaustar is right that classes in Javascript are in general syntactic sugar mainly (extending the prototype methods of an object).
Had a quick look and I donât think you be able to do this out of the box with PlayCanvas and ES5.
You could write a new createScript function that creates a new ScriptType and effectively copies the attributes of the âbaseâ class and patches the prototype functions that are or would be overridden.
Edit: This is just me messing around to see what I could do (this is not an official example!) but you get the idea that a function could be written to âextendâ or âinheritâ from a base ScriptType
Thanks @yaustar. That completely answers my original question. Thatâll solve my immediate needs.
Other thingsâŚ
To copy the attributes, doesnât the swap method do that for us? Can some portion of its underlying code be used to âcopy attributes between two arbitrary classesâ to advance your demo project above?
Or as an alternative, if some list or iterator of the attributes was available, a new custom method could loop through those and âaddâ each to the new object. I see such an iterator does not yet exist per this api - https://developer.playcanvas.com/en/api/pc.ScriptAttributes.html
I would like to override methods too. If you/I think of how, a reply below will help the thread.
I wanted to implement inheritance as well and came up with this solution:
1 // BASE CLASS
2 var DialogueBase = pc.createScript('dialogueBase');
3
4 DialogueBase.prototype.show = function() {
5 // Do some generic stuff...
6 this.onShow();
7 }
8
9 DialogueBase.prototype.onShow = function() {
10 console.error('Not implemented');
11 }
12
13 DialogueBase.prototype.hide= function(args) {
14 // Do some generic stuff...
16 }
1 // CHILD CLASS
2 var NavigationDialogue = pc.createScript('navigationDialogue');
3
4 if (!DialogueBase)
5 var DialogueBase = function() {};
6
7 NavigationDialogue.prototype = Object.create(DialogueBase.prototype);
8 NavigationDialogue.prototype.constructor = NavigationDialogue;
9
10 NavigationDialogue.prototype.onShow = function() {
11 // Do some specific stuff that is needed...
12 }
13
14 NavigationDialogue.prototype.hide = function(args) {
15 // Some additional functionality before hide gets called...
16 DialogueBase.prototype.hide.call(this, args);
17 }
The function show() is inherited
The function onShow() is overwritten
The function hide() calls the base and adds some functionality in front
Lines 7-8 are what make the inheritance work. The prototype of the base class gets copied, replaces the prototype of the child class and its constructor gets renamed.
Lines 4-5 would not be needed if not for the editor. The editor tries to interpret each script individually and if it doesnât find the base class object, there is no prototype and it fails -> the script cannot be parsed. To get around that, you could also just put all classes into one file.
Some things I found that need to be kept in mind are:
Should be self explanatory, but loading order of scripts is important. always load base classes before child classes
Attributes are inherited as well, but only as properties. Therefore they cannot be exposed in the editor unless you add them to every child.
It works great for us so far and have not encountered any serious issues.
This is exactly the way to do in ES5 !! Be careful to manage your scripts loading order so your parent class is loaded before your children classes.
It would be nice to have ES6 support in the PC editor, ES6 syntax is closer to C# with extends and super keywordsâŚ
I see comments saying we shouldnât use OOP since PC is entity/component based. Iâm sorry, but OOP is still very useful in this case. And PC did an entity/component system similar to Unity and its MonoBehaviour, but both are not really well designed since you have logic in your component. Sometimes ago, someone write an excellent entity framework Ash - entity-component-system framework where entity are just properties and they are system to handle all logics. Unity did finally the same Entity Component System | Entities | 0.17.0-preview.42 ; but since it requires many classes, obviously it isnât easy with an editor like PC/Unity. My 2 cents
I donât think it would be too difficult to create a ECS with PlayCanvas where the scriptTypes just hold data and handle events from the engine while the systems can hook onto the script system update event.