790 likes | 922 Views
Sega 500. Creating a New Game. Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles. So far…. Ok, we’ve looked at how to access properties of the game to influence how it looks and plays by modifying the HUD and passing around the Udamage.
E N D
Sega 500 Creating a New Game Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles
So far… • Ok, we’ve looked at how to access properties of the game to influence how it looks and plays by modifying the HUD and passing around the Udamage. • In short, we looked at the pieces…not the whole.
Today… • We’re going to build on what we learnt so far and further modify the gametype rules and objects to create a complete new game. • That’s right…a complete gametype.
So here’s the plan • We’re going to run with the idea of the passing the UDamage around between players, but we’re going to change the *how*. • First off, the player who is killed first will drop the doubler for others to pickup.
So here’s the plan • The player who picks up the doubler is the only player who will be able to score points. • Anytime a player is killed, the doubler is recharged and informs all players in the game.
So here’s the plan • There will only ever be one of these *special* doublers in play at one time…we’re going to leave the regular pickup in game. • Anytime a player who has, the doubler is killed, all players in the game are informed that it has been dropped .
So here’s the plan • And, we’re going to modify the bot pathing information to give a high priority to acquiring this new damage doubler.
Getting started • As with any project, we need to figure out what we need to build. • Since we know the functionality we’re after, what kind things do we need to build or modify? Anyone?….anyone?
Getting started • We can roll this all up into a set of 4 files to cover • our game rules, • our menu interface, • a new item ( the doubler ) • the messages.
The new Gametype • This one is going to be similar to the one we’ve already created, but we’re going to modify it to influence the scoring. • In short have the double to score points. • This is also where we will cause the Doubler to be “dropped”.
The New UDamage • We’ll have to create a new UDamage class so that is plays nicely in our world. • It can’t respawn • It sends messages to the players
The New Message class • Sending messages in UT203 is done a bit differently to allow for network optimization. • In effect, we don’t send a sting across the wire, but an index value…more on this shortly
The New int file • Nothing really fancy here, just creating a new int file so that our game shows up in the menu as an option.
Building the Game • Just for good OOP I’m building from scratch. Create a new package for our code and in goes our gametype. • To keep it crazy, we’re going to derive from xDeathMatch.
Building the Game • This will create the basics game definition, no rules yet… • So lets get the int done so that we can select it from the menu and play test. [Public] Object=(Class=Class,MetaClass=Engine.GameInfo,Name=Eze.EzeGame, Description="DM|King of the hill MK2|xinterface.Tab_IADeathMatch |xinterface.MapListDeathMatch|false")
Building the Game • And at this point, it will play like a regular deathmatch. • So, lets go about changing that.
Building the Game • As always, start simple. • We’re going to override the Killed function again so that whenever a player is a doubler is created into the game.
Building the Game • So what’s this Spawn thingy and how’s it work? function Killed( Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> damageType ) { spawn(class'UDamagePack',,,KilledPawn.location); super.Killed( Killer, Killed, KilledPawn, damageType ); }
Building the Game • Well, Spawn is defined in the actor class as: native(278) final function actor Spawn ( class<actor> SpawnClass, optional actor SpawnOwner, optional name SpawnTag, optional vector SpawnLocation, optional rotator SpawnRotation );
Building the Game • Well, isn’t that just dandy, fortunate the header tells us a bit more: Spawn an actor. Returns an actor of the specified class, not of class Actor (this is hardcode in the compiler). Returns None if the actor could not be spawned
Building the Game • Ah, ok…so a spawn a UDamage pickup….cool. • But what’s this optional keyword stuff and how do I get it to be created where I want it?
Building the Game • Well, time to consult the good old UDN: With the "optional" keyword, you can make certain function parameters optional, as a convenience to the caller. For Unreal Script functions, optional parameters which the caller doesn't specify are set to zero. For native functions, the default values of optional parameters depends on the function. For example, the Spawn function takes an optional location and rotation, which default to the spawning actor's location and rotation.
Building the Game • In other words, you don’t have to pass in optional parameters…cool. • So in our spawn call, we’re telling to create the new object at the pawns location. spawn(class'UDamagePack',,,KilledPawn.location);
Building the Game • The result is, whenever you kill a bot, a doubler is spawned at that location. • Cool….nes-pas?
Building the Game • But this causes a small problem, very quickly we get a sea of damage doublers to play with. • Not exactly what we want, time to add some game logic to fix that.
Building the Game • Actually, the logic that we’re adding is surprisingly simple. • We’re going to use a similar method to the last king of the hill gametype.
Building the Game • In our global space for the gametype, we need a handle to the pawn who has the doubler: var pawn HasUDam;
Building the Game • And then, in the killed function, we add some logic… If the killed pawn had it, it’s now free for the taking if(killedpawn == HasUDam) { HasUDam=none; } if(HasUDam == none) { spawn(class'UDamagePack',,,KilledPawn.location); } else { HasUdam.EnableUDamage(30); } No one has it so drop one with this kill Someone else has made a kill
Building the Game • And this should work…But…like always, there’s a problem • Any ideas? Anyone?….anyone?
Building the Game • The damage doublers respawn…and this gonzo’s our “one doubler” rule. • NUTZ!
Building the Game • Don’t panic, we’re not dead yet. All this means is that we need a customized damage doubler class…not a problem. • All we need to do is derive a new class from the current damage doubler.
Building the Game • Digging this fella out of the class tree, we find it here, under pickups and derive a class off of it.
Building the Game • And there are 2 areas of interest the defaults and the touch function. • Don’t’ worry about the “auto state Pickup” line for now. We’ll be discussing states in great detail later on. • For the moment, it’s sufficient to know that the touch function gets called like any other function.
Building the Game auto state Pickup { function Touch( actor Other ) { local Pawn P; if ( ValidTouch(Other) ) { P = Pawn(Other); P.EnableUDamage(30); AnnouncePickup(P); SetRespawn(); } } } • Copy and paste the entire state group from UDamagePack into your new class.
Building the Game • In order to prevent the respawn, there’s one line we need to kill and one we need to add. • Comment out or delete the SetRespawn line. function Touch( actor Other ) { local Pawn P; if ( ValidTouch(Other) ) { P = Pawn(Other); P.EnableUDamage(30); AnnouncePickup(P); SetRespawn(); } }
Building the Game • And add a call to the destroyed function. • In effect, when the object is pickup up, the pickup item is removed from the game. function Touch( actor Other ) { local Pawn P; if ( ValidTouch(Other) ) { P = Pawn(Other); P.EnableUDamage(30); AnnouncePickup(P); //SetRespawn(); Destroy(); } }
Building the Game • And in the defaults, we just change the pickup message PickupMessage="Eze DOUBLE DAMAGE!"
Building the Game • And now going back into the gametype, we change the line where we spawn he UDamagepickup to spawn our own. spawn(class'EzeUDam',,,KilledPawn.location);
Building the Game • HAZA!!!! It works! Broadcast message…Well talk about this in a minute Pickup message
Building the Game • Now, we need to do one last thing to ensure that we can’t have multiple EzeUDam’s in play. • In our game type, we create a global handle to it. var EzeUDam dam;
Building the Game • And in our killed function, we modify it to check if anyone has it… • Remember, Spawn returns us an object. if(HasUDam == none && dam == none) { //toss the UDamage in to the air dam=spawn(class'EzeUDam',,,KilledPawn.location);
Building the Game • And don’t forget to add this line to the EzeUdam’s Touch function. • What were doing here is accessing the gametype and setting this parameter to which pawn made the pickup. EzeGame(level.Game).HasUDam=P;
Building the Game • All that this line does is access the current game and type cast it into our gametype so we can access the HasUDam parameter. • And, yes. We really should do some sanity checking here…Well cover this when we look at he “isa” function. EzeGame(level.Game).HasUDam=P;
Building the Game • Great! Now we on ever have on in play. • But this is kind of boring…just spawning the pickup like that… • Now that we have a hold of the object, what say we manipulate it some…
Building the Game • Just by adding a few lines to this function, we can fling it into the air when the player is killed. if(HasUDam == none && dam == none) { dam=spawn(class'EzeUDam',,,KilledPawn.location); dam.Velocity= 500*VRand(); dam.Velocity.Z= RandRange(500,800); dam.SetPhysics(PHYS_Falling); }
Building the Game • So what’s going on? Well, we’re changing some of its physics properties to give it a velocity dam.Velocity= 500*VRand(); dam.Velocity.Z= RandRange(500,800);
Building the Game • The VRand function returns to us a random direction. In fact a unit vector. Multiply this by a scalar to determine just where to toss it. • RandRange(500,800); gives us a number between 500 and 800 for the height. We over ride this since we don’t want to throw it downwards
Building the Game • And since we want to have this thing behave as thought there is gravity affecting it, we need to change it’s physics properties. dam.SetPhysics(PHYS_Falling);
Building the Game var(Movement) const enum EPhysics { PHYS_None, PHYS_Walking, PHYS_Falling, PHYS_Swimming, PHYS_Flying, PHYS_Rotating, PHYS_Projectile, PHYS_Interpolating, PHYS_MovingBrush, PHYS_Spider, PHYS_Trailer, PHYS_Ladder, PHYS_RootMotion, PHYS_Karma, PHYS_KarmaRagDoll, PHYS_Hovering, PHYS_CinMotion, } Physics; • Now, all the physics types are defined in the actor class…as you can see there are just a few to choose from.
Building the Game • Also, although we can see the physics property in the editor, it’s defined as const so the assignment operator will not work. • You have to use the SetPhysics function.