Monday, July 1, 2013

Using Delegates in UnrealScript

A delegate in UnrealScript is a type of variable that references a function. With the use of delegate is possible to set the function that should be called during the execution of the game.

Before we create a new delegate we will first use one that is already defined in Unreal Engine 3.

A Dynamic Array has a function to sort its data. This function takes as a parameter another function that will be stored internally in a delegate. The description of this function in the UnrealScript Language Reference is as follows:

"Sort(SortDelegate): uses SortDelegate to sort the contents of the array in-place. SortDelegate should have signature matching the following:

delegate int ExampleSort(ArrayType A, ArrayType B) { return A < B ? -1 : 0; } 
// a negative return value indicates the items should be swapped"


This description tells us to create a function that takes two parameters of the same type that is used in the Dynamic Array. We need to compare the two parameters and return a negative value if the items need to change position.

The function is using the ternary operator "? :" which is a type of "if" command abbreviated. The expression "A < B ? -1 : 0" means that the comparison before the "?" will be evaluated. If the result is true, then the resulting value will be the first, which in this example is "-1". If false, the resulting value will be the second, which is "0". It is important to note that in this example the list will be in descending order. That is, the highest values ​​will be first in the list.

The function that is created does not need to have the word "delegate" in its definition.

Now imagine that we have in our game a Dynamic Array of Pawns as below:
var array <Pawn> pawnList;

We want this list to be sorted by the Pawn's Health attribute. The Pawns with more health must be at the beginning of the list.

Example function to sort the Pawns.
function int SortPawn(Pawn A, Pawn B)
{
    local int result;
          
    if(A.Health < B.Health)
    {
        result = -1;
    } 
    else 
    {
        result = 0;
    }
    
    return result;
}

The same function can be written in another way:
function int SortPawn(Pawn A, Pawn B)
{
    return (A.Health < B.Health) ? -1 : 0;
}

To sort you must call the Sort() function of the Dynamic Array:
pawnList.Sort( SortPawn );

Now let's learn how to create a new delegate. To define a delegate in a class do so:
delegate delegateName( parameters ... );

To define a function that takes a delegate as a parameter:
function functionName( delegate< delegateName > delegateParameter)
{
}

In the example below it was created a delegate that will be called when a player (UTPawn) is dying. This delegate can be used to notify some other class in the game that need to perform an action when this happens.
class UTPawnDelegate extends UTPawn;

delegate notifyDeath( Pawn player ) ;

function SetDelegate( delegate< notifyDeath > newDelegate)
{
    notifyDeath = newDelegate ;
}

simulated function PlayDying(class<DamageType> DamageType, vector HitLoc)
{
    Super.PlayDying( DamageType, HitLoc );
    
    notifyDeath( self );
}