750 likes | 892 Vues
Sega 500. Custom Scripted Actions. Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles. Thus far. We’ve played with both Scripted events and sequences for our pawns and found them to be quite similar.
E N D
Sega 500 Custom Scripted Actions Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles
Thus far • We’ve played with both Scripted events and sequences for our pawns and found them to be quite similar. • Not to mention that we had some fun making our bot get squashed and run in circles.
Today • Although the current actions list is quite extensive, without surprise, there is some functionality which is not included. • So we’re going to build our own.
What are we building? • Well, one of the few things thing that I found I could not do in the list was cause the creation of a pawn with AI. • Sure, we could create the pawn, but there was no attachment to a controller.
What are we building? • I’ve found 2 methods that work well to create a pawn at a specific location and both are fairly straight forward. • The first relies almost exclusively on the current functionality for adding bots
What are we building? • The second, has a bit more to it, but if gives more direct control over the pawns creation.
Setup • Both of the classes derive from scriptedaction class Action_CreateBot extends ScriptedAction; • These will auto-magically appear in the pull down menu of our actions list in the editor.
About Scripted Actions • Actually, setting up a new action is really quite easy. • All the magic happens around one function: function bool InitActionFor(ScriptedController C)
About Scripted Actions • Although there are a one or twocases where it is not used, it’s fairly safe to say that anything we want to implement will be called from here.
The easy way • Starting by getting the bot into the game at any player start point, we just need to call a few function that already exist in our game type.
The easy way • The trick lies in accessing these functions. • The ones we’re after are: • SpawnBot. • RestartPlayer. • Both of which are defined in the Deathmatch game type.
The easy way • The nice part is that any gametype we use will have this class as a parent.
The easy way • So how do we get there from here? • As you already know, the game is accessible from just about anywhere in the code. • It just takes some typecasting.
The easy way • I our case, we’re given a controller, which can see the level. • And the level knows about the game, so we can safely cast to our parent class. DeathMatch(c.Level.game)
The easy way • Cool! • So getting our bots in is just a matter of accessing these functions… local bot newBot; newBot = DeathMatch(c.Level.game).SpawnBot(); c.Level.game.RestartPlayer(NewBot);
The easy way • And this spawns our dude into the level when this script is hit. • And because we’re using the existing functions, all the initializations are taken care of for us…gota like that!
The easy way • But spawning him at a random start point is not always what we want. • So how to we tell UT where to spawn something?
The easy way • Well UT’s spawn function takes parameters, one of which is location…should be simple no? • Just do an allactors search and match up a tag to an object…simple.
The easy way • But there’s a problem. We don’t have an allactors iterator…can’t see it, can’t access it. • We derive off object, not actor where all our iterators are defined. • …so, does this mean we’re screwed?
The easy way • Well, no…the cost of admission just goes up. • Object has a single iterator for us to use. AllObjects <Shudder>
The easy way • So we can get to any object’s tag, we just have to iterate over ALL the objects in the game. • Expensive.
The easy way • It works just like any other iterator native(197) final iterator function AllObjects (class baseClass, out Object obj);
The easy way • So how do we us it then… • And inside the InitActionFor function: var(AIBOT) name loctag; // what we’re looking for
The easy way foreach AllObjects(class'Actor', A) { if( a.Tag==locTag ) { newBot = DeathMatch(c.Level.game).SpawnBot(); c.Level.game.RestartPlayer(NewBot); NewBot.SetLocation(A.Location); newbot.Pawn.SetLocation(A.Location) } }
The easy way • And TA-DA! It’s in! Spawn anywhere. • But there’s a *small* catch to this method. • The restartplayer call causes a spawn at the player start in the conventional manner
The easy way • An then we set the players location to where we want him. • However, this leaves the spawn effect at the start point.
The easy way • So this works, but we can’t have this effect happening where the player can see it. • On to method number two, which is quite similar. We just change the guts of the InitActionFor function.
A better way • And add a bit more in the set up. • This method also allows us to define which controllers and pawn we want to use. var(AIBOT) name objecttag; //Where to spawn var(AIBOT) class<bot> bType; //What Bot type var(AIBOT) class<Pawn> pType; //What pawn Type
A better way • And in the InitActionFor function, we redefine it as: function bool InitActionFor(ScriptedController C) { local bot newBot; local Pawn newPawn; local actor A; local UnrealTeamInfo BotTeam; local RosterEntry Chosen;
A better way • The UnrealTeamInfo and RosterEntry are needed to properly initialize the bot. • Everything else is a handle to an object that we’ll create here.
A better way • We keep the same search method…not much of a choice foreach AllObjects(class'Actor', A) { if( a.Tag==locTag ) {
A better way • Spawn a pawn and a controller at the desired loaction, based on our search result (Actor a) newBot = c.Level.Spawn(bType,,,a.Location, a.Rotation); newPawn = c.Level.Spawn(pType,,,a.Location, a.Rotation);
A better way • So they’re both in the game but need to be added to the game roster and initialized BotTeam=DeathMatch(c.Level.game).GetBotTeam(); Chosen =BotTeam.ChooseBotClass(); Chosen.Init(); DeathMatch(c.Level.game).InitializeBot(newBot,BotTeam , Chosen);
A better way • And lastly, we need the controller to own the pawn. This is done with the Posses function. newBot.Possess(newPawn);
A better way • Give it a run, it works nice… ...but there’s something missing…
A better way • The pawn comes in, with a brain, great! • But where the heck is the gun!
A better way • And, notice that once you frag them, spawn back into the game with all there toys. • So we missed something…
A better way • Actually, just one line…ain’t that always the way? • If you route through the deathmatch class you find this function AddDefaultInventory( pawn PlayerPawn )
A better way • And it does, just what the name says… • Accessing it is nothing new as well, DeathMatch(c.Level.game).AddDefaultInventory(newPawn);
A better way • Lastly, in our default properties, we need to set the ActionString to something meaningful. ActionString="Spawn EzeBot"
A better way • As best I can tell, the action string is used exclusively for debug purposes and this is the text that is thrown to the screen. • This is done from the ScriptedSequence object. Beyond that, I’ve not found any functionality.
That’s all well and good… • But, continually adding bots is only so much fun. • The real fun lies in killing them off
Killing our pawn • So, from our scripted sequence, time to do that. • This part is actually really easy if you controller already has a pawn associated to it…Well go over how to get one in a minute if it doesn’t.
Killing our pawn • So the new action I defined as: class Action_Gib extends ScriptedAction; function bool InitActionFor(ScriptedController C) { c.Pawn.ChunkUp(c.Pawn.Rotation, 1.0); c.Pawn.PlaySound(sound'PlayerSounds.Final.Giblets1'); return true; //must return true or UT crashes }
Killing our pawn • Yup, that’s the whole thing. • The actual kill is build into the pawn already, it’s just a matter of accessing it. • Can you guess what it does?
Killing our pawn • Before:
Killing our pawn • After: SPLAT! However, I am a bid confused as to how he got 2 skulls though…
Killing our pawn • Yup, it turns our pawn into a bunch of giblets. • The best thing is, you can now just add this to the list of Scripted events for your AIScript.
Killing our pawn • So long as you have a pawn associated with it that is…
Integration into Gameplay • Ok, I believe that it’s great for telling stories to the player and watching things happen. • But can the player interact with it? • In a word, yes.