Cogito, ergo sum

Legacy:UnrealScript Language Reference/Functions

From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

UnrealScript Language Reference

This subpage is part of a document by Tim Sweeney. The Unreal Wiki has been granted permission to host it. Please don't make any edits to these pages other than basic formatting of the text. If you have more to say on a topic here, please start a new Wiki page on it, for example from UnrealScript or Unreal Engine, and then add a "related topics" section to the very end of a page here.

Tim Sweeney
Epic MegaGames, Inc.
tim@epicgames.com
http://www.epicgames.com

Functions

Declaring Functions

In UnrealScript, you can declare new functions and write new versions of existing functions. Functions can take one or more parameters (of any variable type UnrealScript supports), and can optionally return a value. Though most functions are written directly in UnrealScript, you can also declare functions that can be called from UnrealScript, but which are implemented in C++ and reside in a DLL. The Unreal technology supports all possible combinations of function calling: The C++ engine can call script functions; script can call C++ functions; and script can call script.

Here is a simple function declaration. This function takes a vector as a parameter, and returns a floating point number:

// Function to compute the size of a vector.
function float VectorSize( vector V )
{
        return sqrt( V.X * V.X + V.Y * V.Y + V.Z * V.Z );
}

The word "function" always precedes a function declaration. It is followed by the optional return type of the function (in this case, "float"), then the function name, and then the list of function parameters enclosed in parenthesis.

When a function is called, the code within the brackets is executed. Inside the function, you can declare local variables (using the "local" keyword"), and execute any UnrealScript code. The optional "return" keyword causes the function to immediately return a value.

You can pass any UnrealScript types to a function (including arrays), and a function can return any type.

By default, any local variables you declare in a function are initialized to zero.

Function calls can be recursive. For example, the following function computes the factorial of a number:

// Function to compute the factorial of a number.
function int Factorial( int Number )
{
       if( Number <= 0 )
               return 1;
       else
               return Number * Factorial( Number - 1 );
}

Some UnrealScript functions are called by the engine whenever certain events occur. For example, when an actor is touched by another actor, the engine calls its "Touch" function to tell it who is touching it. By writing a custom "Touch" function, you can take special actions as a result of the touch occuring:

// Called when something touches this actor.
function Touch( actor Other )
{
       Log( "I was touched!")
       Other.Message( "You touched me!" );
}

The above function illustrates several things. First of all, the function writes a message to the log file using the "Log" command (which is the equivalent of Basic's "print" command and C's "printf"). Second, it calls the "Message" function residing in the actor Other. Calling functions in other actors is a common action in UnrealScript, and in object-oriented languages like Java in general, because it provides a simple means for actors to communicate with each other.

Function Parameter Specifiers

When you normally call a function, UnrealScript makes a local copy of the parameters you pass the function. If the function modifies some of the parameters, those don't have any effect on the variables you passed in. For example, the following program:

function int DoSomething( int x )
{
       x = x * 2;
       return x;
}
 
function int DoSomethingElse()
{
       local int a, b;
       a = 2;
       log( "The value of a is " $ a );
 
       b = DoSomething( a );
       log( "The value of a is " $ a );
       log( "The value of b is " $ b );
}

Produces the following output when DoSomethingElse is called:

 The value of a is 2
 The value of a is 2
 The value of b is 4

In other words, the function DoSomething was working with a local copy of the variable "a" which was passed to it, and it was not affecting the real variable "a".

The "out" specified lets you tell a function that it should actually modify the variable that is passed to it, rather than making a local copy. This is useful, for example, if you have a function that needs to return several values to the caller. You can just have the caller pass several variables to the function which are "out" values. For example:

// Compute the minimum and maximum components of a vector.
function VectorRange( vector V, out float Min, out float Max )
{
       // Compute the minimum value.
       if ( V.X<V.Y && V.X<V.Z ) Min = V.X;
       else if( V.Y<V.Z ) Min = V.Y;
       else Min = V.Z;
 
       // Compute the maximum value.
       if ( V.X>V.Y && V.X>V.Z ) Max = V.X;
       else if( V.Y>V.Z ) Max = V.Y;
       else Max = V.Z;
}

Without the "out" keyword, it would be painful to try to write functions that had to return more than one value.

With the "optional" keyword, you can make certain function parameters optional, as a convenience to the caller. For UnrealScript functions, optional parameters which the caller doesn't specify are set to zero. For native functions, the default values of optional parameters depends on the function. For example, the Spawn function takes an optional location and rotation, which default to the spawning actor's location and rotation.

The "coerce" keyword forces the caller's parameters to be converted to the specified type (even if UnrealScript normally would not perform the conversion automatically). This is useful for functions that deal with strings, so that the parameters are automatically converted to strings for you.

Function Overriding

"Function overriding" refers to writing a new version of a function in a subclass. For example, say you're writing a script for a new kind of monster called a Demon. The Demon class, which you just created, extends the Pawn class. Now, when a pawn sees a player for the first time, the pawn's "SeePlayer" function is called, so that the pawn can start attacking the player. This is a nice concept, but say you wanted to handle "SeePlayer" differently in your new Demon class. How do you do this? Function overriding is the answer.

To override a function, just cut and paste the function definition from the parent class into your new class. For example, for SeePlayer, you could add this to your Demon class.

// New Demon class version of the Touch function.
function SeePlayer( actor SeenPlayer )
{
       log( "The demon saw a player" );
       // Add new custom functionality here?
}

Function overriding is the key to creating new UnrealScript classes efficiently. You can create a new class that extends on an existing class. Then, all you need to do is override the functions which you want to be handled differently. This enables you to create new kinds of objects without writing gigantic amounts of code.

Several functions in UnrealScript are declared as "final". The "final" keyword (which appears immediately before the word "function") says "this function cannot be overridden by child classes". This should be used in functions which you know nobody would want to override, because it results in faster script code. For example, say you have a "VectorSize" function that computes the size of a vector. There's absolutely no reason anyone would ever override that, so declare it as "final". On the other hand, a function like "Touch" is very context-dependent and should not be final.

Advanced Function Specifiers

Static

A static function acts like a C global function, in that it can be called without having a reference to an object of the class.  Static functions can call other static functions, and can access the default values of variables.  Static functions cannot call non-static functions and they cannot access instance variables (since they are not executed with respect to an instance of an object).  Unlike languages like C++, static functions are virtual and can be overridden in child classes.   This is useful in cases where you wish to call a static function in a variable class (a class not known at compile time, but referred to by a variable or an expression).

Singular

The "singular" keyword, which appears immediately before a function declaration, prevents a function from calling itself recursively. The rule is this: If a certain actor is already in the middle of a singular function, any subsequent calls to singular functions will be skipped over. This is useful in avoiding infinite-recursive bugs in some cases. For example, if you try to move an actor inside of your "Bump" function, there is a good chance that the actor will bump into another actor during its move, resulting in another call to the "Bump" function, and so on. You should be very careful in avoiding such behaviour, but if you can't write code with complete confidence that you're avoiding such potential recursive situations, use the "singular" keyword.

Native

You can declare UnrealScript functions as "native", which means that the function is callable from UnrealScript, but is actually written (elsewhere) in C++. For example, the Actor class contains a lot of native function definitions, such as:

native(266) final function bool Move( vector Delta );

The number inside the parenthesis after the "native" keyword corresponds to the number of the function as it was declared in C++ (using the AUTOREGISTER_NATIVE macro). The native function is expected to reside in the DLL named identically to the package of the class containing the UnrealScript definition.

Latent

Declares that a native function is latent, meaning that it can only be called from state code, and it may return after some game-time has passed.

Iterator

Declares that a native function is an iterator, which can be used to loop through a list of actors using the "foreach" command.

Simulated

Declares that a function may execute on the client-side when an actor is either a simulated proxy or an autonomous proxy. All functions that are both native and final are automatically simulated as well.

Operator, PreOperator, PostOperator

These keywords are for declaring a special kind of function called an operator (equivalent to C++ operators). This is how UnrealScript knows about all of the built-in operators like "+", "-", "==", and "||". I'm not going into detail on how operators work in this document, but the concept of operators is similar to C++, and you can declare new operator functions and keywords as UnrealScript functions or native functions.

Event

The "event" keyword has the same meaning to UnrealScript as "function". However, when you export a C++ header file from Unreal using "unreal -make -h", UnrealEd automatically generates a C++ -> UnrealScript calling stub for each "event".  This is a much cleaner replacement for the old "PMessageParms" struct, because it automatically keeps C++ code synched up with UnrealScript functions and eliminates the possibility of passing invalid parameters to an UnrealScript function. For example, this bit of UnrealScript code:

 event Touch( Actor Other )
 { ... }

Generates this piece of code in EngineClasses.h:

 void Touch(class AActor* Other)
 {
     FName N("Touch",FNAME_Intrinsic);
     struct {class AActor* Other; } Parms;
     Parms.Other=Other;
     ProcessEvent(N,&Parms);
 }

Thus enabling you to call the UnrealScript function from C++ like this:

 AActor *SomeActor, *OtherActor;
 Actor->Touch(OtherActor);

Discussion

Arelius: Event, Why for instance is Landed(vector Hitnormal) defined as a event in some places, and a function in others? Do they refer to the same routines, does the function override the event? Would an event override a function?

MythOpus: They are basically the same thing, only event's can be called by native code. I think that's the only difference.

Arelius: As it turns out, an Event will generate a wrapper in the native header, the function will then often be defined as a function in subclasses, as the parents event wrapper will call that.

El Muerte: event only has meaning for native classes and functions. In any other case it's equal to function. The only thing different from event and function is that the native declaration of even is "nicer" to be called from native code. Like Arelius says, a special wrapper is created. You could also call a function from the native code, but it's not as easy to call as an event. So it's almost safe to say that only events will be called from native code. For this reason a lot of people will also declare an overridden event as event, even though it's safe to simply use function.


Prev Page: Legacy:UnrealScript Language Reference/ExpressionsSection 4 of 9 – Next Page: Legacy:UnrealScript Language Reference/Program Structure