Mappers' Corner Mappers and Modders

Go Back   Omnip)o(tentS Forums > SERVERS > Mappers' Corner
Thread Tools Display Modes
Old 09-30-2007, 02:33 AM   #1

Optimus_P-Fat's Avatar
Join Date: Jan 2006
Location: New Jersey
Posts: 3,633
UT2k4 UScript tutorials 102: Objects (Classes)
Reply With Quote

This is the second of the super ground up tutorials. Again, I'm going to try to focus on explaining these things as a concept, and not so much as a "this is stuff in UScript" sort of thing. I'll get to how they are used in UScript during some explainations, and in some cases, closer to the end of this tutorial.

Object-Oriented Programming is based on the idea of "objects" that perform specific tasks, and contain all of their own necessary information to do so. It also usually includes a concept called inheritance, which inserts the idea of "child" objects that "inherit" all the properties of their "parent" object, but are even more specialized. This usually is used in a way where the programmer can create a "generic" parent object to do some common work, but create multiple "child" objects, based on that parent, that implement the work in more specific ways, albeit doing the same work in the end.

An object that is self contained will have its own properties, that are maintained and used by it, and relate to it in some manner. In UnrealScript, the definition of an object is called a "class". These are the main building blocks of UnrealScript. Everything in UnrealScript is an object (AKA, a Class). Everything from a weapon, to a vehicle, to a player's character, to the messages that show up on your screen when you get a headshot, are objects. They all perform a specific task that is unique to them. For instance, the message classes will handle drawing a message in a specific color and using a specific font to a specific place on your screen. The most important thing to understand, is that everything is an object. To begin with a recurring example for this tutorial, let's say we are writing some code to do something (it doesn't matter what) with a group of shapes.

The first thing we would do is define a class for our shape object. In UnrealScript, this is done by creating a new .uc file for it. The name of the .uc file is the name you will give to your object. So, if we are making a "shape" object, we would name the file "shape.uc". The first line of the file (if you remember me telling you during the variable tutorial not to worry about it then) is the definition of the class itself. The basic definition of a class looks like such:

class <class name> extends <parent class name> <modifiers>;

The <class name> is the name you will refer to your class by from now on. This is the same name that you give to the file. In our example case, it would be "shape".

The <parent class name> is the name of the class that you will inherit your class from. We will not go over this at the moment, but I will get to it later in this tutorial.

The <modifiers> group is an optional list of keywords that denote special handling of your class. In many cases, you do not need to use these, and as of right now, do not concern yourself with them.

As always, the statement is terminated by a SEMI-COLON.

Now, back out of UScript land for a moment, and back into concept land. Your shape object is going to need some info about itself to use whenever it does whatever stuff you want to do with it. Some examples of info that it may need would be a name, a color (for drawing), and a position on the screen. Since we are working with the simplest of examples here, let's assume we are only concerned with 2d, and the shape only needs x and y position properties.

How do we go about giving our shape class these properties? We declare variables inside the class. These are called member variables of the class. These belong to that class, and are accessed by that class. How do we do this in UnrealScript land? The way that I explained in the Variables tutorial (UScript tutorial 101) thread. In our shape example, shape.uc file would look something like this:

Originally Posted by shape.uc
class shape extends Object;

var color MyColor;
var string MyName;
var int X;
var int Y;
The first line in our file is our declaration of the shape class. In this case we are inheriting from the "Object" class. DO not concern yourself with this yet, I will get to it in a bit. What you should concern yourself with is the next four lines. I declare four member variables of my shape class, for each of the things I named above. If you remember what I went over in the variables tutorial, you will see that their variable TYPEs are color, string, int, int, respectively. (I did not specifically mention color as a type in the tutorial, but if you followed the link I gave to the rest of the common variable types, you would have seen it in there).

Ah, now we have a definition of an object that represents a shape! Wonderful. Now what?

Well, this is only the definition of the object, it isn't an actual OBJECT yet. Think of this the same as you would think of a blueprint for a townhouse. You can't really live in the blueprint, but you can use it to make townhouses that you CAN live in. In code terms, this is called creating an instance of the object. In Unrealscript, this is done in one of two ways, depending on what your class derives from. Do not worry about HOW this is done at the moment, as we are still trying to go over concept. Basically, when you create an instance of a class, you are using the blueprints you wrote (your class definition) to create an actual object in memory on your computer that has that description. You can create as many instances as you want of a class. In my example, I may want to create 10 shapes and do some calculations with them. Using my single piece of code that I wrote for my "shape" class, I can then create 10 object instances that all follow that same setup. I can then go about giving each of those instances different values for their member variables. For example I can name them "shape1" through "shape10". The first instance of my shape class I create, I would assign it's MyName member variable to the value "shape1". I would do this for every instance I make, using a different value for each one. Each instance is just that - a different entity, with all of its own properties and all of its own, personal values.

Okay so this is all wonderful. I have 10 shapes now, with different names, colors, and locations on my screen. Now what can I do with them? Well, not much at the moment. I'm thinking that maybe we want to draw them, right? Okay. We have two options. The first, and most looked down upon in the world of Object Oriented programming, is that we give our shape definition another variable, that contains what KIND of shape it is. Let's do this a horrible way as an example, and add the following line to our class:

Originally Posted by bad code
var string MyShapeType;
Now we can assign that variable a different "shape type" for each instance we make. Maybe for a couple of them, we will assign it the word "triangle", and for others we assign it the word "square".

Why do we make this? Well, we want to know HOW to draw the shape, right? And as you can all guess, drawing a square is a little different than drawing a triangle, right? Well then, we (as bad programmers) are using this variable to determine what the hell we are actually going to do when we need to draw this shape. Our drawing logic would look something like this:

Originally Posted by bad logic
is my MyShapeType variable set to the word "square"?
if so, do some specific work to draw a square
otherwise is my MyShapeType variable set to the word "triangle"?
if so, so some specific work to draw a triangle
otherwise, if it is set to none of these (through some error in my code), panick and report an error to the user.
Obviously you can see one problem with this right off the bat: this leaves us prone to a logic problem. If we forget to ever set the MyShapeType variable to something our drawing logic is looking for, our object will not know what to do when that time comes. So now we introduce the extra complexity on our programmer to make SURE that that variable better always be set to something valid, or else its curtains for your code.

However, there is another problem in this code that is not readily noticed by beginner eyes: that is the fact that every time we have to draw, we need to do a comparison to see what the hell we actually need to do. Now, drawing itself happens very very often. You are now doing this same check, over and over again, even though we know it will ALWAYS evaluate to the same answer. This is actually a big waste of CPU cycles, since your object is not going to change from being a square to being a triangle from one draw to the next. Oh crap, so now we have two problems, we have a potential hole for bugs to creep into, AND we are wasting the CPU with pointless checks. How do we fix this?

The answer comes along again, in the concept of object oriented programming. If everything is an object that performs a specific function, then maybe we should just create two DIFFERENT objects, one for a square and one for a triangle, right? Not so fast. What about all those properties on your shape that are the same for both - color, x, y, and name? Both your square and your triangle need those same exact properties, right? It would be a shame if we had to write all that code again (I know I know, it's not that much to write, given our example, but other objects could contain MANY variables, and it's silly to duplicate all of that). How do we get the best of both worlds here? The answer is in a concept called inheritance.
Optimus_P-Fat is offline  
Old 09-30-2007, 03:01 AM   #2

Optimus_P-Fat's Avatar
Join Date: Jan 2006
Location: New Jersey
Posts: 3,633
Reply With Quote

So how can we create two specific implementations of our drawing logic, one for squares, and one for triangles, without duplicating all of the code in our shape class? This is where inheritance comes in. We can define our two classes, for square and triangle, and have them inherit from our shape class using the extends keyword in the declaration statement. In our example, the "square" class's first line (in its own square.uc file, remember) will look like this:

Originally Posted by square.uc
class square extends shape;
This is telling our program that a "square" will have all of the same properties of a "shape". This gives our "square" its own x, y, color, and name, without you having to add the definitions again. The "square" class can now access those properties as its own. If we inherit our triangle class from shape as well, it will also get those variables for itself.

Now comes the fun part- we can create Drawing logic in each of our child classes that draws the specific way we need to draw for the shape it is, EVERY time. By doing so, we eliminate the need for the MyShapeType variable, because, for instance, the "square" class ALWAYS draws a square. It doesn't HAVE to check what kind of shape it is, because by definition, it is a square. The same goes for our triangle class. I will not go into the specifics of how we create this logic on the child classes yet, I will save that for the next tutorial, which will be on FUNCTIONS. However, by doing this, we will solve not only the problem that we have to ensure that the MyShapeType variable is set to something we know about, but we also remove the need to do a pointless check against that variable, which would never change in the first place, EVERY single time we draw. Yay for us, all the benefits of the shape's common properties, and none of the hassle!

What else does this mean? It means we no longer create instances of the "shape" class - since that is just a "base" for our specific classes, but we create instances of the "triangle" and "square" classes where we need each of them. If I need 2 squares and 3 triangles, I create 2 instances of my "square" class, and 3 instances of my "triangle" class, and NOT 5 instances of my "shape" class. If you are trying to be clever, you may think "hey, but aren't these different object types now? don't we now have to keep track of TWO different types of objects when we draw? THe triangles list and the squares list?" Well, you would be right, if we didn't derive our triangle and square classes from the SAME parent class, in this case, "shape". But, since BOTH our classes extend from the SAME common parent class, we can keep track of all of them in a single list (do not worry about implementation here, but suffice to say, FOR NOW, that all objects that extend from the same class can be treated as that same class). This means, in our ful drawing logic for our program, all we have to do is something like this:

Originally Posted by better code
for each shape instance, tell it to draw itself
Our main drawing logic does not need to care what KIND of shape it is, because our square and triangle would have "Draw" logic that would implement the specific steps necessary to draw themselves. Our program's draw logic would walk through a list of all of the instances of any object that is extended from "shape", and basically tell it "hey, I dont care how you do it, but draw yourself". The objects that are of the type "triangle" would run the code inside the "triangle" class that draws a triangle, and the ones that were of the type "square" would run THEIR code, that would draw a square. The parent object (the "shape" class) AND the outer drawing logic would never need to care about the specifics of the matter, because the child classes take care of it.

I know this is kind of a hard topic to get used to if you've never been exposed to it, and hence I am trying to explain it as a concept as much as I can. To use the "blueprint" example I gave above, think of the "parent" class as the main blueprint of a townhoue. Now, picture photocopying that blueprint for each family that will build that type of house. Each family will then draw their own furniture layout on their own copy of the blueprint. All of the blueprints have much in common - the layout of the rooms, the walls, plumbing, etc, however each of them has specific items placed in ways that are specific to the family who will live in that house - couches, beds, chairs, tables, etc. So while all of the familys are building a "townhouse", the Smiths are building "The Smith's townhouse" and the Joneses are building "the Joneses townhouse." They may be built exactly the same, but maybe the Smiths have painted their house white, and the Joneses have painted their house blue (stated more in code-like terms, the "townhouse" parent class itself has a "color" property, but the "joneses_townhouse" has it set to blue, while the "smiths_townhouse" has it set to white).

I will obviously be explaining more about variables, classes (and instances thereof), and inheritance as I go on in my tutorials. The next one, regarding functions, will show you just how the situation we explained above with shapes would be handled as a script, using inheritance. For now, try to just understand the CONCEPT of an object, and the CONCEPT of "inheriting" a "child" object from a "parent" object, and what that actually means. Also try to make sure you understand the difference between the class definition and an instance of that class.

If anyone has ANY questions or would like some clarification on these concepts, by all means post here.

However, if you feel like bringing up any of the advanced topics that I explicitly stated not to worry about in this tutorial, do NOT post it or I will delete your post from the thread, as this is not the place to be confusing beginners with details such as those. These first few tutorials (i.e. ones denoted with a 100 level number after them!) are all about CONCEPTS, and we will get to the detailed specifics of UnrealScript in later, more advanced tutorials.
Optimus_P-Fat is offline  

Go Back   Omnip)o(tentS Forums > SERVERS > Mappers' Corner

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
UScript Tutorials 201: Advanced Variables (modifiers and arrays) Optimus_P-Fat Mappers' Corner 1 10-04-2007 02:25 PM
UScript tutorials 103: Functions Optimus_P-Fat Mappers' Corner 3 09-30-2007 11:47 PM
UScript Tutorials 101: Variables Optimus_P-Fat Mappers' Corner 3 09-29-2007 02:44 AM
Vehicle classes Gorzakk Onslaught 46 04-09-2007 11:47 AM
Scientists teleport two different objects Mésto Off Topic 9 10-08-2006 11:54 AM

All times are GMT -5. The time now is 12:34 AM.