Dynamic Array
Definition
An array is a series of variables stored together and references as one variable. You can also access individual elements of the array variable. It is often likened to a list – it could be a list of integers, a list of names, a list of strings, etcetera. You can even have arrays of structs and arrays of references.
A dynamic array is an array that can be lengthened or shortened to accomodate the number of elements in the array. Dynamic arrays support is implemented in UnrealScript starting with UnrealEngine2.
Dynamic arrays have advantages and disadvantages when compared to arrays with a fixed number of elements (for these, see Variable Syntax). Dynamic arrays cannot be replicated. However, they can be resized and they are faster than static arrays. Although this may seem strange, it's true - dynamic arrays can actually be accessed faster than static arrays. However, the difference is primarily academic, as both have an almost negligible access time.
Syntax
var/local array<type> ArrayName, ...;
The type can be any of the built-in or self-defined types (structs, enums, classes). Note that you can declare a variable of type array<bool>
and your code will compile fine, but the engine simply ignores assignments to elements of that array, so it's basically worthless. You'll have to resort to array<byte>
for that. After declaration the dynamic array is empty, i.e. the array's length is zero.
To access a dynamic array use this syntax:
ArrayName[element number]
Dynamic arrays have various properties and methods to modify them:
- ArrayName.Length
- Returns the number of elements in the array. (Similar to ArrayCount(ArrayName) for static arrays.) So, for example, if the array has no elements, ArrayName.Length will have a value of 0 (zero). If the array has 47 elements, ArrayName.Length will equal 47. And so on. You can change this property to add or remove elements from the array. Only use the
=
operator for doing this, any other (like e.g.+=
) will not work and might even crash the game. Increasing the length adds empty elements at the end of the array while preserving the existing elements. Decreasing the length removes only the last elements without changing the other ones. - ArrayName.Remove(position, number)
- Removes number elements from the array, starting at position. All elements before position and from position+number on are not changed, but the element indices change, i.e. the element formerly accessed through ArrayName[position+number] is accessed through ArrayName[position] after the removing.
- ArrayName.Insert(position, number)
- Inserts number elements into the array at position. The indices of the following elements are increased by number in order to make room for the new elements.
If you read an array element that doesn't exist because it's beyond the array's length, you'll get a null value (see below) and an "Accessed array out of bounds" warning is logged.
If you write to an array element that doesn't exist (yet) because the array is too short, the array will automatically increase its length. All new elements inserted between the former end of the array and the element you are writing to are initialized with their respective null element (zero, empty string or None, depending on the array's type). Note: Arrays of structs can only be extended that way when assigning an entire struct not only one property of the struct because only the first really assigns something to the array, while the second actually tries to access an object (not) stored in the array to modify one of its properties.
Note: You can't use a combination of dynamic and static arrays.
The declaration var array<string> StringArray[10];
will actually be compiled and used as a static array declared as var string StringArray[10];
Also declaring dynamic arrays of dynamic arrays won't work. Here you can use the same workaround as mentioned for static arrays in Variable Syntax.
Dynamic Arrays as Config Variables
Dynamic arrays can be initialized from .ini files by adding the config
keyword to their declaration. Given the following class...
class DynamicArrayTest extends Object config; var config array<string> MyDynamicArray;
...the corresponding .ini entries look as follows:
[DynamicArrayTest.DynamicArrayTest] MyDynamicArray=first entry MyDynamicArray=second entry MyDynamicArray=third entry
Note the lack of array indices.
If you leave out the MyDynamicArray, like this:
[DynamicArrayTest.DynamicArrayTest]
the result will be an empty MyDynamicArray, even if you have default values set in the class' defaultproperties block
Dynamic Arrays in UnrealEngine1
This is an example of Scripting Operators.
Always wanted to use those elusive array<>'s, but found the GetPropertyText/SetPropertyText interface to be a problem? This is where operators come in. Here I provide a simple interface to a dynamic array of integers (although this is easily adaptable to support various types). You set elements of a dynamic array with 'Array << (Index:Data)' (totally arbitrary syntax I made up), and access an element with 'Array<Index>'.
class TestDynArray extends CommandLet; // Our struct to store the index/data pairs created using the : operator struct SetGroup { var int Index; var int NData; }; // The left side of the Array construct... the one that actually does something. final operator(50) int < ( DynArray A, int B ) { return A.Get( B ); } // The right side of the Array construct... does absolutely nothing, it's just there to make the syntax pretty (complete the brackets). final postoperator int > ( int A ) { return A; } // Sets an element in a dynamic array, taking a index/data pair as the right side. final operator(50) DynArray << ( out DynArray A, SetGroup B ) { A.Set( B.Index, B.NData ); return A; } // Creates a index/data pair final operator(23) SetGroup : ( int A, int B ) { local SetGroup C; C.Index = A; C.NData = B; return C; } // Just a test function to show that we can use all sorts of expressions within the index/data pairs function int TestFunc() { return 10; } function int main( string parm ) { local DynArray Arr; local int i; local setgroup g; // Instantiate a DynArray Arr = new class'DynArray'; // Set some elements Arr << (5:78); Arr << (1:30); Arr << (TestFunc():69); // And log them Log( Arr<5> @ Arr<1> @ Arr<TestFunc()> ); return 1; }
// Interface to dynamic arrays. Evil. class DynArray extends Object; var array<int> Data; var int CacheData[1024]; var int Num; var bool bCached; // Parse the elements out of a string like (2,3,5,2,4,6,2), and store them in our cache function Recache() { local int i; local string Nightmare; local int NextPos; local int z; Num = 0; Nightmare = GetPropertyText("Data"); Nightmare = Right( NightMare, Len(NightMare)-1 ); Nightmare = Left( NightMare, Len(NightMare)-1 ); for(i = InStr( Nightmare, "," );i > 0;z++) { CacheData[Num++] = int( Left(Nightmare, i) ); Nightmare = Mid( Nightmare, i + 1, Len( Nightmare ) ); i = InStr( Nightmare, "," ); if ( i == -1 && Len(NightMare) > 0 ) CacheData[Num++] = int( Nightmare ); } bCached = true; } // Set an element by building a string like (3,3,5,9), and recache. function Set( int Index, int Data ) { local string Build; local int i; Recache(); CacheData[Index] = Data; if ( Index > Num-1 ) Num = Index+1; Build = Build $ "("; for(i=0;i<Num;i++) { Build = Build $ CacheData[i]; if ( i != Num-1 ) Build = Build $ ","; } Build = Build $ ")"; SetPropertyText("Data", Build); bCached = true; } // Get a cached element function int Get( int Index ) { if ( !bCached ) Recache(); return CacheData[Index]; }
Related Topics
Comments
Vertigo: Is there a way to make an array of classes, such as array<class<Object>> MyArray?
MythOpus: Of course!
Wormbo: Just make sure you don't write ">>", but actually put whitespace inbetween: "> >"
Juxtapose: Taking it one step further, is it possible to have a dynamic array of a mutable class type? What I'm specifically trying to do is something like:
class SmallArray extends Object; var class myClass; var array<class <myClass> > data; //---or--- struct Pair { var int Position; var myClass Value; } var array<Pair> Pairs;
I'm trying to create something like a template class in C++ to use a data structure to hold an arbitrary object as the value. Any ideas?
Wormbo: The type array< class<X> >
will create a dynamic array of class values that are either class'X'
or any subclass of X. The type array<Pair>
will create a dynamic array of Pair structs. In both cases myClass
must be a type name (i.e. a class, struct or enum, but not variable!).
MythOpus: Does anyone know how memory 'efficient' Dynamic Arrays are? I haven't used them in quite awhile and need to load all PathNodes in a given level and add them to this array so I can randomly pick and choose a PathNode to do stuff with.
Wormbo: DynArrays take up capacity*elementsize bytes of memory, where capacity may be larger than the actual length of the array and elementsize in your case is the size of a pointer, i.e. 4 bytes in the 32 bit engine versions. Note that passing arrays as parameters or return values of functions or when assigning them to another variable makes a copy of the entire array.
EricBlade: MythOpus, try Controller.FindRandomDest() ?
MythOpus: Thanks for the suggestion but that function doesn't appear to exist? You can habe a cookie anyways though
SuperApe: (under Navigation functions) native(525) final function NavigationPoint FindRandomDest();
MythOpus: Ah... thanks. My 'find' didn't find it :|