Learning UnrealScript Part 3 – Your First Class

Just as promised, in this installment I’m going to walk you through writing your first class, which will eventually become the base for a custom AI. Before we start I must let you know that although I have done a LOT of work with UnrealScript (custom weapons, custom menus, etc.), I have never worked with AI. And this is a good thing for you because I’m actually going to be learning the system as we go along, and I’ll offer insights into not only the “what” but the “why” and the “how”.

One of the reasons I’ve avoided messing with UDK’s AI is its size. Open up Windows Explorer and navigate to \Development\Src\UTGame\Classes\UTBot.uc — it’s a 164 KB file, one of the biggest in the entire game. That translates to over 6000 lines of code. For a programming newbie, the task of writing a custom AI based on such a class would be daunting.

But alright, suppose we wanted to do it anyway. Open your favorite programming IDE (mine is WOTGreal, available for download here: http://www.wotgreal.com/, but you could just as easily use Notepad) and open up UTBot.uc. The first non-commented line in the entire file is:

class UTBot extends UDKBot dependson(UTCharInfo);

Whenever you make a new .uc file, the first line of code must always be of this type. It may not include the extra “dependson”, but at the very least it should say class [your class name] extends [another class name]. And you should save your file as [your class name].uc. So, let’s open up a new file and save it as MyBot.uc in the folder \Development\Src\MyGame\Classes\. The first line of this file will be:

class MyBot extends UTBot;

We don’t need to rewrite the “dependson” because the parent class has already done that for us, but we DO need to specify the parent class (in this case UTBot). Now let’s go back to UTBot.uc and study its contents a bit more.

Under this first line of code there are a whole bunch of lines that say something like “var [blah blah blah]”. These are (you guessed it) variables global to this class. In UnrealScript, you can declare such global variables and allow them to be used by any of the functions in the class (as well as other classes, but we’ll get to that later) — the only requirement is that they are written at the start of the file, before all of the functions. The format is simple: var [type] [name]. For example, “var bool bHuntPlayer” is a variable called bHuntPlayer that is a boolean: it can only store either ‘true’ or ‘false’.

Then come the functions, which are of the type function [type] [function name] ([parameter 1], [parameter 2], etc.) {}. The only requirement is the function’s name. [type] is optional, and it declares what kind of variable this function returns. The parameters are also optional, and it declares the variables the function takes as inputs. So a function that just does something (no input/output) could be: “function DoStuff() {}”. You don’t need to write “void” or anything like that.

Inside functions you can declare local variables, which are only accessible by that function. They are of the form local [type] [name]. Like the global variables described earlier, they must come before anything else in the function, so always declare them first.

Now scroll all the way to the bottom of the file, and you’ll see a thing called defaultproperties {} with a bunch of stuff between the brackets. This is (as far as I know) a thing unique to UnrealScript: here is where you declare all the default values for global variables. When the class is first initialized in-game, the variables that have defaultproperties values will be given those values, and all others will be set to null.

Alright, let’s actually do something. One of the first things I noticed about UTBot.uc when I opened it up was the section of variables that looks like this:

var float BaseAlertness;
var float Accuracy;
var float BaseAggressiveness;
var float StrafingAbility;
var float CombatStyle;
var float Tactics;
var float ReactionTime;
var float Jumpiness;
var class<Weapon> FavoriteWeapon;
var float OldMessageTime;

Epic Games is practically giving you the keys to the AI kingdom right here; just flip a few of these values and suddenly you’ve got a totally different AI. Intrigued, I decided to research further by Ctrl+F’ing “CombatStyle”. On line 1500-something, I found this:

CombatStyle = FClamp(BotInfo.AIData.CombatStyle, -1, 1);

I noticed that “BotInfo” was just the input parameter to the function I was in:

function Initialize(float InSkill, const out CharacterInfo BotInfo) {}

Researching CharacterInfo took me to UTCharInfo.uc, which extends Object and, more importantly, has a config(CharInfo) modifier. This means that it saves and draws its data via the config files, more specifically the CharInfo config file. Hop on over to \UDKGame\Config\DefaultCharInfo.ini to see for yourself: all the bot characters that you play against in UDK, each with specific settings on Accuracy, Jumpiness, and more.

Of course, I had already seen this config file a billion times before, so why go through all this? The answer is because it’s a prime example of something you’re going to have to do all the time when you’re coding UnrealScript: jump from file to file, following the path that a variable or function takes through the system, to understand what it does. Even if I had never seen UDK before, using this strategy I could have figured out how UDK grabs the values for each bot from the config file and uses them in its AI code.

While you’re in the config files, notice also how not all of the bots have custom AIData values. In particular, most of them are lacking the Aggressiveness value. So head on back to your custom file, MyBot.uc, and add this:

defaultproperties
 {
 Aggressiveness=+00000.70000
 BaseAggressiveness=+00000.70000
 CombatStyle=+00000.80000
 }

Remember that the default values in UTBot were around 0.2-0.4; this is almost double. In other words, now you’re going to have insanely aggressive enemies fighting you, and according to their combat styles they will almost always rush you.

One last problem: how to actually get this in game? To do that, UDK is going to have to recognize this custom file. Open up a new file and call it MyGame.uc, then add:

class MyGame extends UTGame;
defaultproperties
{ 
BotClass=class'MyGame.MyBot'
}

Notice how the “.” operator discussed in the previous tutorial comes into play here. We are referencing the MyBot class that is in the folder \MyGame\Classes\, so our string becomes MyGame.MyBot.

Finally you’re going to need to have Frontend recognize that your new files exist, so open up the config file DefaultEngineUDK.ini and add the line +EditPackages=MyGame right under the line +EditPackages=UTGameContent (Ctrl+F it if you need to). Then, save a close DefaultEngineUDK.ini and delete UDKEngine.ini. That’s right, I said delete: UDK rewrites any missing .ini files with the default ones, and we want our changes to take effect.

With that done, open up UDK Frontend and recompile. Now you’re ready to try out your crazy new AI in a map of your choosing. Just open the map in the editor, go to View –> World Properties, change the “Game Type for PIE” to “MyGame” and play in the editor! Wow, custom AI without even a single function written!

Okay, so it’s not the best AI in the world…and not really suitable for a game, either. Next up we’ll begin improving on the AI by writing some functions. We’ll also begin to look more into the UDK class tree and see how different groups of classes interact.

Previous: The UDK Directory
Next: Building an AI Class

26 thoughts on “Learning UnrealScript Part 3 – Your First Class

  1. Pingback: Learning UnrealScript Part 2 – The UDK Directory | WillyG Productions

  2. Pingback: Learning UnrealScript – Introduction | WillyG Productions

  3. Hey um i have a problem and a question. Am i supposed to make the MyGame folder and the Class folder inside that, or should it already be there?

    And also, i don’t have +EditPackages=UTGameContent , but i do have …=UDKBase and …=UTEditor.

    • no, you’re supposed to make it. of course you could name it whatever you like, just make sure to refer to it by that name everywhere in your code

      hmm they might have changed it for later versions of UDK. just put it under the last line of that section (so i’m guessing under =UTEditor)

      • Okay thanks! And i have a bit of an unrelated question. Ok so when I tried to build my level, it said couldn’t find importance volume. So I searched the internet for a solution and I placed an importance volume all around my entire level (skybox too) which I probably shouldn’t have done, but anyway after i did that it stopped building at lightmass and it wouldn’t go any further. It went on like that for a few hours 😦 any ideas?

    • hmm seems i can’t reply to the other one…
      anyways, you should NEVER make an importance volume that big. the reason why it takes a few hours is because you’ve basically made the entire level “important”. what you should do is decide what parts of the level the player will play in the most, then put a volume only around that area…the smaller the better 😛

      • Hey, I deleted the huge volume and made a smaller one, but it’s still not taking as fast as before, I don’t know if this is right but it’s been building for 2 minutes and the swarm agent is in the blue.

      • by the way here’s the end of the log:

        9:34:30 PM: Calculate Irradiance Photons complete, 0.008 million irradiance calculations in 0.2 seconds
        9:34:30 PM: Lighting 13.2%
        9:34:30 PM: Lighting 26.4%
        9:34:31 PM: Lighting 35.4%
        9:34:32 PM: Lighting 44.4%
        9:34:32 PM: Lighting 53.4%
        9:34:33 PM: Lighting 68.7%
        9:34:33 PM: Lighting 70.6%
        9:34:33 PM: Lighting 81.0%
        9:34:34 PM: Assertion failed: MappingContext.FirstBounceCache.InterpolateLighting(RepresentativeVertex, FALSE, FALSE, IndirectLighting) [File:.\Lighting\Src\VertexMapping.cpp] [Line: 965]
        9:34:34 PM:
        9:34:37 PM: Lighting 90.0%

    • having it in the blue after 2 minutes is perfectly normal, especially for bigger maps. i’ve never seen an error like that before so i did a little research…

      it seems that most of the problems with “mappingcontext” have to do with how much RAM you have. lightmass caches RAM to do the indirect lighting (which takes the most memory) beforehand, and if it doesn’t have enough it fails. not sure how to go about solving that problem, tho. it looks like you already tried all the solutions in the book :/

  4. Pingback: Learning UnrealScript Part 4 — Building an AI Class | WillyG Productions

    • This will be hard, since lightmass importance volume is tied to lighting. So any changes you do make in unrealscript won’t take effect dynamically.

      If you mean extending lightmass importance volume and adding stuff to it, then sure, it works just like any other class.

  5. If say.. we named our MyGame.uc something else like the game name.. for comical purposes let’s pretend I named it YogibeareatsbabiesGame.uc
    if i named the bot file MyBot.uc
    would that mess something up? should i have named it YogibeareatsbabiesBot.uc ?
    Also in the tutorial after this when you say start fresh.. does that include clearing out the parts you said will be in EVERY class? Even though you said get rid of all that agressive nonsense from last time?.. this is all very confusing and I haven’t gotten anything to work.. im not sure if i’m even compiling correctly, I open up Unreal Frontend, I click the thingy that says compile, Full Recompile and then I wait for it to be like Hell yeah my brother, I compiled it all successfully, so I respond to Frontend, Thank you FrontEnd, you’ve been very helpful this evening. (But in reality I’m just sad because nothings working.)

    • No, as long as inside the defaultproperties in YogibeareatsbabiesGame.uc you have the line BotClass=class’MyGame.MyBot’ (and assuming the folder all this code is in is called “MyGame”).

      When I said starting fresh in the Part 4, I meant rewriting the Bot class. You will still need a MyGame class like the one given here to compile things.

      Also appreciate the humor, but I can’t help you if I don’t know what the specific problem is. What errors is FrontEnd giving out?

  6. P.S. explaining the actions you tell us to take instead of telling us how much the final product sucks or is annoying would turn this frown upside down. 😦 but i know this whole thing is really old.

    • Yeah, well…the tutorial’s not supposed to help you make something useful or “good”, it’s supposed to be a way to teach absolute beginners about OOP and things like variables, states, config files, etc. by using an example.

      Unfortunately most simple examples will suck. 😛

  7. I get an error when compiling: Error, Superclass UTBot of class MyBot not found
    and the same for the MyGame class. what am I doing wrong?

Leave a reply to Optimusconvoy Cancel reply