Showing posts with label udk. Show all posts
Showing posts with label udk. Show all posts

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 );
}

Wednesday, May 22, 2013

Using Dynamic Arrays in UnrealScript

Dynamic Array is a collection of data items that can be resized during the execution of the game.

A Dynamic Array is a variable type declared as follows:

var array < arrayType > arrayName ;

The array type can be primitives such as int and float or any class such as Actor and Pawn.

A Dynamic Array can also be defined as local variable within a function using the keyword "local".

The current size of a Dynamic Array can be found in their Length attribute. Access to the individual elements of a Dynamic Array can be done with an index in the same way as in a static array. Remember that the index of an array always starts from 0.

A simple example using Dynamic Array:
class EnemyTypes extends Actor;

var array <int> enemyTypeList;


function int getEnemyType(int index)
{
    if(index < 0 || index >= enemyTypeList.Length) 
    {
        return -1;  // Error: Invalid Index
    } 
    else 
    {
        return enemyTypeList[ index ];
    }
}

function setEnemyType(int index, int enemyType)
{
    if(index >= 0 && enemyType >= 0)
    {
        enemyTypeList[ index ] = enemyType;
    }
}

Note that in the above example, in the function setEnemyType(), there is no problem if the index is greater than the current size of the array, because a Dynamic Array will increase its size to store the required index.

There are some functions that are part of a Dynamic Array. Below are the main ones:

  • AddItem( Element ): Adds an Element to the end of the Dynamic Array. The Element must be the same type of the Dynamic Array.
  • RemoveItem( Element ): Removes an Element of the Dynamic Array.
  • InsertItem( int Index, Element): Inserts an Element in the Dynamic Array at the specified index.
  • Find( Element ): Search for the Element within the Dynamic Array and returns the index of the found element, or "-1" if not found.

I did an example that creates a random amount of Shield Belts (class UTGameContent.UTDroppedShieldBelt) in random positions. The Shield Belts instances that were created are added to a Dynamic Array. After creating all Shield Belts, the Dynamic Array is iterated using the ForEach operator to register in the Log the position of each Shield Belt created.

Code and image of this example:
class TestDynamicArrays extends UTGame;

var array <UTDroppedShieldBelt> shieldList;

function StartMatch()
{
    local UTDroppedShieldBelt shieldInstance;    
    local vector shieldLocation;
    local int totalShields;    
    
    super.StartMatch();

    totalShields = 10 + Rand(10);     
    
    do
    {
        //Choose a random position
        shieldLocation.X = -1000 + Rand(2001); //-1000 to 1000;
        shieldLocation.Y = -1000 + Rand(2001); //-1000 to 1000;
        shieldLocation.Z = 50 ;
    
        shieldInstance = spawn(class 'UTGameContent.UTDroppedShieldBelt', , ,shieldLocation);
        
        shieldList.addItem( shieldInstance );        
                
    } until ( shieldList.Length == totalShields ) ;
    
    `Log("TOTAL OF SHIELDS =" @ shieldList.Length);
    
    //write in the log the position of all shields
    foreach shieldList( shieldInstance )
    {
      `Log( "Location =" @ shieldInstance.Location );
    }
}


This log shows what was registered in one of the executions of the example.
[0294.02] ScriptLog: TOTAL OF SHIELDS = 18
[0294.02] ScriptLog: Location = -390.00,183.00,50.00
[0294.02] ScriptLog: Location = -946.00,-300.00,50.00
[0294.02] ScriptLog: Location = -101.00,133.00,50.00
[0294.02] ScriptLog: Location = 225.00,701.00,50.00
[0294.02] ScriptLog: Location = 611.00,-908.00,50.00
[0294.02] ScriptLog: Location = -650.00,-532.00,50.00
[0294.02] ScriptLog: Location = -550.00,449.00,50.00
[0294.02] ScriptLog: Location = -245.00,531.00,50.00
[0294.02] ScriptLog: Location = 307.00,-890.00,50.00
[0294.02] ScriptLog: Location = -14.00,-534.00,50.00
[0294.02] ScriptLog: Location = -191.00,101.00,50.00
[0294.02] ScriptLog: Location = -756.00,832.00,50.00
[0294.02] ScriptLog: Location = 796.00,390.00,50.00
[0294.02] ScriptLog: Location = -833.00,-915.00,50.00
[0294.02] ScriptLog: Location = 780.00,-248.00,50.00
[0294.02] ScriptLog: Location = 492.00,841.00,50.00
[0294.02] ScriptLog: Location = 461.00,-526.00,50.00
[0294.02] ScriptLog: Location = 179.00,-266.00,50.00

Monday, April 15, 2013

Iterating with ForEach in UnrealScript

Before talk about iteration let's imagine an example. Say you built a game that in the levels there are several UTWeaponPickupFactory actors, but only one of them will have a special behavior that will be programmed in UnrealScript.

The UTWeaponPickupFactory class is found in this class hierarchy:



For this example I will place in the level several UTWeaponPickupFactory actors as shown in the image below.



I selected one of the UTWeaponPickupFactory actors, opened the Properties Window (F4 key) and set the "Tag" property with the value SPECIAL_FACTORY. This Tag property is in the Object category as seen in this image.


When starting the game we need to iterate through all the UTWeaponPickupFactory actors until find the one that has the value SPECIAL_FACTORY in the "Tag" property. When find it we will store the object reference of the current UTWeaponPickupFactory actor to be able to handle it in UnrealScript.

That's what this code does.
class TestIteration extends UTGame;

var UTWeaponPickupFactory SpecialFactory;

function StartMatch()
{
    local UTWeaponPickupFactory factory;
   
    Super.StartMatch();
   
    foreach DynamicActors( class'UTWeaponPickupFactory', factory )
    {
       
      if( factory.tag == 'SPECIAL_FACTORY' ) 
      {
        SpecialFactory = factory;
        break;     // Ends the search
      }
    }
    
    Broadcast( self, " Object Name =" @ SpecialFactory.name) ;    
}

To test this code in UDK set the Game Type to "TestIteration". (UDK Menu: View -> WorldProperties -> Game Type

The "foreach" command works with one type of function known as Iterator. These functions have two parameters, the first parameter specifies the type of actor that it should search and the second is a variable that will receive the reference of the current actor in each iteration.

DynamicActors() is the most used iterator function. It searches in the Actors that are not StaticMeshActor. There are several other iterator functions. The main iterators are declared together in the Actor class, just search for "iterator" in the file Actor.uc.

There are other important iterators declared in the WorldInfo class (Actor->Info->ZoneInfo->WorldInfo). To use them you need to put a variable of the type "WorldInfo" in front of the iterator function name. All Actors have a "WorldInfo" variable. Code Sample:
//Extract from GameInfo.uc (Actor->Info->GameInfo)

function StartBots()
{
    local Controller P;

    foreach WorldInfo.AllControllers(class'Controller', P)
    {
        if (P.bIsPlayer && !P.IsA('PlayerController'))
        {
            if (WorldInfo.NetMode == NM_Standalone)
            {
                RestartPlayer(P);
            }
            else
            {
                P.GotoState('Dead','MPStart');
            }
        }
    }
}

Sunday, October 9, 2011

UDK Game Programming: UnrealScript

I'm starting a series of tutorials about UDK Game Programming with UnrealScript. The UDK (Unreal Development Kit) can be downloaded at this link: www.udk.com

UnrealScript is an object-oriented language like Java, but it has many new features targeted for the implementation of games.

Programming a new game with UnrealScript can be very complex, but as Lao Tzu said:

"A journey of a thousand miles must begin with a single step."