Game Development Community

OOP In Torque Script 3.0 (for T2D 1.0.2 specifically, and probably TGE and TSE)

by Bryan Edds · 07/24/2005 (3:17 pm) · 36 comments

Download Code File

Included in the attached .zip is the instructions for applying this resource to your project. Follow the instructions in the OOInTorqueScriptInstructions.txt file to apply the resource to the engine.

After applying the resource, it is critical that you read and study the other files that are included in the .zip file. The first one to study is the tsoo.csl file. This is a script file that can be executed from the console which shows and explains many of the features of OO in Torque script in an example. You should read that file first. The remaining files are EXTREMELY USEFUL. They are different types of class templates that allow you to do a couple of "search and replaces" to create your own class files. Using these are not only instructive, but will also save you lots of time :)

New notes in the 3.0 version -

Mutliple inheritance - In this resource, you are allowed to inherit an unlimited amount of classes into any subclass or datablock. This makes the language very much like C++.

Using Multiple Inheritance - Using multiple inheritance is pretty easy. Simply put a SPC between each class your'e inheriting from. For example, assume ConcreteClass is a concrete class and InterfaceClassA and InterfaceClassB are both interface classes (and ALL of them use SimObject as their engine base). To inherit them into a class called ConcreteSubClass, do like so -

// class
   link( SubClass, 
         ConcreteClass1 SPC ConcreteClass2 SPC InterfaceClass,
         SimObject);

The first class in the inheritance list will become the Parent class, and is referred to by the Parent:: scope resolver. If you inherit other classes whose methods are named differently than the methods of the first class, they too will be referred to by the Parent:: scope resolver. But, if you inherit two classes which have functions of the same name (say, they both have a protInit function), then you refer to the first class in the inheritance list by Parent::protInit and the second class by it's actual name (in the above case, it'd be ConcreteClass2::protInit. If you need to call both in a function, you simply call them in order like this -
function SubClass::protInit(%this)
{
   Parent::protInit(%this);
   ConcreteClass2::protInit(%this);

   /// some code...
}
If you only need to call one of them, just leave out the call to the one you don't need like this -
function SubClass::someFunc(%this);
{
   Parent::someFunc(%this);

   /// some code
}

Old notes from the 2.0 version -

SimObject is now the main engine base class - In this resource, the main engine base class to derive from to create a new script base class is SimObject, not ScriptObject. You can still use ScriptObject instead of SimObject, but it's quite unnecessary and rather confusing at best (for an explanation of the difference between engine base classes and script base classes, see the included tsoo.csl file).

Cast function - Have a bad design you don't have time to refactor into a good one? Is the engine losing type information (like in onCollision) giving you parameter objects whose actual type is unknown? Use this super-cool cast function to make sure the object you have is of a certain class type or derived from a certain class. It's basically the Torque Script version of C++'s dynamic_cast, but it's not slow like C++ version. Use it all you want without worrying about performance (but use this facility only when you have to since down-casting is the sign of bad OO design).

Override xxx::onRemove(), NOT xxx::delete() - I have made it so SimObjects (the object from which ALL objects in script derive) makes the proper call to xxx::onRemove() when an instance is deleted. So when you need to execute some code when your object is deleted, make sure to override the class's ::onRemove() function, NOT the ::delete() function.

Singletons use reference counting for garbage collection - In this singleton template's implementation, singletons are created when they are first referenced, and deleted when all the objects referring to them unregister their references to the singleton.

Old notes from the 1.0 version -

Initially, all script inheritance functionality was put into the ScriptObject, and unfortunately, it only allowed one layer of inheritance. While it was handy for very specialized tasks, I could not help but wonder what I could do with it. Harold and I discussed the current capabilities, and he quickly saw that with just the smallest bit of tinkering, multi-layered inheritance was possible. So, like the insane genius he is, he went in, did a bit of C++ coding, and made multi-layered inheritance work... well, almost. Unfortunately, there was another task that remained which would be needed to be done in order to help the ConsoleEval object find the methods of multi-layered inheritance when the method was not defined at all levels of inheritance. So with a bit of direction from Ben, I went into ConsoleEval, and updated it to handle the new capabilites in just a couple hours. No problem.

And I figured I might just stop there... but my curiousity drove me forward. I asked myself, "Why can't I put this feature into ALL objects that can be accessed in script?" So I tried it a couple different ways, and found one that worked expertly! I just moved all the inheritance functionality implemented in ScriptObject backwards into SimObject. Good stuff.

So, with the code extension considered by themselves, the only thing you got here is some fixed inheritance features that Torque was probably meant to have in the first place. The great thing about this is that you can use these features only if you want to - if you're not a big fan of inheritance, you just ignore it. Problem solved. It just all depends on what you want to do and how you do it. For OO maniacs like me, it's better to have the feature available than not, so long as it doesn't get in anyone else's way. Which brings up another good thing, this code extension is %100 backwards compatible with all your old script code. All you have to do is copy the zipped "engine" folder into you Torque directory, do a rebuild, and you're done.

So, that, in a nutshell, is what has been done in the extension. But I told you that story so I could tell you this one -

When I had arrived seriously on the Torque scene after developing some GUI stuff on the Q game engine, I took a very hard look at what capabilities Torque script offered its programmers. Although I did not, at the time, know that inheritance allowed only one layer, I knew that with a bit of methdological standardization, a form of object-oriented programming in script was possible. This all, of course, is before I met Harold. So, I pounded out the necessary disciplines that I thought would be a great way to achieve OO in script. Only after that, I had someone explain to me that Torque's implementation of scripting inheritance, while it would not stop me from using this methodology, would severely limit how useful the methodology would be. And that's when I met Harold... and ya'll know the rest :)

So download the zip, follow the readme.txt file, and take a look at the sample tsoo.cs file to see the new OO methodology in use. I've tried to include all the explanation I could, but if anyone has anyone questions, feel free to contact me here, or even privately. I'll be happy to answer any questions or concerns as to the hows, whys, or wtfs :D

Also, I've tested this code quite a bit, BUT, that does not mean it will work for you. Since this code has only been narrowly tested, it is highly advised that make sure to read and follow the code rollback instructions in case you encounter a big problem with the code. I cannot guarantee any amount of success with this since I haven't tested it out on your personal machine with your personal project :D

Thanks again to Harold for the help - it was his initial code example that springboarded this entire project. Thanks also to Ben, definitely for the encouragement to do it my way and go allll the way with it. And BIG thanks to the community for all the help for getting my newbie-arse up to speed on the inner workings of Torque.

Final Note: If anyone has any problems or I have gotten any line numbers wrong, please don't hesitate to tell me by e-mailing me at the e-mail address specified in my profile.

Good luck, and thanks for using object-oriented programming in Torque Script!
Page«First 1 2 Next»
#21
09/18/2005 (8:49 pm)
Vincent, I believe you misunderstood what I said. Classes can have all the data members you want, and those data members are inherited just fine. I was not talking about classes, but rather *interfaces*. Interfaces are a *special* type of class that has no implementation. The purpose of an interface is to provide a class that has no implementation. Interfaces simply set up a standard collection of message passers (function signatures) that concrete classes (those classes with implementation) can inherit from in order to make those concrete classes compatible with other classes that communicate to objects derived from that interface.

...

It's complicated to explain. If you don't understand interfaces, then it really doesn't matter anyway because you won't be using them. Just use regular classes and you'll be using full inheritance in no time - inheriting data members and all.

Bottom line is that you do not need to be concerned with interfaces at this point. Classes allow inheritance of data members, and that's what you'll be using. Trust me, it does everything you expect it to do. The default behavior inherits functions and members so long as you're not using interface classes, but regular classes instead.

Final Note: If you want to learn more about the difference between interfaces and regular (AKA concrete) classes, I suggest the great book "Design Patterns Explained". There is no better introduction to OOP in the world IMO.
#22
09/19/2005 (2:47 pm)
Bryan, thank you for the enlightenment. Interface classes certainly sound like an interesting idea. I do still have a question on how the OOP aspects work in the script, so far I have not been able to find the info I'm looking for. In any case, I will start it in a new thread.
#23
10/09/2005 (9:05 pm)
I am rating this 5- xtremely useful; I haven't even compiled and played with it yet, but it's very existence explains some things I was rather confused about and not working correctly in torquescript. Thanks Bryan!
#24
10/09/2005 (9:57 pm)
Going forward is this going to remain a separate resource, or any indication that core Torquescript is going to include these feautures?
Quote:In addition, it looks to me like some of the original inheritance functionality in TGE was stripped out of T2D - this adds that functionality back in.
What is that removed functionality in reference to, specifically?


The best thing about this resource is the extensive examples and code comments.

One area for improvement would be to explain exactly what shortcomings it overcomes with out-of-the-box torquescript. [edit: and really how O-O, inheritance, constructors, etc. works in out-of-the-box torquescript)
#25
10/09/2005 (11:15 pm)
Thank you Alex.

I don't see GG adding this into the HEAD without a very large base of community support. And even then it may not happen. I've talked with Ben Garney, but there's been no promising words there. For some reason, there's a lot of community resistance to this resource. I guess it's like old C programmer resenting going to C++ (even if all the new features are optional and can be completely ignored).

So, it could maybe happen I guess... but I wish a lot of luck to any person who tries to get it done >:)
#26
10/10/2005 (10:05 am)
@Bryan, I am reading each of the 200+ search hits on garagegames.com about ScriptObject, in an attempt to grok how it works (or doesn't work) in Torque core.

It may be wimpy, but I don't want to import another C++ resource if I can avoid it. Do you have any useful posts from labrat or anyone else bookmarked that you can recommend to me?

question about this resource: Other than enabling multiple-inheritance and "interfaces", what does this resource add or fix as compared with stock T2D and stock TGE?
#27
10/11/2005 (6:00 am)
Alex, I changed this resource a little to include some of the information you're looking for. Looks at the Old notes from version 1.0 section on this page. It explains the shortcomings of the original language and how this resource came about to resolve this problem.
#28
12/30/2005 (7:19 pm)
Has this resource been tested with TGE 1.4 / T2D 1.1 alpha2? I applied it to T2D 1.1 alpha1 (TGE 1.3 based I believe) and was experiencing crashes -- not sure if they're just bugs associated with poor Mac support, or if they're signs of problems with this patch...
#29
12/31/2005 (2:30 am)
There should be no reason for this pach to crash in T2D 1.1 A 1 other than bad application of the patch. It might help to roll back and try reapplying. If that doesn't work, zip up and send me your copy of T2D C++ source and I'll find the problems personally.

Thanks!
#30
01/03/2006 (3:39 pm)
Bryan, the problems with 1.1A1 might have been unrelated -- there seem to be other people having the same kinds of crashes and they haven't fessed up to using the OO TorqueScript patch... :)

I'm not inclined to put a lot of effort into getting 1.1A1 working, given that it's a dead-end... I'd be happy to work with you on 1.1A2 though, if you're interested?
#31
01/03/2006 (3:41 pm)
Sure. Just let me know via my e-mail addy in my profile :)
#32
02/07/2006 (8:44 pm)
Has anyone had any luck getting this to work with T2D 1.1ALPHA4?
#33
05/31/2006 (8:45 pm)
Could you possibly update this for the new Beta 4 build? The code has changed quite a bit, and I would really like to implement this resource.
Thanks =)
#34
05/31/2006 (11:04 pm)
Hmm... I guess I really need to update it. I'll try to make time for it in the next week. I'm really busy right now with other stuff, so it will probably take at least a couple days to get around to it.
#35
03/23/2007 (3:26 am)
Could you update this code for TGB v1.1.3 ? I think use this great resource in Torque.
#36
07/06/2007 (4:49 am)
This is a great resource but its near impossible to add it to current versions of Torque and/or TGB because line numbers are all off and you provide too little context to make it possible to find the right location.
An example:
....
In engine/console/compiledEval.cc on line 1047, replace this code -
if(ns)
                  nsEntry = ns->lookup(fnName);
               else
                  nsEntry = NULL;
with this code - ....

There are two occurences of this code in the file (about 5 lines away from each other) and it's near impossible to me to determine which one to replace.

Couldn't you simply supply a unified diff file (which you can create with any standard diff tool available)?
Unified diffs usually add a few lines of context around all code changes so it would be a lot easier to figure it out and one could maybe even use the patch tool to apply your resource automatically.

This would otherwise qualify as an extremely useful resource and Im sorry that I can only give it a useful rating because of the aforementioned problems.
Page«First 1 2 Next»