Introduction to Object Oriented Programming with TorqueScript

When the concept of programming a computer to accomplish tasks first became firmly established, the primary strategy used was to actively control the order in which things occurred within your program—line by line, the programmer would write code that directed every single operation in a strict order, and there was no real concept of distinct groups of functionality that were associated in some way—the program simply ran line by line, with a single “controller”—the program author.

As programming evolved, it become apparent that there was great benefit in having the ability to group things that were happening in the program with some form of logical association—for example, it became apparent that certain sections of a program were written to accomplish tasks on a certain set of data, and those tasks were very specific to the data itself. For example, a program might need to track information about people within a “room”, and the actions that could happen between the room and the people themselves—people could enter a room, they could leave the room, and there could be a need to count the number of people within the room. This type of association between data and tasks lead to a concept called “objects”—the room (and the people within the room) could be programmed so that they could interact: a person would enter a room, and the room object’s data would automatically be updated to indicate that the person was now “in” the room.

This type of programming style has great advantages—just one includes the concept of “code re-use”. If we apply theoretical design principles to our “room object”, we realize that in fact the room is simply a container—it can hold objects, objects can be placed in the container and removed from the container, and we can count the number of objects within the container at any one time. With this abstract definition of a “container object”, we can write code that is generic, and can be used over and over again for any type of object that has the properties of a container—a backpack, a room, members of a party within our game, and many other examples. In the “old school” manner of programming, we would have to write new (and unique) code for every single situation in our program where a container was needed, but with this new way of looking at programming, we could simply write one set of code that handled all situations where the ability to be a container was needed. This set of code is called a class.

The Concept of Classes

A Class is defined as a set of code that manages a specific set of data, and allows this data to be accessed and manipulated in a specific manner. Classes are written once, and can be used many times by a process called instantiation. Since the class is written to be generic (not limited to a unique program or area within a program), when we need to have the abilities of a particular class, we can simply instantiate an object that is based upon this class—giving that object the properties of the underlying class. In Torque, classes are written in C++, and there are hundreds of minor and major classes that we can use for our programming needs. Some classes are very basic—in Torque, we have classes such as SimSet, which handle the needs of basic containers, all the way up to complex classes such as Player, or t2dAnimatedSprite, which have complex and detailed data and actions that can be accomplished with that data.

We can use a class many times simply by creating a new object from a class, via the process of instantiation. TorqueScript provides the new command that interacts with C++, and instantiates a unique object with the properties and capabilities of the assigned class, allowing us to easily use complex and intricate programming without having to write the code ourselves—a major benefit!

Classes vs. Objects

A fundamentally important thing to understand is that when we create a new object, we aren’t creating a new class—we are simply instantiating an underlying class that has been written for us already. There may be dozens or even hundreds of instantiations of the exact same class within our game, but each of them may use the same code written as part of the class they are instantiated from—and each of the objects can contain different data. We may have two objects instantiated from the class t2dStaticSprite, but each of the objects may have different images, different positions, and different physics characteristics, yet they all use the same code.

Using Objects and the Data They Contain

We mentioned that objects not only have data, but tasks that you can perform on that data, but how exactly do we accomplish those tasks? As part of the programming of a new class, the programmer will define and implement sections of code called methods, which are designed to perform logical operations on a set of data. Some methods may be very basic, such as allowing the game programmer to check the position of an object within the game world, to complex calculations that may report back how many other objects are currently colliding with our object, and where those collisions are occurring.

One of the major benefits of class methods is that the class developer can restrict what the “end user” can do to the data within an object, which helps to ensure that the object behaves the way the developer intended. It doesn’t make much sense to allow a game developer to directly modify the “number of people within a room” without actually adding or removing people within the room, and classes “protect” our data by, in this particular example, making the count of number of objects within our container only able to be read, instead of both read and written to, by the end user. This way, we make sure that our container acts appropriately—you can’t directly force the container to show zero objects in the room without actually removing all of the objects themselves.

Methods can be considered as ways to either ask questions about an object, or request that actions be performed on an object. You can’t directly force things to happen with any particular object (other than what the class developer allows), but you can interact with objects through their methods to accomplish tasks.

Inheritance, or “Who’s my Daddy?”

Another powerful benefit of Object Oriented Programming is the ability to have classes reference other classes when they are implemented, in a technique called inheritance. This effectively means that a class can be implemented as a “super-set” of another class—gaining both the data and functions of the original class (called the Parent class), and also add additional data and capability to the new class.

For example, we might want to implement a “Vehicle” class, with not only the ability to move forward and backwards, but also the ability to have passengers. We’ve already described the concept of a container, and since our Vehicle class needs to have the ability to “contain” passengers that makes sense, but we don’t want to force all containers to have the ability to move forwards and backwards, so we can make a new class called Vehicle, and use the Container class as our “parent”—gaining both the abilities of the container itself, as well as any abilities we might add to our Vehicle class. This capability of Object Oriented Programming is very powerful, and used extensively in our Torque engines.

OOP Summary

What we’ve covered barely touches the surface of the principles of Object Oriented Programming, but points out several key points that are important to working with Torque. There are literally hundreds of additional subtleties and benefits of using Object Oriented Programming practices, and many of them will be important to understand as you continue to work with Torque and TorqueScript, but understanding the fundamental characteristics is important to successful TorqueScript development.