|
|
U n r
e a l S
c r i p
t
by Windex
|
I n t r o d u c t i o n
|
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. |
L e t ' s g e t s t a r t e d . . .
|
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. |
W h a t i n t a r n a t i o n i
s a c l a s s ?
|
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. |
M o v i n g O n
|
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. |
T h e C l a s s D e c l a r a t i o n
|
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:
|
FlakCannon Class Declaration |
class
FlakCannon expands
Weapon;
|
|
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. |
I n t r o d u c i n g : V a r i a b l e s
|
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. |
T y p e s o f V a r i a b l e s
|
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:
|
The Variable Declaration |
var [vartype]
[varname];
|
|
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:
I
n t e g e r |
Keyword: int
|
|
An
integer number value. For those of you not familiar with
what an integer is, it's a whole number that can also be
negative. In other words, anything without a decimal. 37 is
an integer. 2 is an integer. -674 is an integer. 6.3432 is not
an integer.
|
Integer Example |
|
var
int myInt;
myInt = 3; //Assign
a value
myInt++; //Increment
myInt--; //Decrement
|
|
|
Note the special syntax you can use to add or subtract
one from an integer. Saying "myInt++;" does the
same thing as saying "myInt = myInt + 1;", and
saying "myInt--;" does the same thing as saying
"myInt = myInt - 1;". |
F
l o a t i n g P o i n t |
Keyword: float
|
|
A number
value that, unlike an integer, can include decimals. 6.3432,
4534243.2, and -0.98 are all floating point numbers.
|
Floating Point Example |
|
var
float myFloat;
myFloat = 3.2453; //Assign
a value
|
|
|
You cannot increment and decrement a float using the same
syntax as an int. To add one to a float, you would have to
say "myFloat = myFloat + 1;", not "myFloat++;".
It's also important to keep in mind one other thing when
working with integers and floats. Take a look at these
examples:
|
Integers and Floats Don't Mix |
|
var
int myInt;
var float
myFloat, Result;
//Example 1
myInt = 5;
myFloat = 0.5;
Result = myFloat * myInt;
//Example 2
myInt = 5;
myFloat = 2.0;
Result = myInt / myFloat;
|
|
|
In example one, Result will not equal 2.5. Because
you are multiplying an integer by a float, you will always
get an integer back. If you wanted to get 2.5 back, you
would have to declare myInt as a float, not an int. The same
is true for example two. Even though you are dividing 5 by
2, and assigning the result to a float, you will not
get 2.5 back, because the 5 is an integer. Also, note the
way I've declared the two floats in this example. You can
declare multiple variables in the same statement by simply
separating the different variable names with commas. |
B
o o l e a n V a l u e |
Keyword: bool
|
|
A value
which is either "true" or "false". These
have not always been around, since it's possible to simply
use an integer, and set it to either 0 or 1. This would give
the same effect. However, it's easier to see and understand
the words true and false than it is to understand a 0 or 1,
so the bool was introduced.
|
Boolean Example |
|
var
bool bMyBool;
bMyBool = true;
//Assign a value
|
|
|
Note that the prefix "b" is often used in
boolean variable names. This is just a naming convention,
though, and it's not a required. |
|
An
integer value in the range of 0 to 255. The use of these may
not be apparent at first glance. You're probably saying to
yourself, Why not just use an integer? Well, I
honestly can't answer that. I very rarely (if ever) use
these, so I'm not extremely clear on their advantages. I can
give you an example of one thing they are used for, though,
and that is RGB color values, which fall in the range of 0
to 255.
|
Byte Example |
|
var
byte bMyByte;
bMyByte = 255;
//Assign a value
|
|
|
Again, note the prefix "b". For some reason,
Epic chose to use the same naming convention for both bytes
and bools. So, be careful not to confuse the two when
looking through existing scripts. |
S
t r i n g |
Keyword: string
|
|
A string
is simply a bunch of alpha-numeric characters. In other
words... well, words. Strings of letters and numbers that
make up words and sentences.
|
String Example |
|
var
string[32] String1; //Declare
string
var string[32]
String2;
var string[32]
Result;
String1 = "Blah";
//Assign a value
String2 = "Gah";
//Combine two
strings
Result = String1 $ String2;
//Find left 2
characters of String1
Result = Left(String1, 2);
//Find right 2
characters of String1
Result = Right(String1, 2);
//Find the number
of characters in String1
Result = Len(String1);
//Return String1
in all caps
Result = Caps(String1);
|
|
|
Note that strings are declared in a special way. The
number in the square brackets after the word
"string" is the maximum number of characters the
string can be. In this example, the maximum length of
String1, String2, or Result would be 32. There are also many
special operations which can be performed on strings, such
as "concantations" (or combining two strings into
one), finding left or right characters, or finding the
length of the string. |
|
Names are
a tough one. They're hardly ever used, and understood by
few. I'll do my best to explain them, though. The only
application I can think of for them is in tags. If you've
done any level design, you've probably used tags. They're
used to associate one object with another in order to
trigger certain events. Anyway, tags are simply name
variables. It can be easy to confuse names with strings, but
names are not strings. A string can be modified
dynamically, but a name is simply a label for an object.
|
Name Example |
|
var
name MyName;
MyName = 'Windex'; //Assign
a value
|
|
|
|
E
n u m e r a t i o n |
Keyword: enum
|
|
Enumerations
are simply a way of defining a type of variable that can be
one of a certain pre-defined set of values. Like bools,
they're not absolutely necessary, since integers could be
used to get the same effect. However, it's easier to see
understand a set of descriptive words instead of a bunch of
numbers.
|
Enumeration Example |
|
//Declare a new enumeration
enum EColor;
{
CO_Red,
CO_Blue,
CO_Green
};
//Declare variable of type EColor
var EColor MyColor;
//Assign a value
MyColor = CO_Blue;
|
|
|
Note that the "CO_" preceding each of the color
values is simply a naming convention, and is not required.
You can name your enumeration values anything you want. |
A
c t o r R e f e r e n c e |
Keyword: n/a
|
|
Actor
references are a special type of variable that references an
actual object in the game. It will be difficult to fully
grasp them at this point, but I'll give you the basics, at
any rate. Later on, once I've introduced functions, I'll go
into more detail about them.
|
Actor Reference Example |
|
//Declare
a reference to any actor
var Actor
MyActor;
//Declare a
reference to a pawn
var Pawn
MyPawn;
//Declare a
reference to a weapon
var Weapon
MyWeapon;
|
|
|
You'll notice I didn't include any examples explaining
how you assign a value to an actor reference. This is
because you can only set an actor reference equal to another
actor reference, or to a newly spawned actor using the
Spawn() function. As I said, actor references are difficult
to explain at this point, but I'll go into more detail
later, once you've learned a bit more. |
C
l a s s R e f e r e n c e |
Keyword: class
|
|
Class
references, like actor references, are a special type of
variable. Also like actor references, they're difficult to
explain at this point. I'll do my best, though. A class
reference, unlike an actor reference, doesn't reference an
actual object in the world. It references a class itself, or
the mold. It references the thing that creates
objects, instead of the objects themselves.
|
Class Reference Example |
|
//Declare
a class reference
var class<Actor>
MyClass;
//Assign a value
MyClass = Class'Pawn';
|
|
|
The word "Actor" in angle brackets after the
word "class" in the declaration means that Actor
is the upper limit of this variable. What this means
is that MyClass cannot be set equal to anything
higher than Actor in the class tree. Class references are
assigned values by using the keyword Class, followed
by the name of a class in single quotes. |
S
t r u c t |
Keyword: struct
|
|
A
structure is a way of defining a new type of
"super-variable" that is made up of individual
components. A struct is actually similar to a class,
although a very simple class that can only contain
variables. Structs define a new type of variable that can be
declared and used just as any other variable. Take this
example:
|
Struct Example |
|
//Define a new struct
struct Box
{
var float Length;
var float Width;
var float Height
};
//Declare a couple variables of type Box
var Box MyBox, YourBox;
//Assign values to individual components
YourBox.Length = 3.5;
YourBox.Width = 5.43;
YourBox.Height = 2.8;
//Set MyBox equal to YourBox
MyBox = YourBox;
|
|
|
The struct defines a new type of variable, called
"Box", which has three sub-variables to it:
length, width, and height. Once you define a variable of the
new type, you can assign values to its individual components
with the syntax "VarName.ComponentName". One very
common struct in UnrealScript is the vector, which is
made up of X, Y, and Z components. The techniques of working
with vectors are somewhat complex, and you can learn more
about them in the Vectors
tutorial. |
|
C o n d i t i o n a l s
|
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:
|
Conditional Syntax |
|
if ([expression1] [operator] [expression2])
{
Do some stuff here;
}
else if ([expression1] [operator] [expression2])
{
Do more stuff here;
}
else
{
Hey, look, more stuff;
}
|
|
|
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:
Operator |
Description |
== |
Equal to |
!= |
Not equal to |
< |
Less than |
> |
Greater than |
<= |
Less than or
equal to |
>= |
Greater than
or equal to |
~= |
Approximately
equal to |
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.
|
Basic Conditional |
|
var bool bSomeBool, bSomeOtherBool;
var int SomeInt, SomeOtherInt;
if (SomeInt > 3)
{
SomeInt is greater than 3, so do
something;
}
else if (SomeOtherInt <= SomeInt)
{
SomeInt is not greater than 3,
but SomeOtherInt is less than or
equal to SomeInt, so do something
else;
}
else
{
All the conditionals failed, so
do this;
}
if (bSomeBool)
{
bSomeBool is true, so do this;
}
else if (!bSomeOtherBool)
{
The first conditional failed, but
bSomeOtherBool is false, so do this
instead;
}
|
|
|
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:
Operator |
Description |
&& |
And |
|| |
Or |
These are used to link conditions together in the same
statement. Take a look at this example:
|
Conditional with && and || |
|
var bool bSomeBool;
var int SomeInt, SomeOtherInt;
if (SomeInt > 3 && SomeOtherInt < 3)
{
SomeInt is greater than three,
and SomeOtherInt is less than
three, so do something;
}
else if (SomeOtherInt == SomeInt || !bSomeBool)
{
The first condition failed, but
either SomeOtherInt equals SomeInt,
or bSomeBool is false, so do this
instead;
}
|
|
|
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. |
O t h e r F l o w C o n t r o l D
e v i c e s
|
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
|
For loops
are the type I use the most, since I've found that they
usually fit my needs just as well or better than the other
two types. The basic concept of a for loop is to execute a
certain block of code over and over again, until a certain
condition is met.
|
For Loop Example |
|
var int i;
for ( i=0; i<5; i++ )
{
Do stuff;
}
|
|
|
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. |
D
o L o o p s
|
Do loops,
unlike for loops, have no built-in expressions for
incrementing counters or setting initial values. They simply
execute over and over until a condition at the end of the
loop is met. Because they have no built-in expression for
incrementing a variable, you will have to include a line
within the loop that somehow increments or changes your
counter variable, so that the ending condition will
eventually be met. Otherwise, you get an infinite loop. Not
a good thing.
|
Do Loop Example |
|
var int i;
do
{
Do stuff;
i++;
} until (i == 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. |
W h i l
e L o o p s
|
While
loops are basically do loops, except for the fact that they
execute while their condition is true, whereas do
loops execute until their condition is true. Again,
you'll have to include a line in the loop to somehow
increment your counter variable, since there is no built-in
expression for this in the loop declaration.
|
While Loop Example |
|
var int i;
while ( i < 5 )
{
Do stuff;
i++;
}
|
|
|
|
S w i t c h S t a t e m e n t s
|
A switch
statement is basically like a complicated if statement. It
allows you to execute different blocks of code depending on
the value of a certain variable. Take a look at this
example:
|
Switch Statement Example |
|
var string[32] Developer;
switch ( Developer )
{
case "Tim":
Hey, it's Tim. Do something;
break;
case "Cliff":
Look, there's Cliffy.
Do something else;
break;
case "Myscha":
Where'd Myscha come from?
Better do something else;
break;
default:
No one here;
break;
}
|
|
|
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. |
|
F u n c t i o n s
|
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:
|
Simple Function Example |
|
var int SomeInt, Result;
//Take an integer, and return its square
function int Sqr( int Num )
{
return Num * Num;
}
//Test the Sqr() function
function PostBeginPlay()
{
SomeInt = 3;
Result = Sqr(SomeInt);
}
|
|
|
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.
|
Local Variables |
|
function PostBeginPlay()
{
//Declare a local integer
local int SomeInt;
//Assign a value
SomeInt = 3;
}
|
|
|
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. |
I n h e r i t a n c e
|
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. |
S t a t e s
|
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:
|
The Weapon Idle State |
|
state Idle
{
function AnimEnd()
{
PlayIdleAnim();
}
function bool PutDown()
{
GotoState('DownWeapon');
return True;
}
Begin:
bPointing=False;
if ( (AmmoType != None)
&& (AmmoType.AmmoAmount<=0) )
Pawn(Owner).SwitchToBestWeapon();
if ( Pawn(Owner).bFire!=0 ) Fire(0.0);
if ( Pawn(Owner).bAltFire!=0 ) AltFire(0.0);
Disable('AnimEnd');
PlayIdleAnim();
}
|
|
|
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');".
|
D e f a u l t P r o p e r t i e s
|
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:
|
Default Properties Variable |
|
var([defaultgroup]) [vartype] [varname];
|
|
|
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. |
Y o u r F i r s t C l a s s
|
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:
|
New Variable Declarations |
|
local projectile p;
local class<projectile> Proj;
local float Selection;
|
|
|
Next, find the line "Spawn(class'FlakShell',,,
Start,AdjustedAim);", and replace it with the following
lines:
|
New Code |
|
Selection = FRand();
if ( Selection < 0.4 )
Proj = Class'FlakShell';
else if ( Selection < 0.7 )
Proj = Class'Grenade';
else
Proj = Class'TazerProj';
p = Spawn(Proj,,, Start,AdjustedAim);
if ( Proj == Class'Grenade' )
p.DrawScale *= 1.5;
|
|
|
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 :) |

Visitors Since December 26, 2000
|
>
|