This tutorial was created by Thomas Werth and demonstrates a SDK 1 key switch between a chase Cam and first Person view.

The purpose of this tutorial is to create a chasecam for SDK 1 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, GMain.c, GMain.h. So at the end of this tutorial u can switch between first and third person view by pressing the K-key.

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


GMain.h
/////////////////////////////////////////////////////////////////////////////////
//
//Variablen
//
/////////////////////////////////////////////////////////////////////////////////7

//added
 geBoolean b1stPerson;
//end added




GMain.c

 if (IsKeyDown('L'))
 {
  GenVSI_SetWorld(VSI, SetupWorldCB, ShutdownWorldCB, "Levels\\GenVs.Bsp");
  return GE_TRUE;
 }

 if (IsKeyDown('K'))
 {
  b1stPerson=!b1stPerson;
 }

 

 Move = GenVSI_GetClientMove(VSI, Player->ClientHandle);

 if (!Move)
  return GE_TRUE;

 assert(Move);
 

Client.c

First near the beginning add these lines where indicated:

extern geVFile *MainFS;
extern geFloat EffectScale;

//added for Camera switch
extern geBoolean b1stPerson;
//end added


static int32 NumUpdates = 0; // For status bar updating...

#ifdef _DEBUG
Fx_Player *PLAYER_TO_FXPLAYER(Client_Client *Client, GPlayer *Player)
{
uint32 Index;


Then 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 (Client->ViewPlayer == PlayerIndex && !TempPlayer)   // Only render viewplayer in mirrors
   {
    //added
     if (b1stPerson) {if (geWorld_AddActor(World, Player->Actor, GE_ACTOR_RENDER_MIRRORS|GE_ACTOR_COLLIDE, 0xffffffff) == GE_FALSE)
          GenVS_Error("[CLIENT] CheckClientPlayerChanges:  Could not add actor to world.  ActorDef Name: %s.\n", ActorIndex->FileName);
    }
    else {if (geWorld_AddActor(World, Player->Actor, GE_ACTOR_RENDER_NORMAL|GE_ACTOR_COLLIDE, 0xffffffff) == GE_FALSE)
        GenVS_Error("[CLIENT] CheckClientPlayerChanges:  Could not add actor to world.  ActorDef Name: %s.\n", ActorIndex->FileName);

    }
                //end added

 // Make these flags recent...
 Player->OldViewFlags2 = Player->ViewFlags;
 Player->OldViewIndex2 = Player->ViewIndex;
 Player->OldScale2 = Player->Scale;

about(2152)
 //added
 //Tombraider Camera nur wenn NORMAL statt MIRROR
 if (Client->ViewPlayer == PlayerIndex && !TempPlayer)   // True when Player gefunden
 {
  if (b1stPerson) {
   geWorld_SetActorFlags(World, Player->Actor, GE_ACTOR_RENDER_MIRRORS|GE_ACTOR_COLLIDE);
  }
  else {
   geWorld_SetActorFlags(World, Player->Actor, GE_ACTOR_RENDER_NORMAL|GE_ACTOR_COLLIDE);
  }
 }
    //end added

 return GE_TRUE;
}
 

Next, the rest of the changes occur in the BuilsClientViewXForm block I've copied the whole block cause there are so many changes i just don't know how the original looks like.. If you have any questions about these items refer to the previous tutorials.

/*
added
*/
//=====================================================================================
// BuildClientViewXForm Tomb Raider view
// 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;

if (!b1stPerson)
 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;

if (!b1stPerson)
 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

if (!b1stPerson) {
 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_CONTENTS_SOLID_CLIP, 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

if (!b1stPerson)
{
 xtrans = (float) (sin(Client->Angles.Y)*distance);
 ztrans = (float) (cos(Client->Angles.Y)*distance);
}
geXForm3d_Translate(&Client->ViewXForm, Pos.X, Pos.Y, Pos.Z);

}

 Client->ViewXForm.Translation.Y += 140.0f;
if (!b1stPerson)
{
 // 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 += 40.0f;
 Client->ViewXForm.Translation.X += xtrans;
 Client->ViewXForm.Translation.Z += ztrans;
}
}
//end added

 

That's it. These changes make a nice little chase cam which will zoom in on the player depending upon the stated conditions You can switch between first and third Person view by th eKey k..  Thanks again to the authors of the previous chasecam tutorials. Special thanks to Robert H. at rhbh4x4@megasurf.net. So on Thomas Werth!