This tutorial was created by Robert Harder and demonstrates a Beta 4 advanced chase camera.

The purpose of this tutorial is to create a chasecam for Beta 4 which not only stays behind the character but also zooms to the player when the camera encounters such things as walls (ie, Nightmare Creatures type cam). It is based on the work of the previous chasecam tutorials and I give many thanks to the hard work of those previous authors. Most of the modifications for this effect are the same as those in the previous tutorials so we'll go entry by entry and see what must be changed. All modifications occur in Client.c.

 

New code: Yellow (Assuming no modifications have been made to Client.c)

First is to render the character. On or about line 1857 there is the following line:

if (geWorld_AddActor(World, Player->Actor, GE_ACTOR_RENDER_MIRRORS|GE_ACTOR_COLLIDE, 0xffffffff) == GE_FALSE)

Change MIRRORS to NORMAL to render the player, as follows:

if (geWorld_AddActor(World, Player->Actor, GE_ACTOR_RENDER_NORMAL|GE_ACTOR_COLLIDE, 0xffffffff) == GE_FALSE)

Next, the rest of the changes occur in the BuilsClientViewXForm block which begins on or about line 2005. For clarity I have copied the complete block of code with changes made in red. You may notice most of the comments: these are taken directly from the previous chasecam tutorial . If you have any questions about these items refer to the previous tutorials.

//=====================================================================================
// BuildClientViewXForm
// Builds the client view xform
// Short-curcuits the process by using the local angles that were sent in the last
// move intention, unless told otherwise by the viewplayer, or demomode...
//==============================================================

static void BuildClientViewXForm(Client_Client *Client)

{
float xtrans;
float ztrans;

geVec3d Pos;
GPlayer *Player; 

float Ydistance,distance; //Distance between Actor and camera

GE_Collision Collision;
geVec3d Front, Back, In, Help;
geVec3d Mins = {-1.0f, -1.0f, -1.0f};
geVec3d Maxs = { 1.0f, 1.0f, 1.0f};
geWorld *World; //Must declare this

assert(Client->ViewPlayer >= 0 && Client->ViewPlayer < NETMGR_MAX_PLAYERS);
Player = &Client->Players[Client->ViewPlayer];
Client->ViewXForm = Player->XForm;

World = GameMgr_GetWorld(Client->GMgr); //Set World to Gmgr this way; //differs from Beta 3

if (Client->Demo.Mode != CLIENT_DEMO_PLAY && !(Player->ViewFlags & VIEW_TYPE_FORCE_XFORM))
{
Pos = Client->ViewXForm.Translation;
geXForm3d_GetIn(&Client->ViewXForm, &In);
//Send ray to examine if player is looking up or down by determining the height
//difference
//(300.0f = max camera distance)

//Eqn is divided by 1.75 to allow for smooth up/down zooming; see below

geVec3d_AddScaled(&Pos, &In, -1000.0f, &Help);
Ydistance=300.0f-(float)fabs((Pos.Y-Help.Y)/1.75);

//Start sending ray 20.0f from behind Actor, or it will collide with the Actor self

geVec3d_AddScaled(&Pos, &In, -20.0f, &Front);

//Start sending ray in View-Height

Front.Y = Front.Y +180.0f;
Back.Y = Back.Y +180.0f;

//Look 10000.0f behind

geVec3d_AddScaled(&Front, &In, -100000.0f, &Back);

//if backward ray collides with wall decrease camera distance

//As you can see the format of geWorld_Collision has changed since Beta 3; still //basically the same, though. It's becomes obvious here why World was set to

//Gmgr above (as contrasted by previous tutorial).

if (geWorld_Collision(World, NULL, NULL, &Front, &Back, GE_COLLIDE_ALL, 0, NULL, NULL, &Collision))
{
//Get Distance behind Actor and Wall

distance=(float)fabs(geVec3d_DistanceBetween(&Collision.Impact,&Front));

//Minimum between looking up/down and Wall behind

distance=min(distance,Ydistance);

//distance ranges:

if (distance<1.0f) distance=-20.0f;
if (distance>300.0f) distance=300.0f;

}

// Clear the matrix

geXForm3d_SetIdentity(&Client->ViewXForm);

// Rotate then translate.

geXForm3d_RotateZ(&Client->ViewXForm, Client->Angles.Z);
geXForm3d_RotateX(&Client->ViewXForm, Client->Angles.X);
geXForm3d_RotateY(&Client->ViewXForm, Client->Angles.Y);


//changed to variable camera distance

xtrans = (float) (sin(Client->Angles.Y)*distance);
ztrans = (float) (cos(Client->Angles.Y)*distance);

geXForm3d_Translate(&Client->ViewXForm, Pos.X, Pos.Y, Pos.Z);

}

// HACK the view height till we get it in
// Just use a vakue that looks good for now...

 

// Set the viewheight from 140 to 180 else her big head will be in the way ;-)

Client->ViewXForm.Translation.Y += 180.0f;
Client->ViewXForm.Translation.X += xtrans;
Client->ViewXForm.Translation.Z += ztrans;

}

Included with this tutorial is a copy of the modified Client.c. Download a copy by clicking here.

That's it. These changes in Client.c make a nice little chase cam which will zoom in on the player depending upon the stated conditions. The next improvement would probably be to make the zooming action a little slower/smoother (any ideas?). As I noted above there is a 1.75 divisor in the Ydistance eqn. This is because I have all of my movements set up on my mouse, as follows: Forward=LeftButton, Jump=RightButton, LookUp/Down=move mouse Up/Down, TurnL/R=move mouse L/R. I found that this would be the best type of movement config, letting the right hand move the character and the left hand do all of the actions (shoot, change wpn, examine item, etc). If your using only the keyboard for movement and LookUp/Down you can take this number out of the eqn. I only put it there to slow the zooming action of LookUp/Down when the mouse moves up and down; it was zooming in too fast and was kind of disorienting. Well, that's about it, except this: the only way we can turn Genesis into a serious contender is to SHARE THE KNOWLEDGE. Don't be silent: if you made something new and neat with the engine share it! It's the only way we indies can make it! Thanks again to the authors of the previous chasecam tutorials. Later, Robert H. at rhbh4x4@megasurf.net.