I search for solutions in this order: Past Code, Unreal Source, Wiki, BUF, groups.yahoo, google, screaming at monitor. – RegularX
Legacy:Flow Syntax
Contents
Basics
There are two basic flow control functions in UnrealScript, GoTo and If...Else.
Any other functions and loops described here (except ForEach) could be replaced by combinations of these two functions (In fact, that happens in UnrealScript byte code for While, For and Do...Until loops.), but it's considered bad coding practise to actually do so.
If a loop, If or Else contains only one line of code the { } are optional. A single loop, If or Switch statement is treated as one command in this context.
Example:
If ( bExecute ) For (i = 0; i < 5; i++) { a += i; b *= i; }
Note: Due to a compiler bug it is not possible to use a loop (for, while, ...) as the statement in a simple else statement.
if (foo) bar(); else // Doesn't work, compiler error! for (i = 0; i < 10; i++) { blargh(i); }
You have to use a "block-else" instead, i.e.:
if (foo) bar(); else { // Actually the same thing, but works! for (i = 0; i < 10; i++) { blargh(i); } }
Stand-alone blocks, i.e. statements grouped in { }, are not allowed in UnrealScript.
Special Flow Commands
Return expression
The return keyword terminates execution of the function in which it appears and returns control (and the value of expression if given) to the calling function or state.
If the function returns a certain type of value the return value has to be specified in the return command. If a function with a return value ends without return it will return a null value for its data type. (e.g. 0
, empty string, None
, etc.)
Break
The break keyword terminates the smallest enclosing do, for, foreach, switch or while statement in which it appears. Code execution continues with the next line of code after the loop.
Example:
for ( Inv=Pawn.Inventory; Inv!=None; Inv=Inv.Inventory ) //Iterating through the inventory list { if( Inv != None && Inv.InventoryGroup == 1) //If there is an inventory item in Group 1 then... { //Destroy that item. That item will become 'None' after that, and will //Magically create an 'Accessed None' Error Inv.Destroy(); break; //To crush that Accessed none error, you must 'break' } }
Unlike some other languages (e.g. Java or Perl) UnrealScript does not support the break label; syntax to break the loop with the specified label.
Continue
The continue keyword passes control to the next iteration of the smallest enclosing do, for, foreach or while statement in which it appears.
Example:
While (i < 10) { if ( i % 2 == 0 ) Continue; log(i); }
Unlike some other languages (e.g. Java or Perl) UnrealScript does not support the continue label; syntax to skip to the next iteration of the loop with the specified label.
Stop
Imediately stops execution of State code. This is like the return command for states.
Assert (expression)
If the expression passed to Assert evaluates to False, the game shuts down with an error message telling you the file (class) and the line the Assert call is in.
Example:
Assert(numPlayers > 0);
GoTo (label)
Continues code execution at the specified label. GoTo is mainly used in state code, but is also allowed within functions, although it is rarely used there. For state flow there's also GotoState( Statename, label): see state for more on this.
Syntax:
GoTo('label');
Example:
State Idle { Begin: PlayIdleAnim(); FinishAnim(); Sleep(0.5); GoTo('Begin'); }
In UT2004 case the goto syntax varies. In function code the parentheses are invalid, apostrophes are optional. In state code the parentheses are optional, apostrophes are required. Therefore the syntax that's valid in both types of code is:
GoTo 'label';
If Statements
If statements execute some code if a certain condition is true. The optional Else part executes some other code if the condition is false. Multiple If...Else statements can be combined to create If...ElseIf...Else statements.
Syntax:
// single line if: if ( condition ) // statement // simple block if: if ( condition ) { ... } // if...else: if ( condition ) { ... } else { ... }
Example:
(The second If is the command executed if the first condition is false.)
If ( Pawn(Owner) != None && Pawn(Owner).bIsPlayer ) { log(Pawn(Owner).PlayerReplicationInfo.PlayerName); Pawn(Owner).PlayerReplicationInfo.Score += 2; } Else If ( Pawn(Owner) != None ) Owner.Destroy(); Else log("No Pawn.");
Switch Statements
Switch statements can be used to check if a certain expression is set to one of several values.
Syntax:
Switch ( expression ) { Case value1: ... break; Case value2: Case value3: ... break; Default: ... break; }
In this example a variable i is checked. If its value is 1 the DoSomething function is called and code execution continues below the Switch statement. If its value is 2 or 3 both DoSomethingElse and DoSomethingMore are called and the current function is canceled (due to the return command). If the value of i is 4 only the DoSomethingMore function is called and the current function is canceled. If i has a different value the DoNothingSpecial function is called and code execution continues below the Switch statement.
Note that without a break; or return; at the end of a case, execution will simply fall through to the next case's statements.
Example:
Switch (i) { Case 1: DoSomething(); break; Case 2: Case 3: DoSomethingElse(); Case 4: DoSomethingMore(); return; Default: DoNothingSpecial(); break; }
While Loops
While loops are executed as long as the condition stays true. If the condition is false before the loop starts, the whole While loop is not executed.
Syntax:
While ( condition ) { ... }
Note: Due to a compiler bug it is possible to append an Until(...); clause to a While loop, effectively turning it into a loop with two conditions – one executed before and one after each iteration. Please don't use this "feature" though, it might be removed in the future.
For Loops
For loops can be used similar to While loops. The InitialCommand is executed before the first loop cycle starts, LoopCondition is checked before each (including the first) loop cycle and UpdateCommand is executed at the end of every loop cycle. The For loop is executed as long as the condition stays true, but it will not be executed at all if the condition initially is false.
Syntax:
For ( InitialCommand; LoopCondition; UpdateCommand ) { ... }
Unlike other languages, UnrealScript does not accept multiple statements as InitialCommand or UpdateCommand. Additional initial commands must be added above the loop. Attempting to use multiple update commands can become very tricky if you want to use the Continue statement, but if you don't need Continue you can just add the additional update commands as the last statements of the For statement block.
Also unlike other languages, UnrealScript does not allow empty statements as InitialCommand, LoopCondition or UpdateCommand. Consider using a While loop instead if you don't need initial InitialCommand or UpdateCommand.
For loops can be used to make simple loops with a counter or to iterate through a linked list.
Examples:
For (i = 0; i < 10; i++) { ... }
The above example will execute for i = 0, 1, ... 9. The endgame scenario is:
- execute loop for 9
- increment i to 10
- start from the top: check i and it fails the condition; so move on.
The following example loops through all Pawns in the level: (works only server-side)
For (P = Level.PawnList; P != None; P = P.NextPawn) { ... }
If you were to rewrite a For loop only with If and GoTo statements, it would probably look similar to this:
InitialCommand; beginloop: if (LoopCondition) { /* loop code block */ continuetarget: // this is where a 'continue' statement would jump to UpdateCommand; goto 'beginloop'; } breaktarget: // this is where a 'break' statement would jump to
Do...Until Loops
Do...Until loops are always executed at least once. The loop stops if the condition becomes true.
Syntax:
Do { ... } Until ( condition );
Example:
Do { log(i); } Until (i++ > 10);
Note: Due to a compiler bug you can leave out the Until clause, effectively turning this into an infinite loop. It is not recommended to use this "feature" since it will probably be fixed in the future, but if you do you will have to add a Break or Return somewhere in the loop.
ForEach Loops
ForEach uses an iterator function to loop through a list of actors.
Syntax:
ForEach IteratorFunction(BaseActorClass, IteratorVariable, IteratorParameters) { ... }
IteratorFunction must be a valid reference to a native function with the iterator
specifier.
The first example iterates through all HUD actors in the map.
The second one iterates through all projectiles, which are in the same zone like the actor calling the ForEach loop.
Examples:
ForEach AllActors(class'HUD', H) { ... }
ForEach Region.Zone.ZoneActors(class'Projectile', P) { ... }
Note: If you access the iterator function through an object reference, make absolutely sure the reference is valid, becasue this is the only place where accessing None will not generate a warning but actually crash the game.
Another example for using ForEach:
RadiusActors - argument 1 actors (stored in argument 2 variable) which are in the argument 3 radius of the calling actor.
ForEach RadiusActors(class'Projectile', P, 128) { ... }
Discussion
EricBlade: I've never seen the 'stop' keyword. Does that return the object to it's default state (auto state, or no state)? Or does it remain in that state, with no state code running?
Wormbo: 'Stop' simply halts state code execution without changing states. There's actually an implicit 'Stop' after the last code statement in every state that contains state code.
Sweavo: UnrealScript Language Reference/Program Structure covers much of this material and it much prettier. I'm inclined to remove the subjects from here that are covered there then see what's left and refocus the page...?
Wormbo: UnrealScript Language Reference is only a copy of an Epic Games document that we are allowed to host here but not modify. This page here is our own description of these language constructs and it's much easier to link to from other pages.
Kartoshka: Just before the "Special Flow Commands" section there is a partial sentence "Statement blocks of". Is that just something that got left in one edit, or left out? I have no idea if it was important anyway...
Wormbo: I don't know what I wanted to write there. Removed it.