740 likes | 882 Views
Sega 500. Building Non-Bot AI. Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles. Thus far…. We modified some of the Bot’s AI properties by deriving a new class off of bot.uc and over ridding some of it’s states.
E N D
Sega 500 Building Non-Bot AI Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles
Thus far… • We modified some of the Bot’s AI properties by deriving a new class off of bot.uc and over ridding some of it’s states. • Where we managed to get some new functionality to take place.
However… • We quickly discovered the pain that is incurred from wrestling with the current AI system. • No easy way to insert new states or functionality into those 4500 lines of code.
Which leads us here… • Building our own AI in UT. From scratch! <GASP!>
That’s right! • Today, we’re going to implement that basic setup to build our own, stand alone, non-bot AI. • This is not by any means going to be a complete AI, as that is far beyond the scope of this course.
But Why? • Isn’t building our own AI a comparably large task? • I mean bot.uc was 4500 lines of code, shouldn’t we expect to have to write about the same?
Not Necessarily… • Writing an AI is really comparable to the length of a piece of string. • The more complex it it’s, the longer it gets…that simple.
This being said… • Bots are fairly complex beasties, hence those 4500 lines are some what appropriate. • However, as mentioned they are written to perform specific tasks and behave in a very specific manner…
Yet… • If you need an AI fro a Nali Cow or a Vorpal Bunny…erm…The bot AI may not be the best of choice. • And you should be able to build some decent functionality in considerably less.
That being said… • Time to get on down to the code. • But first, understand exactly what were after here. We’re throwing away all of the bot’s “brains” (such as they are) and are going to have no dependence on any AI decision processes other than the controller and the pawn.
That’s right… • No SquadAI, No TeamAI…nothing but the pawn and controller. And no…We’re not in Kansas anymore.
What we need… • The functionality we need comes from 2 classes. • A Gametype • A controller
The Gametype • Will be used for 2 things in this context (other than the base game rules). • It’s will specify which default controller the bots will use. • It’s also responsible for adding AI’s to the level.
The Gametype. • Setting up the gametype and the prebeginplay function should be pretty familiar to you by now. class EzeAIDM extends DeathMatch; function PreBeginPlay() { class'xGame.xPawn'.default.ControllerClass=class'EzeAI.EzeController'; super.PreBeginPlay(); }
The Gametype. • All that really goes on there is that we tell the default pawn which controller to use. • Do notice that I’m not deriving of xDeathmatch either. I doubt this will have an impact as xDeathmatch is used mostly for precaching…However the other gametypes off teamgame DO have additional functionality.
The Gametype. • Next I had to over ride the addbot function. • This function is called every time UT adds a new pawn to the game. • We really only had to change 2 lines of code to get it to spawn our AI.
The Gametype function bool AddBot(optional string botName) { local EzeController NewBot; if ( GameStats != None ) return false; NewBot = Spawn(class'ezeAI.EzeController'); …<SNIP>… if ( Level.NetMode == NM_Standalone ) RestartPlayer(NewBot); else NewBot.GotoState('Dead'); return true; }
The Gametype • Do notice that we are not spawning the pawn here. This is it’s controller. • A rather important distinction to make.
The Gametype • Lastly, just a little preventative coding… • Doing so prevents a bunch of “accessed nones” function UnrealTeamInfo GetBotTeam(optional int TeamBots) { return EnemyRoster; }
The Controller • The basics are really simple. • The bot will spawn at this point with nothing more than a declaration of the class. • And as expected it will be completely brainless.
The Controller • And yup…do an Addbot through the console and it tosses one in, no problem. • Now, if you kill it off, it will not respawn.
The Controller • Which, surprisingly enough is our 1st step into building the AI. • Here’s why, If you look at the addbots method in the game type you’ll see that there is a GotoState('Dead') call.
The Controller • You guessed it, we don’t have one of those… • Building one…well, I just grabbed the state labels from the one defined in bot. • Essentially, it just restarts the player.
The Controller state dead { Begin: if ( Level.Game.bGameEnded ) GotoState('GameEnded'); Sleep(0.2); TryAgain: if ( UnrealMPGameInfo(Level.Game) == None ) destroy();
The Controller else { Sleep(0.25 + UnrealMPGameInfo(Level.Game).SpawnWait(self)); LastRespawnTime = Level.TimeSeconds; Level.Game.ReStartPlayer(self); Goto('TryAgain'); } MPStart: Sleep(0.75 + FRand()); Level.Game.ReStartPlayer(self); Goto('TryAgain'); }
The Controller • So if we kill him off now, he should respawn without a hitch… • So! … We kill him again …
The Controller • Heh? What the… • Now there’s 2 of them?
The Controller • For some reason when I push the respawned one off the start point, another one immediately spawns in? • Well I’ll just kill off the one that just spawned in…
The Controller Oh my…
The Controller • Ok, why is it important to get this out of the way 1st off… • One of this mess of pawns is possessed by our controller…the others are just pawns with no brains at all. • I imagine you can see where this could complicate testing… I mean really…
The Controller • Fixing this is actually pretty simple… Even though it took me be a few hours to find it . • Right after the begin label, call this DestroyPawn(); • It will release the pawn and controller.
The Controller • This is likely not the best way to do it as it causes the controller and pawn to be respawned. But it suites our purposes just fine. • Currently, addbot gets called with every respawn…which is the root of the problem.
The Controller • Now that we’ve a brain for the pawn, lets go on about making it think so that it can interact with it’s environment. • Understand that AI’s in UT are, by default, blind, deaf and dumb. They have absolutely no senses what so ever.
The Controller • We have to build that for them. • Once again, since this is not an AI class, I’m simply going to talk about how to make them interact with their environment. Not do anything…intelligent.
Simple Brains • The functionality we’re going to build is just enough to cover that basics of how to get you AI to interact with it’s level • Using 4 basic algorithms (5 is you count dead.) All implemented via states. • Seek, avoid, wander and engage.
Simple Brains • The AI will have no method to navigate around obstacles or avoid hazards. • This is reserved for more advanced topics in AI.
Seek • When in this state the AI will move directly towards the player via the shortest route.
Avoid • The AI will maintain a set distance away from the player.
Wander • A brief look into how to get the AI to navigate the path network.
Engage • The pawn will simply turn to face the player, fire his weapon and perform a basic evade (dodge move).
Simple Brains • Now, I know this is not much when you look at it in its most basic parts, it looks overly simplistic. • However, these are the core abilities that allow the AI’s to behave and interact with their environment.
Simple Brains • From here, how big, smart and complex you choose to build your AI’s is up to you. • This is just the starting point.
Simple Brains • Starting with the Seek and avoid… • Both are really similar in their setup, heck, even their methodology… But we still need to look.
Simple Brains state seek { begin: MoveToward(otherP,,,true); sleep(1); goto('begin'); } • Seek: • The 1st step into AI navigation as we don’t really need to build anything new.
Simple Brains • The MoveToward function is defined it the controller base class which tells the AI to move towards any actor in the game…via the most direct route. • By using the goto, we loop it every second and update the postion. • The other parameters are for what the AI should look at and if they should walk.
Simple Brains • Notice that we are doing nothing with telling the pawn to play its walk animation. The xPawn class takes care of that for us…In this case anyway.
Simple Brains • We also need a way to get into this state so that it will chase the player down. • I could use the auto keyword, but I’d rather use the opportunity to introduce another funky little item.
Simple Brains • Also defined in the controller class, simple does what its name promises. • However, there is an interesting comment with them. event bool NotifyBump(Actor Other); // notifications of pawn events (from C++) // if return true, then pawn won't get notified
Simple Brains • So we can use this function as a trigger to prompt the controller to enter other states. event bool NotifyBump(actor Other) { if(other.IsA('Pawn')) otherP=pawn(other); gotostate('seek'); return false; }