UnrealScript Language Reference/Advanced Language Features
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
Advanced Language Features
ForEach And Iterator Functions
UnrealScript's "foreach" command makes it easy to deal with large groups of actors, for example all of the actors in a level, or all of the actors within a certain distance of another actor. "foreach" works in conjunction with a special kind of function called an "iterator" function whose purpose is to iterate through a list of actors.
Here is a simple example of foreach:
// Display a list of all lights in the level. function Something() { local Actor A; // Go through all actors in the level. log( "Lights:" ); foreach AllActors( class 'Actor', A ) { if( A.LightType != LT_None ) log( A ); } }
The first parameter in all "foreach" commands is a constant class, which specifies what kinds of actors to search. You can use this to limit the search to, for example, all Pawns only.
The second parameter in all "foreach" commands is a variable which is assigned an actor on each iteration through the "foreach" loop.
Here are all of the iterator functions which work with "foreach".
- AllActors ( class BaseClass, out actor Actor, optional name MatchTag )
- Iterates through all actors in the level. If you specify an optional MatchTag, only includes actors which have a "Tag" variable matching the tag you specified.
- ChildActors( class BaseClass, out actor Actor )
- Iterates through all actors owned by this actor.
- BasedActors( class BaseClass, out actor Actor )
- Iterates throgh all actors which are standing on this actor.
- TouchingActors( class BaseClass, out actor Actor )
- Iterates through all actors which are touching (interpenetrating) this actor.
- TraceActors( class BaseClass, out actor Actor, out vector HitLoc, out vector HitNorm, vector End, optional vector Start, optional vector Extent )
- Iterates through all actors which touch a line traced from the Start point to the End point, using a box of collision extent Extent. On each iteration, HitLoc is set to the hit location, and HitNorm is set to an outward-pointing hit normal.
- RadiusActors( class BaseClass, out actor Actor, float Radius, optional vector Loc )
- Iterates through all actors within a specified radius of the specified location (or if none is specified, this actor?s location).
- VisibleActors( class BaseClass, out actor Actor, optional float Radius, optional vector Loc )
- Iterates through a list of all actors who are visible to the specified location (or if no location is specified, this actor?s location).
more on this topic in the Wiki: Iterator |
Function Calling Specifiers
In complex programming situations, you will often need to call a specific version of a function, rather than the one that?s in the current scope. To deal with these cases, UnrealScript provides the following keywords:
- Global
- Calls the most-derived global (non-state) version of the function.
- Super
- Calls the corresponding version of the function in the parent class. The function called may either be a state or non-state function depending on context.
- Super(classname)
- Calls the corresponding version of the function residing in (or above) the specified class. The function called may either be a state or non-state function depending on context.
It is not valid to combine multiple calling specifiers (i.e. Super(Actor).Global.Touch).
Here are some examples of calling specifiers:
class MyClass extends Pawn; function MyExample( actor Other ) { Super(Pawn).Touch( Other ); Global.Touch( Other ); Super.Touch( Other ); }
As an additional example, the BeginPlay() function is called when an actor is about to enter into gameplay. The BeginPlay() function is implemented in the Actor class and it contains some important functionality that needs to be executed. Now, say you want to override BeginPlay() in your new class MyClass, to add some new functionality. To do that safely, you need to call the version of BeginPlay() in the parent class:
class MyClass extends Pawn; function BeginPlay() { // Call the version of BeginPlay in the parent class (important). Super.BeginPlay(); // Now do custom BeginPlay stuff. //... }
more on this topic in the Wiki: Function Syntax and Special UnrealScript Keywords |
Default Values of Variables
Accessing Default Values of Variables
UnrealEd enables level designers to edit the "default" variables of an object's class. When a new actor is spawned of the class, all of its variables are initialized to those defaults. Sometimes, it?s useful to manually reset a variable to its default value. For example, when the player drops an inventory item, the inventory code needs to reset some of the actor?s values to its defaults. In UnrealScript, you can access the default variables of a class with the "Default." keyword. For example:
var() float Health, Stamina; //... // Reset some variables to their defaults. function ResetToDefaults() { // Reset health, and stamina. Health = Default.Health; Stamina = Default.Stamina; }
Accessing Default Values of Variables in a Variable Class
If you have a class reference (a variable of "class" or "class<classlimiter>" type), you can access the default properties of the class it references, without having an object of that class. This syntax works with any expression that evaluates to class type.
var class C; var class<Pawn> PC; Health = class'Spotlight'.default.LightBrightness; // Access the default value of LightBrightness in the Spotlight class. Health = PC.default.Health; // Access the default value of Health in a variable class identified by PC. Health = class<Pawn>(C).default.Health; // Access the default value of Health in a casted class expression.
Accessing Static Functions in a Variable Class
Static functions in a variable class may be called using the following syntax.
var class C; var class<Pawn> PC; class'SkaarjTrooper'.static.SomeFunction(); // Call a static function in a specific class. PC.static.SomeFunction(); // Call a static function in a variable class. class<Pawn>(C).static.SomeFunction(); // Call a static function in a casted class expression.
Dynamic Arrays
Previously, we covered Arrays, which were static. What that means is that the size (how many elements are in the array) is set at compile time and cannot be changed. Dynamic Arrays and Static Arrays share the following common characteristics:
- Constant seek time
- The time code spends accessing any given element of the array is the same, regardless of how many elements are in the array
- Unlimited element type
- You can have an array of anything (other than bools) – ints, vectors, Actors, etc.
- Access behavior
- You can access any element with an index into the array, and conversely, attempting to access an element at an index that is outside the bounds of the array will throw an accessed none.
Dynamic Arrays provide a way of having Static Array functionality with the ability to change the number of elements during run-time, in order to accommodate changing needs. In order use Dynamic Arrays, we need to know a few things.
The first is variable declaration. In order to declare a dynamic array, the syntax is array<VARIABLE_TYPE> VARIABLE_NAME
which is preceded by the appropriate identifiers (var or local, for example). An example would be var array<int> IntList
. When script starts, IntList will start with 0 elements. There are methods supported by Dynamic Arrays that allow us to add elements to the array, take elements out, and increase or decrease the length of the array arbitrarily. The syntax for calling these methods is (using our IntList example) IntList.MethodName()
. The following is a breakdown of the supported methods and a brief explanation of their parameters:
- Insert(int index_to_insert_at, int how_many_elements_to_insert)
- This allows us to tell the array to create more elements and create them starting at a specific location in the array. Inserting 5 elements at index 3 will shift up (in index value) all elements in the array starting at index 3 and up (shifting them up by the number of elements to insert).
- Remove(int index_to_begin_removing_at, int how_many_elements_to_remove)
- This allows us to remove a group of elements from the array starting at any valid index within the array. Note that any indexes that are higher than the range to be removed will have their index values changed, keep this in mind if you store index values into dynamic arrays.
Dynamic Arrays also have a variable called "Length", which is the current length (number of elements) of the dynamic array. To access Length, using our example array, we would say IntList.Length
. We can not only read the Length variable, but we can also directly set it, allowing us to modify the number of elements in the array. When you modify the Length variable directly, all changes in array length happen at the 'end' of the array. For example, if we set IntList.Length = 5
, and then we set IntList.Length = 10
, the extra 5 elements we just added were added to the end of the array, maintaining our original 5 elements and their values. If we decreased the Length, the elements would be taken off the end as well. Note that when you add elements to the array, either by Insert() or by increasing Length, the elements are initialized to the variable type's default value (0 for ints, None for class references, etc). It is also noteworthy to know that you can increase the length of a dynamic array by setting an element index that is greater than the array's current Length value. This will extend the array just as if you had set Length to the larger value.
A word of caution – the Length member of a dynamic array should never be incremented/decremented by '++', '–', '+=', or '-=', nor should you pass Length to a function as an out parameter (where the function can change the value of it). Doing these things will result in memory leaks and crashes due to Length not being accurate any more; only setting the Length via the '=' operator (and setting an element at an index larger than Length) modifies the actual length of the dynamic array properly.
A final note – dynamic arrays are not replicated. You could get around this by having a function that replicates and has two arguments, an index into the dynamic array and the value to store there. However, you would also have to consider consequences of elements not being the same within a space of a tick on client and server.
more on this topic in the Wiki: dynamic array |
Prev Page: /Language Functionality – Section 8 of 9 – Next Page: /Advanced Technical Issues