Unreal Script
by Windex
Introduction
| So, I'm
guessing the first question floating through your mind would
be, What the hell is UnrealScript? Well, UnrealScript
is the mini programming language that Unreal mods are written
in. If you've had experience coding with C++ or JavaScript,
you'll probably catch on quickly. UnrealScript syntax is
almost identical to JavaScript, so JavaScript books and
tutorials are good resources for learning your UnrealScript
vocabulary.
If you've never written a line of code in your life, though, don't give up. Everyone has to start somewhere, and UnrealScript is as good a place as any. I've tried to make this tutorial as simple and basic as possible, so it can be understood by just about anyone. Like anything else, UnrealScript takes practice to become good at, but that doesn't mean it can't be fun along the way. |
| There are two
methods for writing UnrealScript. The first, and simplest, is
to use UnrealEd, which comes fully featured with everything
you'll need to get started in UScript. The second method
involves writing code in plain text .uc files, and compiling
them using Unreal -make. This is usually the preferred method
for most experienced UScripters, because it gets rid of
complications and bugginess caused by UnrealEd. It also allows
for easier mixing and matching of new models. Information on
how to use this method is contained in the Using
Unreal -make tutorial. If you're just starting out,
though, I would have to recommend that you stick to UnrealEd
for now. As a result, this is the method I'll talk about most
during this tutorial. If you've never run UnrealEd before,
you'll need to grab a couple of bug fixes to make sure it
works properly. Download and install the Visual
Basic 5.0 Runtime, and the RichText
Control Update, and you should be set.
Alright. It's time to start your career in UnrealScript. Open up UnrealEd, and take a look around. The first thing you'll probably notice are the grided viewports in the center. These are meant for level design and you won't be using them for writing UnrealScript. Now take a look on the right. This is the browser window. By default, it displays textures for level design, but this isn't what you want. Click on the "Browse" pull-down menu, and select "Classes". This will bring up the class tree. |
| You may have
heard the term "Object Oriented Programming" before. C++,
Java, JavaScript, and UnrealScript are all object-oriented
languages. OOP is a fairly new concept, and it's one that can
make the task of programming quite a bit easier. Especially
when you're writing code for an FPS, where it's easy to think
of things as actual "objects" in the game. Everything you see
and interact with in Unreal (as well as quite a few things you
can't see) is an object. Your eightball gun is an
object. The rockets and grenades it fires are objects. The
unfortunate krall at the other end of these rockets and
grenades is an object. All of these things are controlled by
written code, which is contained in a class. So,
there's the answer to that question. A class is simply a
collection of code which is used to control some object in the
game. Each object has its own class.
A popular analogy is to think of a class as a mold that is used to create objects in the game. You might have more than one skaarj in a game at the same time, but that doesn't mean that these skaarj are identical. One of them could be patrolling peacefully at its post, and the other might be fighting for its life against a blood-crazed player with an attitude and a big gun. They are both created from the same class, or "mold", but they are controlled separately. In case you're new to 3D game development, there's something I should probably explain at this point. I've said an object is something in the game that can (usually) be seen and interacted with. What you "see" however is not dictated by the code you write for it. What you see is a 3D model which is created in a separate program entirely, such as 3D Studio Max or Lightwave. The code you write controls what the object does. A model without code will just sit there and do nothing in the game. Code makes your eightball fire when you click the mouse button, makes the rocket appear in front of you, and makes it speed off to explode between your enemy's eyes. |
| Now that you
have some concept of what a class is, it's time to look at
them in a little more depth. Go back to to the class browser
in UnrealEd, and look it over a bit. Classes in Unreal are
arranged in a hierarchy, with the "Actor" class at the
top. Actually, Actor is not the highest class, but it's as
high as you'll need to go for now. Just so you know, "Object"
is at the true top of the tree, and it can be displayed in the
class browser by deselecting the Only show actor
classes box.
The idea behind having the classes arranged in a hierarchy is that each class will inherit code from the classes above it. Code that will be used for every class in the game is put in the top-most class, so it will be inherited by all the classes below it. This is very useful, since it means that you don't have to re-invent the wheel for each new class you create. If you want to create a new weapon, for instance, you can simply expand upon the existing Unreal weapon class, and add only the functionality that is specific to your weapon, instead of unnecessarily re-writing code that is already written in the base weapon class. Now, click on the little minus sign by the word "Inventory" to display its child classes. After that, expand "Weapon", and look at what appears. All the Unreal weapons are child classes of Weapon, which is a child class of Inventory, which is a child class of Actor. There is quite a bit of code in Inventory and Weapon which controls the basics of how a weapon should act, but the specific code that controls how each individual weapon works is contained in that weapon's class. To get your first look at UnrealScript in all its glory, double-click on the FlakCannon class. A window with a dark blue background will appear, containing all the code for the FlakCannon. If you've written C++ or JavaScript before, you'll probably recognize quite a bit of the syntax. If you're new to programming, though, don't panic. Code may look complicated at first, but once you break it down, it's really very simple. Code in UnealEd is color coded, as you've probably noticed already. Comments (text which is ignored by the compiler, and used to explain and document your code) are bright green, keywords are aqua blue, labels are yellow, exec commands are gray, and everything else is white. The first line of aqua blue and white when you first open the class is called the class declaration. Under this are the gray exec commands. These are used to import the models, sounds, and textures used by the class, and can be ignored for now. Scroll down till you get to some more colorful code. This code contains the variables, functions, and states of the class, and is what actually controls what the FlakCannon does. |
| The class
declaration is a line of code in a class which states the name
of the class, and its parent class. The class declaration for
the FlakCannon looks like this:
Not too difficult, is it? All it consists of is the word "class", followed by the name of the class, then the word "expands" followed by the name of the parent class and a semicolon. The semicolon is just a way of telling the compiler that the statement is finished. Just about everything you write in UnrealScript will need a semicolon at the end, so get used to it. Now, when writing code in UnrealEd, you won't have to worry about the class declaration much, since UnrealEd will automatically generate this line of code when you create a new class. However, if you write code in text-based .uc files outside of UnrealEd, you will need to write the class declaration manually. |
| If you've ever
done any programming before, I'm sure you have a firm concept
of what a variable is, and what they're used for. If this is
the case, you should probably skip down to the "Types of
Variables" section below. If the question What the hell is
a variable? is floating around in the back of your mind
(or the front of it, for that matter), though, you'll want to
keep reading.
Technically speaking, a variable is a location in your computer's memory that stores a piece of information. This information can be of many different types, such as numbers or words. Variables come in handy all the time while writing code. For example, let's say you're making a new weapon, and you want it to charge up in alt-fire. To accomplish this, you could use a variable. When the player presses alt-fire, have Unreal add to this variable. Then, when the player presses fire, have Unreal fire a projectile that does a varying amount of damage according to the value that was stored in your charge variable. Damn, I didn't do a very good job explaining that, did I? Well, hopefully you're able to grasp the concept of variables without much help from me. I've found that most people don't have much trouble with it. It's just one of those things that naturally makes sense. |
| If you've done
any programming in BASIC, or a similar language, you've
probably become accustomed to using variables a certain way.
Namely, not having to declare them. Declare them, you
ask? Yes, declare them. Variables in UnrealScript, just as in
C++, Java, and JavaScript, must be declared before you
can use them. Basically, you have to let Unreal know that you
are going to use a new variable. The basic variable
declaration syntax in UnrealScript looks like this:
Pretty straight-forward. First comes the keyword "var", then the type of variable you are declaring, and finally the name of the variable. Variables must be declared at the beginning of a class, after the class declaration and exec commands, but before any functions. There are many different types of variables, ranging from numbers, to letters and words, to "true" or "false" values. The types available in UnrealScript are as follows:
|
| If you've ever
done any programming before, you're almost sure to be familiar
with the If/Then/Else statement. They exist in UnrealScript as
well, although the syntax might be slightly different than
what you're used to if you program in a BASIC language. If
you've never programmed before, then allow me to explain. A
conditional is a way of having Unreal perform certain
operations only if a certain condition is met. For instance,
do one thing if a bool is true, and do something else if it's
false. Conditionals are key to accomplishing all sorts of
things in any programming language, and UnrealScript is no
exception. The basic syntax for a conditional in UnrealScript
is:
First, Unreal checks to see if the first condition is true by comparing expression1 to expression2 using the operator. If that condition checks out, then the first set of commands are executed, and the conditional is finished. If the first condition isn't true, though, Unreal will check the second condition, and if it's true, it'll execute the second set of commands. If it goes through all the conditions, and none of them are true, it will execute the "else" set of commands. When writing a conditional, you don't have to have else if's and else's. They're just available should you need to be more specific with what you want Unreal to do. All you have to have when writing a conditional is the first "if" statement. There are many different operators that can be used in conditionals, as you can see in this table:
Not every operator will work with every variable type. For instance, you can't really say that one actor reference is "greater than" another actor reference, so the four greater than/less than operators aren't applicable to actor references. Just use common sense to determine what will work with what, and you should be just fine.
Note the way I used the bools in the second conditional. Because bools can only be one of two values (true or false), they don't need to be compared using two expressions. Saying "if (bSomeBool)" is the same as saying "if (bSomeBool == true)", and saying "if (!bSomeOtherBool)" is the same as saying "if (bSomeOtherBool == false)". Now, moving on, what if you wanted to do something only if two conditions were true? Or what if you wanted to do something if only one of two different conditions were true? That's where these operators come in:
These are used to link conditions together in the same statement. Take a look at this example:
In the first one, && links the two statements together, so the condition is only true if both statements are true. In the else if, || links the two expressions together, so the condition will be true if either of the statements is true. |
| In addition to
"if" statements, there are other ways to control how code
flows. Things such as loops and switch statements will allow
you to fine-tune your code, and get the results you want. To
be honest, I've never used a switch statement in UnrealScript,
but I'll explain them anyway, since everyone's coding style is
different. Loops, however, I use all the time. They can be
extremely useful to do certain things. There are three types
of loops in UnrealScript, which I will explain below.
F o r L o o p
s
The first statement in the parenthesis, "i=0", sets
the initial value of i as the loop starts. The second
statement, "i<5", is the condition that must be met
for the loop to continue executing. As soon as i is
greater than or equal to 5, the loop will terminate. The
final statement, "i++", is what is done to i each time
the loop executes. So, the first time this loop
executes, i will equal 0. The next time, i will be
incremented by one, making it equal 1. This is still
less than 5, so the loop executes again. Next time, i
will be 2, then 3, then 4, and finally 5. The loop will
terminate once it gets to 5, since 5 is not less than
5.
You'll notice I included the line "i++;" within the
loop. This will increment i each time the loop executes,
so it will terminate when i gets to 5. The main
distinction of the do loop is the fact that it executes
until some condition is true. Both for and while
loops execute while some condition is
true.
Not too complicated. You just supply the variable you
want to use for the switch in the first parameter, then
write different "cases" depending on the different
values of the variable. The final "default" label is
optional, and will be executed if none of the other
cases are true. Note the break statements marking
the end of each case.
Like I said before, switch statements are basically
just complicated if statements. I rarely have use for
them, since the same effects can be achieved simply by
using an if/else
if/else. |
| I have a little
confession to make. You know all the examples I've been giving
so far, in which I declare a variable or two, then jump right
into some code, such as assigning values to these variables,
or writing an if statement or a loop? Well, that was illegal.
In actual UnrealScript, you cannot just write code by itself.
The only parts of a class that can be completely on their own
are the class declaration, variable declarations, and exec
commands. Everything else must be part of a function or
state.
So, what's a function, you ask? A function is just a block of code that performs some action. Once they're defined, they can be called in other parts of the code, to do whatever it is they're supposed to do. They can be given, or passed, variables when they're called, and they can return values. I know this all probably sounds very complicated (assuming you've never done any programming before), but it's really fairly simple once you understand it. Take a look at this example:
There are two functions here, Sqr(), and PostBeginPlay(). Sqr() takes a number, Num, multiplies it by itself, and returns it. You'll notice that I didn't declare Num up with SomeInt and Result. This is because it is "declared" as a parameter to a function. When I call Sqr() down in the PostBeginPlay() function, I supply SomeInt as the value in parenthesis, or the parameter. The call to Sqr() causes the code contained in the Sqr() function to be executed, with SomeInt plugged in for Num. You'll also notice that I put the call to Sqr() after "Result =". This is because I am assigning the value which is returned by Sqr() to Result. When all this code is done executing, Result will be equal to 9: the square of 3. You may also have noticed the keyword "int" before the function name in Sqr()'s definition. This "int" means that Sqr() returns an integer value. Anyway, you may be wondering by now, Where is PostBeginPlay() being called from? The answer is, the engine. There are a wide variety of functions in UnrealScript which are called by the engine in certain places and under certain circumstances. The PostBeginPlay() function is called when an object is first created, so it makes a good place to put code that you want to be executed before any other code. For a list of common functions which are called by the engine (as well as other useful functions which aren't called by the engine), refer to the Function Reference at the side of this page. So, are you thoroughly confused yet? If not, then you're doing good. I know I was scratching my head quite a bit when I first learned this stuff. Well, keep reading, it gets better (or worse, depending on your viewpoint). You know the way I've been declaring variables all along? At the beginning of a class, using the syntax "var [vartype] [varname]"? Well, that's not the only way you can declare a variable. That type of variable, declared outside of any functions, is called a global variable. Global variables can be accessed anywhere in a class, and even outside of a class (as we'll see a little later). But, there are also local variables. Local variables are declared at the beginning of a function, and can only be accessed within that function. They're useful for doing short-term operations that won't need to be "seen" outside of a particular function. You see, one of the key elements of a function, and of object-oriented program as a whole, is the fact that a class or function can share useful data and important information with other classes and functions, but hide how they got that useful data and information. They show only the result, but not how they found the result. In any case, where was I going with this? Oh, yes. Local variables. Local variables are declared just like global variables, only they use the local keyword instead of the var keyword.
So, that's a local variable. Not too complicated, is it? Just like a global variable, except for the fact that it can only be accessed inside a particular function. |
| Inheritance,
you ask? What could inheritance possibly have to do with
programming? Well, it has a lot to with programming. At least
when you're talking about classes. If you'll remember, I told
you earlier that one of the reasons classes are arranged in a
hierarchy is that child classes inherit code from their
parent classes. Well, I wasn't just saying that to watch
myself type. A class will inherit all variables, functions,
states, and default properties (I'll talk about states and
default properties a bit later) from every class above it in
the hierarchy. For example, the Weapon class has in it all the
code written in the Inventory class, the Actor class, and the
Object class, since these are the classes above it in the
hierarchy.
Any new code you write in a class is simply added on to the code inherited from parent classes. But what if you wanted to change a certain inherited function? Well, you can. It's called overriding a function. All you have to do is copy the function definition into the new class (the name, parameters, and return value type), and write new code for it. The ability to do this is extremely useful in UScript, since it allows you to add or change functionality in things without having to copy over all the code. For instance, say you wanted to make an ASMD that launched grenades in alt-fire instead of the little blue energy ball thingy. All you would have to do is copy the one function that controls what happens when the player presses alt-fire, and make a few little changes. Nothing to it. |
| No, not the
United kind. We're talking about UnrealScript here, remember?
Anyway, a state is simply a section of code that is executed
only the class is in that state. For instance, what are
the different states that a weapon could be in? It could be
firing, alt-firing, reloading, or just sitting there looking
pretty. Each of these conditions could have their own
state defined for them, which would contain code that's
only used when the weapon is in that condition. For instance,
if you wanted a weapon to play an idle animation every 30
seconds, you could put a looping timer in the idle state, so
it would only run when the weapon was not doing anything. To
give you an idea of how they're defined, here's the actual
Idle state from the Weapon class:
Code in states can be written either within functions, or under labels. Begin is by far the most common label, and any code written under it is executed as soon as the class enters that state. Another cool thing about states is that you can use them to override functions within a particular class. For instance, say you had a Timer() function defined outside of a state. If you defined another Timer() function within a state, then that Timer() function would override the global one if the class was in that state. Another useful thing you can do with a state is to stop certain functions from executing while the class is in that state. For example, if you wanted to make it so the player couldn't fire while his gun was reloading (usually a good idea), you could add this line just after the definition of your reload state:
This makes it so neither the Fire() or AltFire() function can be executed while the class is in this state. To make an object enter a state, use the syntax: "GoToState('State');". |
| Default
properties are simply a means by which you, as the programmer,
or someone else, such as a mapper, can set default values for
certain variables in a class. Default properties are used to
control many things, such as how to display a class, what mesh
or texture to use, and what sounds to use. If you want a
variable to be displayed in the default properties of a class,
you have to declare it in a special way:
The part in the parenthesis, defaultgroup, tells Unreal what section of the default properties you want the variable to be displayed in. If you don't supply anything for this parameter, it will be displayed in a section with the same name as the class. You can look at and change the default properties of a class by selecting it in the class browser, and clicking the "Defaults" button. |
| Here it is. The
moment you've been waiting for since... since... well, since
you started reading this sentence, I suppose. It's time to
create your first new UnrealScript class. To be specific,
you're going to make a new type of FlakCannon that randomly
alternates between firing a flakshell, a grenade, or an energy
ball in alt-fire. Not the most exciting weapon there ever was,
but hey, this is a tutorial for beginners.
To start off, I suppose I should explain a little something about the way Unreal is organized. All classes, sounds, textures, and models are stored in special files called packages. Most of the code and models, and some of the textures and sounds for Unreal are stored in two files: unreali.u, and unrealshare.u (as of 220, anyway). These files are found in your Unreal\System directory, as are all .u files. When you create a new class in UnrealScript, you store that class in a new .u file. It's not a good idea to store a new class in an existing .u file, since you would then have to pass around the entire file if you wanted to distribute your class. With that out of the way, let's get ready to rumble. Open up UnrealEd (if you don't already have it open), and get to the class browser. Open up the Inventory and Weapon threads, and select the FlakCannon class. Now, hit the "New..." button, which can be found down below the browser. You'll get a window asking you to enter a class name, and a package name. Enter "MultiCannon" in both fields, and press the "Create this actor class" button. You'll see that your MultiCannon class will appear under FlakCannon in the class tree, and an editor window will appear, complete with the class declaration. The next thing to do is copy the AltFire() function from the FlakCannon class, since we want to modify what the weapon shoots in alt-fire. AltFire() is simply a function which is called by the engine when the player presses the alt-fire button. It's used to control what happens when a weapon alt-fires. The same goes for the Fire() function, but we're not modifying primary fire here, so we don't need Fire(). Anyway, double-click on FlakCannon in the class browser to open it up. Scroll through the code until you find the AltFire() function, and copy it into your MultiCannon class. You'll notice that the new code appears as all green when you first copy it. This is because UnrealEd doesn't apply the proper coloring to code until you compile it. So, let's compile it. Compiling in UnrealEd couldn't be easier. Simply hit the F7 key to compile all modified classes. Now, add the following local variable declarations to your new AltFire() function:
Next, find the line "Spawn(class'FlakShell',,, Start,AdjustedAim);", and replace it with the following lines:
That's it. Those are all the modifications that need to be made. Hit F7 again to compile the changes, and you're set. So, what does all this code do, you ask? Well, it's simple, really. Selection is set equal to FRand(), which returns a random number between 0.0 and 1.0. Then, an if/else if/else is used to set Proj to either FlakShell, Grenade, or TazerProj, depending on the value of Selection. Whatever Proj is set to is then spawned (Spawn() is a function that brings a class into existence in the Unreal world), and at the same time, p is set equal to this new projectile. Now, here's something I haven't explained quite yet. The line "p.DrawScale *= 1.5;" is used to reference a variable called "DrawScale" in p, and assign it as itself times 1.5. This is useful notation. If you want to reference a variable or function in another class, all you have to do is specify which class it's in by putting the name of the class, followed by a dot and the name of the variable or function. So, that's it. Your first new UnrealScript class. Before the MultiCannon package will actually be written to your hard disk for use in-game, though, you'll have to save it. Hit the "Save" button at the bottom of the class browser, and select "MultiCannon" in the pull down menu of the window that appears. You'll need to do this every time you make any changes to one of your classes. Now, to try out your work in a game, start up Unreal, go to the console, and type "summon multicannon.multicannon" Good luck, and I hope to see some kick ass weapons from you :) |