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.
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!
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.
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.
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.