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!