Mappers' Corner Mappers and Modders |
|
![]() |
|
Thread Tools | Display Modes |
![]() |
#1 | |||
Insider
![]() ![]() Join Date: Jan 2006
Location: New Jersey
Posts: 3,633
|
![]() 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: Quote:
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: Quote:
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: Quote:
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. |
|||
![]() |
![]() |
#2 | ||
Insider
![]() ![]() Join Date: Jan 2006
Location: New Jersey
Posts: 3,633
|
![]() 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:
Quote:
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: Quote:
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. |
||
![]() |
![]() |
||||||
|
Thread Tools | |
Display Modes | |
|
|
![]() |
||||
Thread | Thread Starter | Forum | Replies | Last Post |
UScript Tutorials 201: Advanced Variables (modifiers and arrays) | Optimus_P-Fat | Mappers' Corner | 1 | 10-04-2007 03:25 PM |
UScript tutorials 103: Functions | Optimus_P-Fat | Mappers' Corner | 3 | 10-01-2007 12:47 AM |
UScript Tutorials 101: Variables | Optimus_P-Fat | Mappers' Corner | 3 | 09-29-2007 03:44 AM |
Vehicle classes | Gorzakk | Onslaught | 46 | 04-09-2007 12:47 PM |
Scientists teleport two different objects | Mésto | Off Topic | 9 | 10-08-2006 12:54 PM |