OOP In Torque Script Resource 2.0 (for T2D 1.0.2 specifically, and possibly TGE and TSE)
by Bryan Edds · 05/08/2005 (12:26 am) · 15 comments
Download Code File
THIS RESOURCE IS DEPRECATED!
Find the new 3.0 version HERE.
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 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.
THIS RESOURCE IS DEPRECATED!
Find the new 3.0 version HERE.
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 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.
#2
05/08/2005 (12:34 am)
BTW, I'd like to hear any suggestions for added features to this resourcee. I am contemplating adding multiple interface inheritance right now. I'm wondering what else you TAP OOP'ers would like to see :)
#3
What an exciting bit of fun :D Stay tuned!
05/09/2005 (12:23 am)
Woohoo! I just finished wrenching the multiple inheritance feature in :D It allows both multiple interface inheritance and multiple implementation inheritance! This will be in the next update, though that will be at least a week away to allow for proper testing of this next functionality.What an exciting bit of fun :D Stay tuned!
#4
It's not the perfect OO design solution (the action system goes a bit overboard and should instead be event-based IMO), but is far better than most new OO designers will come up with. Plus it needs a little reworking in some areas which I may go over here if I have time.
05/11/2005 (2:36 pm)
Just did a search on GG's awesome new search facility, and came up with this great article on OO game design!It's not the perfect OO design solution (the action system goes a bit overboard and should instead be event-based IMO), but is far better than most new OO designers will come up with. Plus it needs a little reworking in some areas which I may go over here if I have time.
#5
Is that a valid syntax? (I'll look into the resource in detail tomorrow, but I was curious about this.)
05/13/2005 (7:38 am)
Bryan, this is indeed a cool resource. Can I do something like this:function class1::foo( %this )
{
}
function class1::bar( %this )
{
}
function class2::bar( %this )
{
}
function testIt()
{
%a = new ScriptObject( class1 );
%b = new ScriptObject( class2 : class1 );
%a.foo();
%a.bar();
%b.foo();
%b.bar();
}Is that a valid syntax? (I'll look into the resource in detail tomorrow, but I was curious about this.)
#6
Of course, the syntax is much different than that, and the base engine class you'll want to use is SimObject, not ScriptObject (though ScriptObject is perfectly fine for backward compatibility) :)
Check out the included tsoo.csl file for an example of exactly what you want to do and more. After that, check out all the template files for making formal class definitions in a snap!
05/13/2005 (12:10 pm)
Yup :)Of course, the syntax is much different than that, and the base engine class you'll want to use is SimObject, not ScriptObject (though ScriptObject is perfectly fine for backward compatibility) :)
Check out the included tsoo.csl file for an example of exactly what you want to do and more. After that, check out all the template files for making formal class definitions in a snap!
#7
05/13/2005 (2:12 pm)
@Bryan: Thanks for the article link. I haven't read the whole thing but it looks interesting.
#8
06/14/2005 (7:41 am)
This is awesome man, thanks... I can't wait until yopu get multi inheritence up, that will make my life SOO much easier.
#9
I'll put the multiple inheritance extensions up as soon as I have a chance now that I know someone who wants it :)
06/15/2005 (5:28 am)
Thanks!I'll put the multiple inheritance extensions up as soon as I have a chance now that I know someone who wants it :)
#10
Great job!
06/16/2005 (1:18 pm)
Excellent! I am also interested in the multi inheritance extension.Great job!
#11
I will post some pattern templates once I get them refined and working in my game.
06/16/2005 (3:25 pm)
Beautiful!I will post some pattern templates once I get them refined and working in my game.
#12
I'll try to have the MI extension up tonight. One thing though - I've only gotten it to work for multiple interface inheritance. Due to some time and complexity constraints, I won't be able to get multiple implemention inheritance working. But it may be for the best anyhow, since there are soooo many issues with even a good multiple implementation inheritance implementation.
06/16/2005 (9:01 pm)
Cool Michael :) I love OO design patterns and advocate them for all OO programmers. Can't wait to see em' ;)I'll try to have the MI extension up tonight. One thing though - I've only gotten it to work for multiple interface inheritance. Due to some time and complexity constraints, I won't be able to get multiple implemention inheritance working. But it may be for the best anyhow, since there are soooo many issues with even a good multiple implementation inheritance implementation.
#13
In the same file on a new line after line 960, insert this code -
[code]
///////////////////////////////////////////////////////////////////////////
// CODE INSERTED BY BRYAN EDDS - OOP In Script
///////////////////////////////////////////////////////////////////////////
Con::executef(this, 2, "onRemove", Con::getIntArg(getId()));
///////////////////////////////////////////////////////////////////////////
// END CODE INSERTED BY BRYAN EDDS - OOP In Script
///////////////////////////////////////////////////////////////////////////
I put it in there but it didn't have the right C++ syntax, what is the line before the one you insert?
06/28/2005 (9:22 am)
In the tutorial where it says :In the same file on a new line after line 960, insert this code -
[code]
///////////////////////////////////////////////////////////////////////////
// CODE INSERTED BY BRYAN EDDS - OOP In Script
///////////////////////////////////////////////////////////////////////////
Con::executef(this, 2, "onRemove", Con::getIntArg(getId()));
///////////////////////////////////////////////////////////////////////////
// END CODE INSERTED BY BRYAN EDDS - OOP In Script
///////////////////////////////////////////////////////////////////////////
I put it in there but it didn't have the right C++ syntax, what is the line before the one you insert?
#14
07/10/2005 (8:55 am)
I'm updating the resource to implement mutiple interface inheritance. Go ahead and apply that one instead - it should be done in about an hour. I'll post up a link here when it's done. 
Associate Ron Yacketta
will have to give this a test drive some time
-Ron