On Torque

As I promised earlier I will now rant about the Torque Game Engine.

I would like to preface this by saying that I have not gotten to use the latest version of Torque, and i will refer to version 1.4, roughly speaking. Maybe Garage Games has made sweeping changes and fixed all the problems I'm about to complain about, maybe not. For their sake, I hope so, because I was not impressed by what I saw.

Torque is a complete game engine package, sold to game producers to decrease the amount of work they have to do to bring a game to market. It provides 3D rendering, physics simulation, Handles character animation, vehicles, and provides a scripting language for game logic. It seems to be targeted at the low cost segment of the industry, and is as far as I know the cheapest for-money game engine available.

On Torquescript

It sounds nice, but many of it's features are enough to drive sane men mad. Lets talk about Torquescript. What is Torquescript? To call it weakly typed isn't a strong enough statement. It doesn't really have any implicit conversion, or any sort of type safety for the simple reason that there is only one type: string. Does it have pointers? Sure, there just integers, stored as strings. Arrays? Those can be stored by concatenating strings with spaces as separators! Or, you can use Torque's array/dictionary notation:

foo[0] = "fish";
foo[ham] = "cow";

Seems fine right? Well it works okay, except that, unlike how it may appear, foo will contain neither "fish" nor "cow"; indeed the variable foo may not even exist. You see, Torquescript implements arrays/dictionaries very simply, by expanding foo[bar] = flop into foo_bar = flop. That's right; unless you read the documentation (such as it is) very closely, you might think you were doing something, somehow, to the foo variable. Nope! You just silently created the foo_bar variable instead. That means that what you thought was a single object, containing items, or perhaps key/value pairs, is actually a cloud of variables that are totally unaware of each other. It's odd, to say the least. Also means that there's no way to get a complete list of what's in one of your 'arrays' or 'dictionaries', since the foo object hasn't a clue about the rest of those objects whose names begin with 'foo'.

Another great thing about Torquescript is the way the slogan that one of my teammates invented for it: "When in doubt, zero it out!" You see, there's also no need to declare variables in Torquescript, as the come into existence when used. But not just when they're assigned to, but for any other operation as well. This leads to great bugs like:

foo = 5;
if( fo == 5 )
    bar();

'bar()' will of course never get called, because fo will be initialized with the default value of 0. And there won't be any errors or warnings, because the code is entirely correct Torquescript. The writer obviously intended to assign 5 to foo, create the variable fo, check if fo is 5, and only call bar() if it is. This happened to me a lot, and, yes, it is my fault for typing the wrong code, but it's such an easy and common mistake to make, and one that depends on a language feature that serves no purpose that I see. Why not only allow instantiation on assignment. Sure, there'll be more error messages and crashed scripts, but that's good, right? After all, those scripts were wrong, and nobody I know would want to ship a game that contains code that doesn't work.

On the Torque-Blender exporter

My 3D modeling and animation tool of choice is Blender. It's free, not too hard to use with practice, and does far more than I'll ever really be able to use. So, I was happy to learn that we could generate content in Blender to put into a game built with Torque. Unfortunately, the export itself introduces more maddening difficulty. IT's hard to pin down, because the main problem is inconsistency. Sometimes when exporting the textures are not detected, and won't show up in the exporter's 'Materials' list. Sometimes they show up in Blender and in the exporter, but don't display in Torque. Occasionally I have accidentally created objects which are textures with shiny environment mappings of the sky when displayed in Torque. To this day i've no idea how I did it, nor can I deliberately reproduce it.

On Torque and the STL

Torque has built into it it's own memory allocation system and profiler, which if I understand correctly, are related. The only trouble is that some part of this renders Torque's C++ code incompatible with the C++ Standard Template Library. This means no vector, map, or set, etc. Not to worry, Torque has its own, built in data structure classes! Except that, they aren't very trustworthy. You'd think that you would want you data structures library to be a solid foundation on which to build the rest of your code, no? After a bit of fighting with the built in Vector class, I decided to just stay away. You see, the back() method of the Vector class is broken, such that it always points one item beyond the end of the contents, unless the pop_back() method has been called at least once. I couldn't, with a quick look at the code, figure out how it's broken, but it that doesn't work, I'm loath to trust any of the rest either.

On Random Broken Things

The worst problem of all, as I see it, is an umbrella problem: Torque is literally sprinkled with features that just don't work, and while each is relatively easy to fix the whole mess is daunting. A few examples:

One feature, which my team discovered purely by reading error messages in the log files, is that Torque supports four stated buttons. If you create a button in the user interface which displays thing.jpg as its image, then Torque is supposed to automatically look for thing_h.jpg, thing_d.jpg, and thing_i.jpg to be the hover, down, and inactive states of the button respectively. I was tasked with making the buttons in or game use all four states. What I discovered was that the code for searching for alternate button states was fatally flawed. You see, it didn't actually look for names like thing_h.jpg, but rather thing.jpg_h. There were two alternatives: Fix the C++ to append the suffixes correctly, or use files with suffixes after the extensions. The first way is better, I think, and the second way turned out to but but a mirage anyway. I tried the second method first, because it was quick and I was curious. When I did, the images still didn't display. It turns out that this avenue was blocked because after Torque located the images and read in the data, the only way it has to determine how to decode it is to examine the extension of the filename it came from, and "jpg_h" is not a recognized extension. I ended up replacing the C++ code that searches for the alternate images. It was easy, but the whole thing wasted half an hour, just to repair a feature that was supposed to already be in place.

Another problem that we encountered, the day before our final demo, was a beautiful example: We wanted to display a message to alert players that their turn had begun. The message should be a large, noticeable image, displayed in front for the player's view, and it should automatically disappear after a period of time so as not to get in the way. This sounded like a job for the guiFadeinBitmapCtrl. I made the image to be displayed and and handed it off to Ralph, as he knew exactly where in our code to trigger its appearance. After a few minutes it was in. It showed up, lingered for a few seconds. . then faded to solid black before disappearing suddenly. Ralph said something to the effect of of "Oh, yeah, that's why I didn't use the fade in control for the 'click to pick up item' button." We decided, however, to try to fix the problem, rather than giving up. Digging into the code made it quickly obvious why this was happening. In its render method, the first thing guiFadeinBitmapCtrl did was to ask its parent class, GuiBitmapCtrl to render, drawing the assigned image. Then, if the fadeout was supposed to be occurring, it would compute the inverse of the appropriate alpha value, and draw a black rectangle filling itself. Simple, to the point, and utter not what it should have been doing. Since I've only used OpenGL a little, it took me 5 minutes to look up the correct method for fading the rendered image's alpha on google. In that same time, Ralph, who had more OpenGL experience than I, had coded up the solution, on the hunch that it was the right one, as I was able to confirm. Again, a simple fix to a problem that there seems to be no way for the original developers to have missed.

We encountered other issues like these, but these seemed outstanding. I can imagine no way that the Garage Games people didn't notice what they'd done. Especially in the latter case, it must surely have been painfully obvious to the programmer that the solution being coded wouldn't solve the problem as called for. So why did they do it? Did they think that no one, none of the customers they were selling this to? Really, my gut feeling is that the version of Torque we used was like an unfinished product, that just wasn't ready to be shown to anyone. If I were the owner of such a thing, I would be proud of what I'd accomplished, but would say, with a component of embarrassment, that there was a lot of cleaning up to do before I could really show it to anyone else in detail.

To wrap up, unless a lot has been changed in newer versions of Torque, I can only say that I wouldn't recommend it to anybody. Following from this, if these problems have in fact been addressed, then Garage Games is making a huge mistake by allowing out of date version of their product shape developers opinions of their work, because it is not going to help them get customers, but quite the reverse.

No Comments

Comment on this post