sega 500 camera transitions using delegates jeff “ezeikeil” giles jgiles@artschool.com jgiles

Post on 15-Dec-2015

213 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Sega 500

Camera Transitions using Delegates

Jeff “Ezeikeil” Gilesjgiles@artschool.comhttp://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 closervector(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

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 declarationto 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)

…<snip>…

F11=Offsetdelegate

Delegates

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.

top related