# Sega 500 Camera Transitions using Delegates Jeff “Ezeikeil” Giles

## Presentation on theme: "Sega 500 Camera Transitions using Delegates Jeff “Ezeikeil” Giles"— Presentation transcript:

Sega 500 Camera Transitions using Delegates Jeff “Ezeikeil” Giles jgiles@artschool.com http://gamestudies.cdis.org/~jgiles

Last day We discovered how to do some really cool stuff with the camera Through the playercalcview function. Modification of the user.ini to create executable functions. How to manipulate the game speed to create “bullet time”.

Today Our goals are a bit more modest. Well be expanding on last days class by creating camera transitions on key presses & events.

Transitions So to get started, were going to make the player the focus of the camera. Then well build functionality to make the camera move from one location to another while watching the player.

Transitions In effect, we’ll be creating a camera which can view the player from the front, back, left or right side and remain locked to this new position.

Transitions The first thing to do is set the camera to a new position in space from which to view the player. Making some adjustments to the code, I’m after behind and above POV to start.

Transitions Using a vector…which means how we calculated it is going to be a bit different cameraOffset=vect(-200,0,50) // behind & above More on this in a moment…

Transitions In effect, you can consider this offset to be in model space i.e. relative to the player and not the world origin. 200 units back 75 units up 70 200

Transitions At the moment, we’ll keep this as a fixed distance until we’re setup. Now, here’s an odd note. One would think that, being a variable declared in this class, that we should be able to set its values in the default properties …sounds reasonable right?

Transitions Well, welcome to more UT oddness. We can set *most* variables in the defaults…except vectors. If you do this: defaultproperties { cameraOffset=vect(-200,0,50) // behind & above } It won’t work, nor will it log an error. Your vector gets set to (0,0,0) 

Transitions Now I’ve not tested it with all the variable types, but I would expect that this occurs with rotators and most of the structs…If not all. You’ll have to set them up in a initialization function such as PostBeginPlay() However, setting individual properties of a struct works fine.

Transitions Now we set our Camera’s location to that of the player & offset it by the desired amount… I’m not using the cameraOffset here just for clairity CameraLocation = ViewActor.Location; CameraLocation += vect(-200,0,75);

Transitions The next step is to set up the camera’s rotation to ALWAYS look at the player. CameraRotation = rotator( ViewActor.Location-CameraLocation ); Remember what we’re doing here? We’re getting a vector between the locations & casting to a rotator (or unit vector) to get it’s direction.

Transitions Now if we run it, we should have a camera that always focuses on the player. And we do…

Transitions But notice that I can rotate the pawn but not the camera.

Transitions So the next step, now that we’ve our distance right, is to lock the camera to a specific location in relation to the player. This takes a bit more effort & re-modeling of the code. However, essentially, we just need to combine the camera offset with the rotation of the player.

Transitions To start with, we’ll just lock it behind the player. Surprisingly, the magic happens in one line. cameraOffset= VSize(cameraOffset) * vector(ViewActor.Rotation);

Transitions And we’re locked in chase cam. But there’s a caveat… We loose our elevation above the player.

Transitions For why, look back at the code cameraOffset= VSize(cameraOffset) * vector(ViewActor.Rotation); We multiply a vector by a scalar to get our new vector…no problem…and were casting from a rotator to get the unit vector…a.k.a the direction…fine.

Transitions Look closer vector(ViewActor.Rotation) This is the rotation of the model in world space, e.g. which way it knows is up. Not it’s line of sight.

Transitions To put this another way, the models pitch is 0…not rotated. Hence, this zero’s out our elevation rotation.

Transitions To fix is real easy, just store the Z component of the cameraOffset in a variable & re add it to the cameraLocation.z as we’ve been doing to date… But I’m thinking there is a much more clever way…

Offset relative to the Pawn As we mentioned earlier, we’re going to use this vector to figure out the offset relative to the pawn and not the world. This is important to remember, otherwise it’s very easy to get confused by this.

Offset relative to the Pawn That being said, we have to modify our previous calculations to: And the end result is an offset relative to the pawn. cameraOffset=vect(-200,0,75); … cameraOffset= VSize(cameraOffset) * vector(normalize(rotator(cameraOffset)) +viewactor.Rotation+OffsetRotation()); CameraLocation = ViewActor.Location + cameraOffset;

Offset relative to the Pawn How’s this working? Really we’re doing the same calculation as we did with the Max Payne cam…just with more numbers. cameraOffset= VSize(cameraOffset) * vector(normalize(rotator(cameraOffset)) + viewactor.Rotation ); Scalar multiplication (how far away we are) And in what direction

Offset relative to the Pawn And the net result is the ability to use a vector to define a location relative to the player to view from. Handy…very handy…

Offset relative to the Pawn local vector cameraOffset; cameraOffset=vect(-200,0,75);//model space offset...above and behind bBehindView=true; ViewActor = ViewTarget; //calculate offset relative to the pawn cameraOffset= VSize( cameraOffset) * vector( normalize(rotator(cameraOffset) ) + viewactor.Rotation + OffsetRotation() ); CameraLocation = ViewActor.Location + cameraOffset; CameraRotation = rotator(ViewActor.Location-CameraLocation);

Transitions Now locked behind at a fixed height behind the player. Lets do some transitions…

Transitions For now, lets just build a toggle function which will snap the view from front to back. To do so, we’ll create an exec function & stuff it into the user.ini

Transitions The function is really easy. We just want to add ½ rotation. exec function SwapViewFrontBack() { DirectToCamera.Yaw+= 65535/2; // ½ rotation }

Transitions An now in playercalcview we modify one line: Simply adding an additional rotational value to the camera’s relative direction. cameraOffset= VSize(cameraOffset) * vector(normalize(rotator(cameraOffset)) +viewactor.Rotation + DirectToCamera);

Transitions This now provides us provide us with a ‘snap’ to see who’s behind us.

Transitions Fine…Dandy…where’s the cool? Now, now…This is just making sure we’re properly set up. Now the cool happens. We’re going to build functions which will allow us to snap to the players front, back, left or right

Delegates And we’re going to do this using delegates. From the UDN: A delegates is a reference to a function bound to an object. Can you say “function pointer” boys & girls?...I knew you could.

Delegates Their main purpose in life is to provide a callback mechanism, for example to provide event notification in a user interface system. But this is by NO means their only use.

Delegates Now that we know what they are, lets go about building one. But first, we need some functions to select from… The plan is simple. 4 functions that return a rotator and set the delegate.

Delegates Start by creating a delegate: delegate rotator OffsetRotation(); A delegate must have the same return type and signature as the functions you intend to have it pointing at.

Delegates Now we create a set of functions to be called from the user.ini which set the direction to view from. One for each direction…

Delegates exec function rotator ViewFront() { local rotator rotammount; rotammount.yaw=0; OffsetRotation= ViewFront; return rotammount; } exec function rotator ViewBack() { local rotator rotammount; rotammount.yaw=65535/2; OffsetRotation= ViewBack; return rotammount; } exec function rotator ViewLeft() { local rotator rotammount; rotammount.yaw=65535/4; OffsetRotation= ViewLeft; return rotammount; } exec function rotator ViewRight() { local rotator rotammount; rotammount.yaw=65535/4*3; OffsetRotation= ViewRight; return rotammount; }

Delegates These function is really straight forward, the only weirdness is: OffsetRotation= ViewLeft; Which just sets the delegate to point at this function…just like function pointers in C++

Delegates And now we set up our user.ini to deal with the new exec functions. Don’t forget to give the delegate a default function to use in the default properties. If you don’t, you get some weird screen flickering until one the Viewfrom functions is played.

Delegates Once we give our delegate a default function to point at ( like viewBehind ) we change our rotational calculation to use the delegate and not the absolute vector. cameraOffset= VSize(cameraOffset) * vector(normalize(rotator(cameraOffset)) +viewactor.Rotation + OffsetRotation (); ); The delegate

Delegates

As you can see, we can use delegates to snap the camera to a given position saving us from several if cases, switches or math headaches.

Delegates In addition, like C++ function pointers, we can pass in variables as well. So long as the delegate has the same signature, as mentioned earlier. Just to demonstrate the point…

Delegates The code can modified the code to calculate the camera position for us. delegate rotator OffsetRotation( optional rotator rot); This new definition allows us to optionally pass in a rotator…thus we can still use the same function in the user.ini.

Delegates What the UDN says about optional: The optional keyword, allows you to make certain function parameters optional For UnrealScript functions, optional parameters which the caller doesn't specify are set to zero.

Delegates Modify a line in PlayerCalcView cameraOffset= VSize(cameraOffset) * vector(normalize(rotator(cameraOffset)) +viewactor.Rotation + OffsetRotation(ViewActor.Rotation););

Delegates And slight modifications to the viewfrom functions

Delegates exec function rotator ViewFront(optional rotator rot) { local rotator rotammount; rotammount.yaw=0; OffsetRotation= ViewFront; return rotammount+rot; } exec function rotator ViewBack(optional rotator rot) { local rotator rotammount; rotammount.yaw=65535/2; OffsetRotation= ViewBack; return rotammount+rot; } exec function rotator ViewLeft(optional rotator rot) { local rotator rotammount; rotammount.yaw=65535/4; OffsetRotation= ViewLeft; return rotammount+rot; } exec function rotator ViewRight(optional rotator rot) { local rotator rotammount; rotammount.yaw=65535/4*3; OffsetRotation= ViewRight; return rotammount+rot; }

Delegates Delegates are incredibly powerful tools to have at your fingertips. In effect, there almost like miniature states. Having different functionality based on how they were set.

Delegates Just to further illustrate this, there’s one more, really cool trick we can use. We can actually place the delegate itself in the user.ini. Thus causing a keypress to have a different functionality.

Delegates So, in order to demonstrate this, we’re going to use an enumeration to keep track of what view mode we’re currently in. The best part is, using enum’s is really similar to c++. The only thing is that they have to be declared at the top of the class I the global space.

Delegates Here’s mine var enum viewfromdir { E_FRONT, E_BACK, E_LEFT, E_RIGHT }V_Ddir; Just like in c++, you can append a variable declaration to the definition.

Delegates And to get this to work, we’re simply going to use a case statement. exec function rotator NextView(optional rotator pawnRot) { local rotator rot; switch (V_Ddir) { case E_FRONT: V_Ddir=E_BACK; //next view from OffsetRotation= ViewFront; break; case E_BACK: V_Ddir=E_LEFT; OffsetRotation= ViewBack; break;

Delegates Nothing fancy… The only thing to note is that we have the same signature and gave it a default value. case E_LEFT: V_Ddir=E_RIGHT; OffsetRotation= Viewleft; break; case E_RIGHT: V_Ddir=E_FRONT; OffsetRotation= Viewright; break; } return rot+pawnRot; }

Delegates And, in the user.ini, we set it up exactly the same as any other exec function… Aliases[30]=(Command="NextView",Alias=Offsetdelegate) … F11=Offsetdelegate

Delegates

And just by repeatedly hitting the F11 key, we cycle through different views. But just remember…we are in fact executing different functions! All that we’ve done here is implemented a “pointer” to which function to execute.

Delegates So, once again, I hope you can see the power behind these things and that their usefulness can extend far beyond what they were originally designed to do.

Delegates Very… very handy for implementing things like changes to thinks like weapon functionality or AI decision making…or even something so small as what to display to the HUD. All it takes is a little bit of for thought and planning.

That’s a wrap for today! I hope you can see the usefulness and coolness that comes with this bad boys.