For people who consider themselves as programmers the following is completely obvious and not worth explaining. However, for those of us who are still learning how to program, functions have things in them that are completely obscure. In a previous tutorial we had a chunk of code which looked like this:
exec function MyCustomKismetEvent (){ local int i; local Sequence GameSeq; local array<SequenceObject> AllSeqEvents; GameSeq = WorldInfo.GetGameSequence(); if(GameSeq != None) { GameSeq.FindSeqObjectsByClass(class'SeqEvent_MyCustomKismetEvent', true, AllSeqEvents); for(i=0; i<AllSeqEvents.Length; i++) SeqEvent_MyCustomKismetEvent(AllSeqEvents[i]).CheckActivate(WorldInfo, None); } `log("MyCustomKismetEventactivated "); }
In the previous post about kismet sequences I had the following code in the player controller which went unexplained:
... exec function MyCustomKismetEvent (){ local int i; local Sequence GameSeq; local array AllSeqEvents; ...
These are called variables. The word local is categorized as a “keyword” that means that it’s a word the compiler is specifically looking out for and will treat differently from words it doesn’t consider a keyword. local means that you’d like to set aside a place in memory to put something into. The word following local tells the compiler what sort of shape you’d like that memory to be in.
In the first line in the function we have “local int i;” which means I’m asking for a place in memory in the shape of an int which is short for integer. Then I’d like to call this space in memory “i” which is a common letter used for integers. By the way, an integer is a whole number. Fractions or decimals aren’t allowed to go into an “int” because it’s the wrong shape, or what programmers call a “type.”
If i wanted to I can also declare multiple places in memory for integers using code that looks like this
... local int i,j,k; ...
This will make three places in memory, one named i, another j, and the last k. There are several number types which we can use. There are “ints” and “floats” which mean integer and floating point. There’s also a rarely used type called a byte, this is used for weapon fire modes. The difference is simple, bytes can only have whole numbers between 0 and 255; it’s an 8 bit number. an integer is a larger number from -2,147,483,648 to 2,147,483,647, this seems like a lot but there’s a catch. An int can not include a number like “1.01″ any number that has a decimal in it and any numbers to the right of a decimal point is considered a float.
floats are even larger numbers than integers, much larger. http://wiki.beyondunreal.com/Types#Float Refer to this page to look up more on types. It’s important to consider what you really need to use these numbers for before deciding what you want to do with them. For example, if you want to count bullets in a gun you should use the type int because it’s fairly useless to use 1.23 bullets per trigger pull. Likewise it’s also fairly strange be able to only move in 1 unit increments in a level. The other consideration that a programmer will tell you is important is the size of the memory you are requesting to set aside for use. Bytes use fairly little space in memory, ints use more than bytes, and floats use a lot more than ints. All things considered, a single 2048×2048 pixel texture will be considerably bigger than a bunch of floats you might use in your script, so I wouldn’t worry so much about this just yet. (yes, you embedded programmers worry about memory lots, but this is a video game engine where we’ve got PCs with more memory than your tiny hand held arm proc will ever know what to do with.)
In addition to assigning basic types like numbers and letters we can also create space for other scripts. The following line says “local Sequence GameSeq” this is something fairly interesting, and this is where programming really becomes powerful. You can hunt through Development/Src/Engine/Classes and find Sequence.uc for your self. In it it’s got a nice comment saying the following:
/** * Container object for all sequence objects, also responsible * for execution of objects. Can contain nested Sequence objects * as well. * Copyright 1998-2009 Epic Games, Inc. All Rights Reserved. */ class Sequence extends SequenceOp native(Sequence); ...
It’s talking about being a “Container” for all sequences and taking care of executing objects. Wow, that sounds pretty, well… obscure. In an object oriented world, an int is an object, so just as well, any other chunk of code can also be an object, objects also include other classes. A class is data which can be as complex as a character, or as simple as a single number. So like a number, a class like our sequence event can even be stored into memory as a variable.
So we have in the code we’re examining:
local Sequence GameSeq;This is a variable of a squence type which we’ve named GameSeq.
Next we have:
local array AllSeqEvents;Here we have a local variable named AllSeqEvents. However, this local variable looks to be declared with something new, “array” and some <>’s around the SequenceObject. What does this mean? Simply put, it’s a list. Conveniently an array is a numbered list. So if you add three objects to this list you can ask for the first one which is index 0, and you’ll get what was in list number 0. This is follwed by whatever might be in slot 1, then two. In this case, we made a list of sequence objects. Nothing has been assigned to this list yet, so it’s not yet interesting. But just so you know, an array can be declared with a preset number of items, or it can be left open to have any number of items added. It’s also important to know you can only have one type of object in an array, which means you can’t mix sequence objects and ints for an example.
Here I should remind you that you must always group all of your variables at the beginning of your function or class. After you’ve created places in memory to hold objects you can fill the spaces with the objects that already exist or with new data.
now we have a really interesting assignment to look at:
GameSeq = WorldInfo.GetGameSequence();
Okay, thus far we’ve been putting regular numbers int or float into a variable. However, remember objects can be other classes, this includes classes that actively do things. In this case, GameSeq is now assigned the function GetGameSequence(); which is a member of the class WorldInfo. GetGameSequence is a function that will find all of the kismet sequences in the level. It also happens that there’s a lot going on in C++ land under the hood of UDK so we can’t dig any deeper than that.
So what does it mean to have a variable GameSeq that has been assigned to being a function?
In the following we have the following:
if(GameSeq != None)
In a later tutorial we’ll dig deeper into words like “if” and “for” but for now it’s basically a way to check for the existance of data. This is asking “if GameSeq is not empty” then execute the following instructions. An if statement will only execute the code that lies between the curly brackets “{ }”. If the “if” statements conditions which are between the “( )” paranthesis then the code between the following curly brackets will not execute. In general it’s always good to have some sort of condition to meet before your code runs. Otherwise, your code is always running and that can eat up a lot of processor cycles.
Once we’re inside of our if statement we find GameSeq.FindSeqObjectsByClass(class’SeqEvent_MyCustomKismetEvent’,true, AllSeqEvents); This is a clever function that GameSeq gives us. Basically, we use it to fill in our array of sequenceobjects named AllSeqEvents with any object of the class SeqEvent_MyCustomKismetEvent. the true is in there to tell it to “yes, if you find one, put it into the array, kay, thanks…” There are a lot of functions that we’ll be using like this in UDK.
Okay, like I said, I’ll be digging into if and for a bit deeper later on. but next up we have a “for” statement that looks like this:
for( i=0; i<AllSeqEvents.Length; i++)
For statements are very common, and they usually look something like the previous statement. in the ( ) we have three parts. First is “i=0;” this fills the empty int we named before with a value. Then we have a condition “i < AllSeqEvents.Length;” this will determine if we’re going to continue to process the for statement. Integers can only be compared to other integers, in this case it’s asking if i is less than the length of the array AllSeqEvents, then execute this process. Some functions can convert objects into values and “Length” will make the for look think of the Array of sequence events as a number. This number was set when the GameSeq.FindSeqObjectsByClass filled in the AllSeqEvents with what it found in the game.
last is “i++” which means after we process the for statement we’re going to increment i + 1. There are a lot of “operators” which we can use on numbers. ++ and — are operators which work on integers. We’ll go into more detail on these sorts of tricks in a later tutorial, but for now we’re going to just think of i++ as a way to increase the value of i by one each time the compiler runs the for statement.
To step through this, we’ll look at what the code is “thinking” because this is what’s called a loop.
As an example we’ll say that GameSeq.FindSeqObjectsByClass found 2 sequences to put into the AllSeqEvents array.
So the for loop happens and it says:
i is now 0
is i less than the length of AllSeqEvents? AllSeqEvents is 2, yes it is.
lets do the process inside of the curly braces…
Im done with the processes in the curly braces.
i is now 0 + 1.
is i less than the length of AllSeqEvents? AllSeqEvents is 2, yes it is.
lets do the process inside of the curly braces…
Im done with the processes in the curly braces.
i is now 1 + 1=2.
is i less than the length of AllSeqEvents? AllSeqEvents is 2, no it is not.
im not going to do anything…
okay, so why doesn’t it just reset i to 0 each time the for loop thinks? It’s just not made to, otherwise it would be useless. What happens when it quits? Nothing special, for loops dont require anything other than just doing what they’re supposed to until they’re done. The for loop will only execute as long as i is less than the length of the array. if i = 2 and the array is 2 objects long then i is equal not less than 2. There are other ways to compare numbers but we’ll dig into that in a later tutorial.
inside of the for loop we have:
SeqEvent_MyCustomKismetEvent(AllSeqEvents[i]).CheckActivate(WorldInfo, None);
There’s another i inside of that function. This line activates the item in the array. lets revisit the for loops thought process.
i is now 0
is i less than the length of AllSeqEvents? AllSeqEvents is 2, yes it is.
Activate AllSeqEvents[0].
i is now 0 + 1.
is i less than the length of AllSeqEvents? AllSeqEvents is 2, yes it is.
Activate AllSeqEvents[1].
i is now 1 + 1=2.
is i less than the length of AllSeqEvents? AllSeqEvents is 2, no it is not.
im not going to do anything…
When the for loop repeats the i value has been incremented for everyone inside of the for loop as well. Array items can be addressed in this fashion. Array item number 0 is the first one in the array. So if you want to ask the first item in the array to do something you need to talk to it as Array[0].doSomething(); to have it do something for you. This assumes that the object in the hypothetical “Array” has a function in it called doSomething. You can’t ask the array it self to perform any tricks. For instance Array.doSomething(); will not work. Array’s can’t “doSomething” because the Array class can only do things like Array.Length for example.
I tried to avoid anything that would have diverted our attention from the dissection of the function. Things like ++ and < are just the basics of things called operators. I promise i’ll cover how these work later. There is a `log(); in there, But that’s not all that important how that works just yet. But it’ll matter once we start debugging!