CaptureVolume
Linking Volumes and Control points
Or, how I learned to stop worrying and love my volume!
Goes without saying, but if you sample any of this code please give me credit somewhere in your script. Also, note that I'm not the cleanest coder in the world, so be sure to check and double check! Share the love baby!
The origin of this page comes from a project I'm currently working. For the mod, it was necessary to track player position and then have an icon fade in and out on the hud. I'm not going to go into the fades right now since that's a whole monster to itself. What I'm going to focus on is how to link a control point to a capture volume and, using the two, get it to display icons onto the HUD.
Props go to the Adster. Visit his page @ http://www.speakerprojects.com/index.html and tell him he's sexy.
Writing the code
You need to create some new UnrealScript classes. You can either:
- Create a subclass in UnrealEd for each of the following scripts,
- or [Create a package]? containing all these classes.
The first thing you want to do it create your volume subclass. The volume will be used to track when a player enters the space.
/* Extended Volmue Class Graham Ross 9/21/04 An extended volume class to help display the names of rooms on the HUD */ //Graham Ross (thanks Adster!!!) //An interactive volume to trigger elements on the HUD // 10/13/04 //============================================================================= class captureVolume extends PhysicsVolume; var( ) Int captureVolumeNumber; var CapturePoint ourCapturePoint; var int volumeNumber; var bool inVolume; simulated function PostBeginPlay( ) { local NavigationPoint nP; Super.PostBeginPlay( ); for( nP = Level.NavigationPointList; nP != None; nP = nP.NextNavigationPoint ) { if( !nP.IsA( 'CapturePoint' ) ) continue; if( CapturePoint( nP ).capturePointNumber == captureVolumeNumber ) { ourCapturePoint = CapturePoint( nP ); ourCapturePoint.SetMaster( self ); break; } } } event PawnEnteredVolume( Pawn other ) { if( ( other.IsPlayerPawn() ) && ( ourCapturePoint != None ) && (other.PlayerReplicationInfo != none)) //is the problem that the capt. point is none? { if( customPawn( other ) != none ) rscPRI(other.PlayerReplicationInfo).cVolumeNumber = captureVolumeNumber; ourCapturePoint.Touched( other); } } event PawnLeavingVolume( Pawn other ) { if(( other != none )&& ( ourCapturePoint != None )&& (other.PlayerReplicationInfo != none)) { if( customPawn( other ) != none ) rscPRI(other.PlayerReplicationInfo).cVolumeNumber = 0; ourCapturePoint.Untouched( other); } } defaultproperties { captureVolumeNumber=255 volumeNumber = -1; }
So you'll notice there are a few things I'm keeping track of. First, in the PostBeginPlay, I'm cycling through all the NavigationPoints in the scene. If it's a "capture point", I proceed forward and match up the number of the capture points to the number of the volume, two attributes I've custom set. You'll also notice I have two checks for whether the pawn enters or leaves a volume. This is the most important part of the code. When a player enters the volume, it calls "touched" or "untouched" from the capture point. We'll get into that part shortly.
Also, notice that I've set captureVolumeNumber and Volume number to 255 and -1, two out of range types.
Now, let's create a control point to link it to
// Graham Ross (Thanks Adster!!!) // class for altering the function of GameObjective. // //============================================================================= class CapturePoint extends GameObjective Placeable; var( ) localized String captureName; var( ) Name captureEvent; var( ) Int capturePointNumber; var CaptureVolume captureVolume; simulated function PostBeginPlay( ) { Super.PostBeginPlay( ); } function SetMaster( CaptureVolume ourCaptureVolume ) { if( ourCaptureVolume != None ) captureVolume = ourCaptureVolume; } function Touched( Pawn other) { } function Untouched( Pawn other) { } function ResetPoint( Bool bEnabled ) { } defaultproperties { bHidden=False capturePointNumber=-1 captureName="A Capture Point" bUseCylinderCollision=True RemoteRole=ROLE_SimulatedProxy bAlwaysRelevant=True bStasis=False bStatic=False bNoDelete=True bNetNotify=True CollisionRadius=60.000000 CollisionHeight=40.000000 DrawScale=0.60000 bCollideActors=True bBlockActors=False bBlockPlayers=False NetUpdateFrequency=8 ObjectiveName="Capture Point" }
You'll notice there's not much there. Basically the only thing I want is the touched and untouched function. This will allow me to interact easily with the HUD and draw upon it. I personally wasn't able to find a way to interact solely using the volume and the HUD. It's also helpful to note that the triggering is not done by the conrol point, but done by the volume who then interacts with the point.
Also, you must create a custom PRI?(Player Replication Info) for your player to hold a single variable that will track the volume number.
// Graham Ross // 10/13/04 // // Custom PRI to use with my volume and my hud class rscPRI extends xPlayerReplicationInfo; var int cVolumeNumber; defaultproperties { cVolumeNumber = 0 }
The last code you got to put in is some way to draw on the HUD obviously! I'm using a HUD interaction here, in my opinion the best way to draw on the HUD.
At the top, decalre something like this:
var enum volumeNo { VN_None, VN_Bal1, VN_Bal2 } VNStatus;
Later, do something like this...
simulated function checkGlowVariable(canvas c) { switch(rscPRI(pOwner.PlayerReplicationInfo).cVolumeNumber) { case 0: VNStatus = VN_None; fadeout = true; break; case 1: VNStatus = VN_Bal1; fadeout = true; break; case 2: VNStatus = VN_Bal2; fadeout = true; break; default: } }
then later do soemthing like this in drawhud() or a separate function:
simulated function checkGlowInfo() { local byte tempStyle; local color tempColor; glowMoveX = shiftX; glowMoveY = ShiftY; tempStyle = Cv.Style; tempcolor = Cv.DrawColor; cv.SetDrawColor(255, 255, 255, 0); cv.SetPos((cv.ClipX - xpos * HUDscaleX), (cv.ClipY - ypos * HUDScaley)); cv.DrawIcon( LastRoom, sizeIcon * (hudScaleX + hudScaleY)); cv.SetDrawColor(255, 255, 255, fade); cv.SetPos((cv.ClipX - xpos * HUDscaleX), (cv.ClipY - ypos * HUDScaley)); cv.DrawIcon( pLastRoom, sizeIcon * (hudScaleX + hudScaleY)); cv.SetDrawColor(255, 255, 255, mapOp); cv.SetPos((cv.CLipX - (xGlow-glowMoveX) * HUDScaleX), (cv.ClipY - (yGlow-glowMoveY) * HUDScaleY)); cv.DrawIcon( pLastGlow, sizeGlow * (hudScaleX + hudScaleY)); switch (VNStatus) { case VN_None: resetfade(); break; case VN_Bal1: plastRoom = blank; lastVolume = 12; pLastGlow = Bal1_g; ShiftX = 5; ShiftY = 0; break; case VN_Bal2: plastRoom = blank; lastVolume = 13; pLastGlow = Bal2_g; ShiftX = -5; ShiftY = 0; break; default: pLastRoom = blank ; pLastGlow = Hall_g ; resetfade(); break; } }
Please note that the reason I'm doing it this way is becuase of my fades. I faked my fades by having them come in on top of each other, so I needed to track the last icon that came up, then draw it and have it stay to give the appearance of a cross-fade. You could easily track player position and then have it just pop instantly onto the screen...
Linking through Unreal Ed
Okay, hopefully you can just hand this off to a level designer and say "Link the numbers slave of GUI!". But for those less fortunate of us, here's how you link the two together.
- If you've created a package, after you've compiled all your scripts, go to the actor browser and load the package under the actor classes tab. This will bring your scripts into UEd and allow you to access them and place them on your level.
- If you've created classes within UnrealEd, they should already be in the actor browser once you compile in he Script Editor window.
- Add an Actor >> NavigationPoint >> JumpDest >> GameObjective >> CapturePoint.
- Add a Volume of the new class, CaptureVolume.
- Now comes the tricky part. Select your capturepoint. Open the actor ptoperites window and set the capturePointNum to a valid number, like 1. The, go under the events rollout and give it a tag, like MED_CP or something.
- Select the corresponding volume. Give the volume the name number as the capture point (1) and then under the events rollout set the event name to the tag of the capture point (MED_CP). This will effectively link the two. Here's a brief overview on how to better match these tags
That's about it. If you have problems, make sure your tags match between the two. Also, another trick I've found is to set the draw coords to somehting like 500 by 500, so you can make sure it's actually drawing and not getting covered by something.
Confused about what 'trigger' means? Here's a good definition of triggered
Kungfu Hampster: Let me know if u have any problems understanding this.
Tarquin: Looks good. I've added a few tutorial links: you can maybe rewrite your text a bit to make use of them
Kungfu Hampster: Thanks Tarquin. Still a little new ta using the markup! On a side notw, I would not reccomend making the scripts in UnrealEd. Use UDN or WotGreal. UnrealEd's scripting is way to figety for me.