Вид от третьего лица

From Valve Developer Community
Jump to: navigation, search
English


Эта статья не подходит для движка Orange Box

Для Orange Box версии движка смотрите статью Thirdperson-OrangeBox


Обзор

В этом уроке описано, как сделать вид от третьего лица со следующими функциями:

  • Обнаружение столкновения
  • Масштабирование колесиком мыши
  • Прозрачность модели, если камера слишком близко


  • Скрытие рук Гордона в режиме от третьего лица
  • Скрытие оружия в режиме от третьего лица (или первого лица)
  • Скрытие crosshair в режиме от третьего лица (или первого лица)
  • Скрытие модели игрока в режиме от первого лица
  • Добавление кнопки переключения

Спасибо за Third Person Camera статьям сThe Wavelength. Этот туториал модификация нескольких статьей, удобна для понимания.
Спасибо за перевод Google Переводчик

Шаг первый: in_camera.cpp

Это руководство предполагает, что вы используете Single Player Mod и Microsoft Visual Studio 2003/2005/2008/2010.
Откройте Game_Episodic-2005.sln в Visual Studio.

Первым делом будет изменен код внутри камеры: in_camera.cpp (Находится в client).

Закомментируйте строку:

#define CAM_MIN_DIST			36.0

Чтобы получилось так:

// #define CAM_MIN_DIST    36.0

Под строкой #define YAW_MIN -135.0

Добавьте:

in_camera.cpp

#define CAM_MIN_DIST		16.0 // Don't let the camera get any closer than ...
#define CAM_MAX_DIST		96.0 // ... or any farther away than ...
#define CAM_SWITCH_DIST		96.0 // the default camera distance when switching 1st to 3rd person
#define CAM_HULL_OFFSET		6.0  // the size of the bounding hull used for collision checking
#define START_TRANS_DIST	40.0 // how close to player when it starts making model translucent
#define TRANS_DELTA	        1.9921875 // Set to 255 / START_TRANS_DIST

static Vector CAM_HULL_MIN(-CAM_HULL_OFFSET,-CAM_HULL_OFFSET,-CAM_HULL_OFFSET);
static Vector CAM_HULL_MAX( CAM_HULL_OFFSET, CAM_HULL_OFFSET, CAM_HULL_OFFSET);

Под строкой: static kbutton_t cam_in, cam_out, cam_move;

Добавьте:

float mf_NextSwitch;

Замените:

static ConVar cam_idealyaw( "cam_idealyaw", "90", FCVAR_ARCHIVE ); // thirdperson yaw

На:

static ConVar cam_idealyaw( "cam_idealyaw", "0", FCVAR_ARCHIVE ); /* thirdperson yaw
                                                                     | fix side view bug */

Замените эту секцию (под функцией CAM_Think):

if( !m_fCameraInThirdPerson )
      return;

На:

// Toggle first/3rd person, check every 0.5 seconds
if(gpGlobals->curtime >= mf_NextSwitch) {
	if(input->KeyState(&in_camchange))
	{
		mf_NextSwitch = gpGlobals->curtime + 0.5; /* Check if the key has been pressed every
                                                             0.5 seconds */
		if(!m_fCameraInThirdPerson)
		{
			CAM_ToThirdPerson();
		} else {
			CAM_ToFirstPerson();
		}
	}
}

if( !m_fCameraInThirdPerson )
{
	// If in FP mode, transparent
	// This is sort of a hack since when the map first loads you ARE transparent...
	// This is for when you switch from 3rd to 1st.
	if(C_BasePlayer::GetLocalPlayer() ) {
		C_BasePlayer::GetLocalPlayer()->SetRenderMode( kRenderTransColor );
		C_BasePlayer::GetLocalPlayer()->SetRenderColorA(0);
	}

	return;
}
Note:ВЫ можете изменить 0.5 в строке: mf_NextSwitch = gpGlobals->curtime + 0.5 на более маленькое значение.

В пределах этого куска кода:

else if( input->KeyState( &cam_out ) ) {
	dist += CAM_DIST_DELTA;

}

Добавьте после dist += CAM_DIST_DELTA;:

		// Prevent the cam_out from going any further
		// NOTE: Without this, it _appears_ it's not moving, but
		// the transparency changes so it is... this fixes it.
		if( dist > CAM_MAX_DIST )
			dist = CAM_MAX_DIST;

Замените это:

if( cam_snapto.GetInt() )
	{
		camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ];
		camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ];
		camAngles[ 2 ] = cam_idealdist.GetFloat();
	}
	else
        {
         // code already here
}

На это:

if( cam_snapto.GetInt() )
{
	camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ];
	camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ];
	camAngles[ 2 ] = cam_idealdist.GetFloat();
}
else
{
	if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw.GetFloat() )
		camAngles[ YAW ] = MoveToward( camAngles[ YAW ],
					       cam_idealyaw.GetFloat() + viewangles[ YAW ],
                                               CAM_ANGLE_SPEED );
 
        if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch.GetFloat() )
            camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ],
                                             cam_idealpitch.GetFloat() + viewangles[ PITCH ],
                                             CAM_ANGLE_SPEED );
 
        if( !C_BasePlayer::GetLocalPlayer() ) {
            // this code can be hit from the main menu, where it will crash
            camAngles[ 2 ] = dist; // if there's no localplayer to calc from
        }
        else {
            trace_t tr;
            float adjDist = dist;
            C_BasePlayer* localPlayer = C_BasePlayer::GetLocalPlayer();

            Vector origin = localPlayer->GetLocalOrigin(); // find our player's origin
            origin += localPlayer->GetViewOffset(); // and from there, his eye position

            AngleVectors( QAngle(camAngles.x, camAngles.y, camAngles.z),
                         &camForward, NULL, NULL ); // get the forward vector

            UTIL_TraceHull( origin, origin - (camForward * dist),
                            CAM_HULL_MIN, CAM_HULL_MAX,
                            MASK_SOLID, NULL, &tr ); /* use our previously #defined hull to
                                                        collision trace */

            if( tr.fraction < 1.0 ) {
                adjDist = dist * tr.fraction; // move the camera closer if it hit something
            }
            else {
                adjDist = dist; // no trace hit, use cam_idealdist without adjusting it
            }

	    if ( adjDist < START_TRANS_DIST ) {
	        localPlayer->SetRenderMode( kRenderTransColor ); // make him translucent
		localPlayer->SetRenderColorA( (byte)(adjDist * TRANS_DELTA) ); // closer=less opacity
	    }

            if( adjDist < CAM_MIN_DIST )
                adjDist = CAM_MIN_DIST; // clamp up to minimum

            if( adjDist > CAM_MAX_DIST )
                adjDist = CAM_MAX_DIST; // clamp down to maximum

            camAngles[ 2 ] = adjDist;
        }
    }

Найдите:

	m_vecCameraOffset[ 0 ] = camAngles[ 0 ];
	m_vecCameraOffset[ 1 ] = camAngles[ 1 ];
	m_vecCameraOffset[ 2 ] = dist;

Замените:

	m_vecCameraOffset[ 2 ] = dist;

На:

	m_vecCameraOffset[ 2 ] = camAngles[ 2 ];


В функции void CInput::CAM_ToThirdPerson(void)

Измените:

m_vecCameraOffset[ 2 ] = CAM_MIN_DIST;

на:

m_vecCameraOffset[ 2 ] = CAM_SWITCH_DIST; /* When switching, move camera to our specified switch
                                             distance */

Добавьте под этим:

		// Set model to 'player' because when a map first loads
		// it doesn't set the model... sort of a hack.
		//C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
		//pPlayer->SetModel("player");

Шаг второй: c_basecombatweapon.cpp

Откройте файл c_basecombatweapon.cpp в client.

Под этим, в C_BaseCombatWeapon::DrawModel( int flags ):

// check if local player chases owner of this weapon in first person
C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();

Добавьте:

// Get rid of view model, crosshair and weapon in 3rd person
// Once we actually get weapons working, we'll let it draw only the weapon
if (localplayer)
{
	if (input->CAM_IsThirdPerson())
	{
		// make sure the caller is the player to prevent hiding EVERYONE's weapon model.
		if(localplayer == GetOwner())
                {
			SetModel( GetWorldModel() );
			// Hide crosshair, remove this line if you still want to see it.
			localplayer->m_Local.m_iHideHUD |= HIDEHUD_CROSSHAIR;
			return false;
			/* Comment above and uncomment the line underneath if you want
			   to be able to do weapon things (it will display the weapon). */
			//return BaseClass:: DrawModel( flags );
                }
	}
}

Шаг третий: in_main.cpp

Откройте in_main.cpp в client.

Под строкой kbutton_t in_graph;, добавьте:

kbutton_t	in_camchange;

Снизу:

void IN_ZoomDown(void) {KeyDown(&in_zoom);}
void IN_ZoomUp(void) {KeyUp(&in_zoom);}

Добавьте:

void IN_CamChangeDown(void) {KeyDown(&in_camchange);}
void IN_CamChangeUp(void) {KeyUp(&in_camchange);}

Снизу CalcButtonBits( bits, IN_ZOOM, s_ClearInputState, &in_zoom, bResetState );, добавьте:

CalcButtonBits( bits, IN_CAMCHANGE, s_ClearInputState, &in_camchange, bResetState );

Снизу:

static ConCommand startzoom("+zoom", IN_ZoomDown);
static ConCommand endzoom("-zoom", IN_ZoomUp);

Добавьте:

static ConCommand startcamchange("+camchange", IN_CamChangeDown);
static ConCommand endcamchange("-camchange", IN_CamChangeUp);

Шаг четвертый: input.h & in_buttons.h

Откройте in_buttons.h в server.

Снизу #define IN_BULLRUSH (1 << 22), добавьте:

#define IN_CAMCHANGE	(1 << 23)
Note:Если вы планируете добавить еще команды с клавиатуры, вы можете просто добавить:
#define {command} (1 << {int})

Откройте input.h в client.

Снизу:

extern kbutton_t in_back;

Добавьте:

extern kbutton_t in_camchange;

Шаг пятый: kb_act.lst

Откройте kb_act.lst в папке SourceMods/{Ваш_Мод}/scripts/.

И добавьте под:

"blank"			"=========================="
"blank"			"#Valve_Movement_Title"
"blank"			"=========================="
"+forward"				"#Valve_Move_Forward"
"+back"					"#Valve_Move_Back"
"+moveleft"				"#Valve_Move_Left"
"+moveright"			"#Valve_Move_Right"
"+speed"             	"#Valve_Sprint"
"+jump"					"#Valve_Jump"
"+duck"					"#Valve_Duck"

Вот это:

"+camchange"			"Toggle 3rd/1st Person View"

Шаг шестой: Animations

Оригинал на VERC форумах:

Добавлено: Whisp

Это последующей деятельности в должность, что я сделал некоторое время назад. Я пытался ли какие-либо знал, как добавить анимацию в thirdperson чтобы один игрок мод. Никто не знал, но я рад буду объявить что я нашел способ. Глядя на многочисленные код игрок, которого я нашел, что класс CHL2MP_Player происходит от CHL2_Player из одиночной игры. Если вы посмотрите на класс CHL2MP_Player вы увидите, что функция SetAnimation переопределяется. Я скопировал эту функцию из источника депутат и добавил его к классу CHL2_Player моего одного игрока мод. Затем я изменить модель игрока на один из человека (Алике также работает) и изменение функции депутата использовать СП деятельности. Ниже приводится функция, как он сидит сейчас. Я надеюсь, что это помогает, кто пытается добавить такую анимацию. Я не нашел способ сообщить, если игрок бежит не так анимации в настоящее время всегда выполняется (то есть так, как это в депутаты, а). Я попытался проверки ключевых IN_RUN но это не сработало. Я также попытался скорости код в начало функции МП и которые также не работает. Если кто знает способ говорить об этом, пожалуйста, дайте мне знать.
// Set the activity based on an event or current state
void CHL2_Player::SetAnimation( PLAYER_ANIM playerAnim )
{
	int animDesired;
	
	float speed;
	
	speed = GetAbsVelocity().Length2D();
	
	if ( GetFlags() & ( FL_FROZEN | FL_ATCONTROLS ) )
	{
	speed = 0;
	playerAnim = PLAYER_IDLE;
	}
	
	Activity idealActivity = ACT_RUN;
	
	// This could stand to be redone. Why is playerAnim abstracted from activity? (sjb)
	if ( playerAnim == PLAYER_JUMP )
	{
		idealActivity = ACT_JUMP;
	}
	else if ( playerAnim == PLAYER_DIE )
	{
		if ( m_lifeState == LIFE_ALIVE )
		{
			return;
		}
	}
	else if ( playerAnim == PLAYER_ATTACK1 )
	{
		if ( GetActivity( ) == ACT_HOVER ||
			GetActivity( ) == ACT_SWIM ||
			GetActivity( ) == ACT_HOP ||
			GetActivity( ) == ACT_LEAP ||
			GetActivity( ) == ACT_DIESIMPLE )
		{
			idealActivity = GetActivity( );
		}
		else
		{
			idealActivity = ACT_GESTURE_RANGE_ATTACK1;
		}
	}
	else if ( playerAnim == PLAYER_RELOAD )
	{
		idealActivity = ACT_GESTURE_RELOAD;
	}
	else if ( playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK )
	{
		if ( !( GetFlags() & FL_ONGROUND ) && GetActivity( ) == ACT_JUMP ) // Still jumping
		{
			idealActivity = GetActivity( );
		}
		/*
		else if ( GetWaterLevel() > 1 )
		{
			if ( speed == 0 )
				idealActivity = ACT_HOVER;
			else
				idealActivity = ACT_SWIM;
		}
		*/
		else
		{
			if ( GetFlags() & FL_DUCKING )
			{
				if ( speed > 0 )
				{
					idealActivity = ACT_WALK_CROUCH;
				}
				else
				{
					idealActivity = ACT_COVER_LOW; //ACT_IDLE_CROUCH;
				}
			}
			else
			{
				if ( speed > 0 )
				{
					idealActivity = m_fIsSprinting ? ACT_WALK : ACT_RUN;
				}
				else
				{
					idealActivity = ACT_IDLE;
				}
			}
		}
	
		//idealActivity = TranslateTeamActivity( idealActivity );
	}
	
	if ( idealActivity == ACT_GESTURE_RANGE_ATTACK1 )
	{
		RestartGesture( Weapon_TranslateActivity( idealActivity ) );
	
		// FIXME: this seems a bit wacked
		Weapon_SetActivity( Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
	
		return;
	}
	else if ( idealActivity == ACT_GESTURE_RELOAD )
	{
		RestartGesture( Weapon_TranslateActivity( idealActivity ) );
		return;
	}
	else
	{
		SetActivity( idealActivity );
	
		animDesired = SelectWeightedSequence( Weapon_TranslateActivity ( idealActivity ) );
	
		if (animDesired == -1)
		{
			animDesired = SelectWeightedSequence( idealActivity );
	
			if ( animDesired == -1 )
			{
				animDesired = 0;
			}
		}
	
		// Already using the desired animation?
		if ( GetSequence() == animDesired )
			return;
		
		m_flPlaybackRate = 1.0;
		ResetSequence( animDesired );
		SetCycle( 0 );
		return;
	}
	
	// Already using the desired animation?
	if ( GetSequence() == animDesired )
		return;
	
	//Msg( "Set animation to %d\n", animDesired );
	// Reset to first frame of desired animation
	ResetSequence( animDesired );
	SetCycle( 0 );
}

== выше код должен идти внутрь hl2_player.cpp. это, то должна быть определена в hl2_player.h
поэтому в строке 174 поставить:

void SetAnimation ( PLAYER_ANIM playerAnim );

==

Заключение

Теперь вы имеете рабочий вид от третьего/первого лица. Если вы хотите назначить кнопку по умолчания для "+camchange", смотрите Customizing Options: Keyboard вики статьи.

Если вы не скрывают модели игрока и оружия, вы увидите, уродливые модели, которая должна представлять Гордона Фримена. Valve не пытаться использовать вид от третьего лица в HL2 поэтому вам придется найти игрока модель с оружием анимации и установить его!

Reference

Reference code

in_camera.cpp

Ваш готовый in_camera.cpp Должен выглядить так:

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Handles 3rd and 1st Person Views
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hud.h"
#include "kbutton.h"
#include "input.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

//-------------------------------------------------- Constants

#define CAM_DIST_DELTA 1.0
#define CAM_ANGLE_DELTA 2.5
#define CAM_ANGLE_SPEED 2.5
#define CAM_ANGLE_MOVE .5
#define MAX_ANGLE_DIFF 10.0
#define PITCH_MAX 90.0
#define PITCH_MIN 0
#define YAW_MAX  135.0
#define YAW_MIN	 -135.0

#define CAM_MIN_DIST		16.0   // Don't let the camera get any closer than ...
#define CAM_SWITCH_DIST		96.0   // the default distance when switching from 1st to 3rd
#define CAM_MAX_DIST		96.0   // ... or any farther away than ...
#define CAM_HULL_OFFSET		6.0    // the size of the bounding hull used for collision checking
#define START_TRANS_DIST	40.0   // how close to player when it starts making model translucent
#define TRANS_DELTA		1.9921875 // Set to 255 / START_TRANS_DIST

static Vector CAM_HULL_MIN(-CAM_HULL_OFFSET,-CAM_HULL_OFFSET,-CAM_HULL_OFFSET);
static Vector CAM_HULL_MAX( CAM_HULL_OFFSET, CAM_HULL_OFFSET, CAM_HULL_OFFSET);

//-------------------------------------------------- Global Variables

static ConVar cam_command( "cam_command", "0", FCVAR_CHEAT | FCVAR_ARCHIVE ); /* tells camera to go
                                                                                 to thirdperson */
static ConVar cam_snapto( "cam_snapto", "0", FCVAR_ARCHIVE );	      // snap to thirdperson view
static ConVar cam_idealyaw( "cam_idealyaw", "0", FCVAR_ARCHIVE );     // thirdperson yaw
static ConVar cam_idealpitch( "cam_idealpitch", "0", FCVAR_ARCHIVE ); // thirperson pitch
static ConVar cam_idealdist( "cam_idealdist", "64", FCVAR_ARCHIVE );  // thirdperson distance

static ConVar c_maxpitch( "c_maxpitch", "90", FCVAR_ARCHIVE );
static ConVar c_minpitch( "c_minpitch", "0", FCVAR_ARCHIVE );
static ConVar c_maxyaw( "c_maxyaw",   "135", FCVAR_ARCHIVE );
static ConVar c_minyaw( "c_minyaw",   "-135", FCVAR_ARCHIVE );
static ConVar c_maxdistance( "c_maxdistance",   "200", FCVAR_ARCHIVE );
static ConVar c_mindistance( "c_mindistance",   "30", FCVAR_ARCHIVE );
static ConVar c_orthowidth( "c_orthowidth",   "100", FCVAR_ARCHIVE );
static ConVar c_orthoheight( "c_orthoheight",   "100", FCVAR_ARCHIVE );

static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright;
static kbutton_t cam_in, cam_out, cam_move;

float mf_NextSwitch;

// API Wrappers

/*
==============================
CAM_ToThirdPerson

==============================
*/
void CAM_ToThirdPerson(void)
{
	input->CAM_ToThirdPerson();
}

/*
==============================
CAM_ToFirstPerson

==============================
*/
void CAM_ToFirstPerson(void) 
{ 
	input->CAM_ToFirstPerson();
}

/*
==============================
CAM_ToOrthographic

==============================
*/
void CAM_ToOrthographic(void) 
{ 
	input->CAM_ToOrthographic();
}

/*
==============================
CAM_StartMouseMove

==============================
*/
void CAM_StartMouseMove( void )
{
	input->CAM_StartMouseMove();
}

/*
==============================
CAM_EndMouseMove

==============================
*/
void CAM_EndMouseMove( void )
{
	input->CAM_EndMouseMove();
}

/*
==============================
CAM_StartDistance

==============================
*/
void CAM_StartDistance( void )
{
	input->CAM_StartDistance();
}

/*
==============================
CAM_EndDistance

==============================
*/
void CAM_EndDistance( void )
{
	input->CAM_EndDistance();
}

/*
==============================
CAM_ToggleSnapto

==============================
*/
void CAM_ToggleSnapto( void )
{ 
	cam_snapto.SetValue( !cam_snapto.GetInt() );
}


/*
==============================
MoveToward

==============================
*/
float MoveToward( float cur, float goal, float maxspeed )
{
	if( cur != goal )
	{
		if( abs( cur - goal ) > 180.0 )
		{
			if( cur < goal )
				cur += 360.0;
			else
				cur -= 360.0;
		}

		if( cur < goal )
		{
			if( cur < goal - 1.0 )
				cur += ( goal - cur ) / 4.0;
			else
				cur = goal;
		}
		else
		{
			if( cur > goal + 1.0 )
				cur -= ( cur - goal ) / 4.0;
			else
				cur = goal;
		}
	}


	// bring cur back into range
	if( cur < 0 )
		cur += 360.0;
	else if( cur >= 360 )
		cur -= 360;

	return cur;
}

/*
==============================
CAM_Think

==============================
*/
void CInput::CAM_Think( void )
{
	Vector origin;
	Vector ext, pnt, camForward, camRight, camUp;
	float dist;
	Vector camAngles;
	float flSensitivity;
	QAngle viewangles;
	
	switch( cam_command.GetInt() )
	{
	case CAM_COMMAND_TOTHIRDPERSON:
		CAM_ToThirdPerson();
		break;
		
	case CAM_COMMAND_TOFIRSTPERSON:
		CAM_ToFirstPerson();
		break;
		
	case CAM_COMMAND_NONE:
	default:
		break;
	}
	
	// Toggle first/3rd person
	if(gpGlobals->curtime >= mf_NextSwitch) {
		if(input->KeyState(&in_camchange))
		{
			mf_NextSwitch = gpGlobals->curtime + 0.5;
			if(!m_fCameraInThirdPerson)
			{
				CAM_ToThirdPerson();
			} else {
				CAM_ToFirstPerson();
			}
		}
	}

	if( !m_fCameraInThirdPerson )
	{
		// If in FP mode, transparent
		// This is sort of a hack since when the map first loads you ARE transparent...
		// This is for when you switch from 3rd to 1st.
		if(C_BasePlayer::GetLocalPlayer() ) {
			C_BasePlayer::GetLocalPlayer()->SetRenderMode( kRenderTransColor );
			C_BasePlayer::GetLocalPlayer()->SetRenderColorA(0);
		}

		return;
	}		
	
	camAngles[ PITCH ] = cam_idealpitch.GetFloat();
	camAngles[ YAW ] = cam_idealyaw.GetFloat();
	dist = cam_idealdist.GetFloat();
	//
	//movement of the camera with the mouse
	//
	if (m_fCameraMovingWithMouse)
	{
		int cpx, cpy;
		
		//get windows cursor position
		GetMousePos (cpx, cpy);
		
		m_nCameraX = cpx;
		m_nCameraY = cpy;
		
		//check for X delta values and adjust accordingly
		//eventually adjust YAW based on amount of movement
		//don't do any movement of cam using YAW/PITCH if we are zooming in/out the camera	
		if (!m_fCameraDistanceMove)
		{
			int x, y;
			GetWindowCenter( x,  y );
			
			/* keep the camera within certain limits around the player (ie avoid certain
                           bad viewing angles) */
  
			if (m_nCameraX>x)
			{
				//if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0))
				if (camAngles[YAW]<c_maxyaw.GetFloat())
				{
					camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((m_nCameraX-x)/2);
				}
				if (camAngles[YAW]>c_maxyaw.GetFloat())
				{
					
					camAngles[YAW]=c_maxyaw.GetFloat();
				}
			}
			else if (m_nCameraX<x)
			{
				//if ((camAngles[YAW]<=135.0)||(camAngles[YAW]>225.0))
				if (camAngles[YAW]>c_minyaw.GetFloat())
				{
					camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((x-m_nCameraX)/2);
					
				}
				if (camAngles[YAW]<c_minyaw.GetFloat())
				{
					camAngles[YAW]=c_minyaw.GetFloat();
					
				}
			}
			
			//check for y delta values and adjust accordingly
			//eventually adjust PITCH based on amount of movement
			//also make sure camera is within bounds
			if (m_nCameraY > y)
			{
				if(camAngles[PITCH]<c_maxpitch.GetFloat())
				{
					camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((m_nCameraY-y)/2);
				}
				if (camAngles[PITCH]>c_maxpitch.GetFloat())
				{
					camAngles[PITCH]=c_maxpitch.GetFloat();
				}
			}
			else if (m_nCameraY<y)
			{
				if (camAngles[PITCH]>c_minpitch.GetFloat())
				{
					camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((y-m_nCameraY)/2);
				}
				if (camAngles[PITCH]<c_minpitch.GetFloat())
				{
					camAngles[PITCH]=c_minpitch.GetFloat();
				}
			}
			
			//set old mouse coordinates to current mouse coordinates
			//since we are done with the mouse
			
			if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 )
			{
				m_nCameraOldX=m_nCameraX*flSensitivity;
				m_nCameraOldY=m_nCameraY*flSensitivity;
			}
			else
			{
				m_nCameraOldX=m_nCameraX;
				m_nCameraOldY=m_nCameraY;
			}

			ResetMouse();
		}
	}
	
	//Nathan code here
	if( input->KeyState( &cam_pitchup ) )
		camAngles[ PITCH ] += CAM_ANGLE_DELTA;
	else if( input->KeyState( &cam_pitchdown ) )
		camAngles[ PITCH ] -= CAM_ANGLE_DELTA;
	
	if( input->KeyState( &cam_yawleft ) )
		camAngles[ YAW ] -= CAM_ANGLE_DELTA;
	else if( input->KeyState( &cam_yawright ) )
		camAngles[ YAW ] += CAM_ANGLE_DELTA;
	
	if( input->KeyState( &cam_in ) )
	{
		dist -= CAM_DIST_DELTA;
		if( dist < CAM_MIN_DIST )
		{
			// If we go back into first person, reset the angle
			camAngles[ PITCH ] = 0;
			camAngles[ YAW ] = 0;
			dist = CAM_MIN_DIST;
		}
		
	}
	else if( input->KeyState( &cam_out ) ) {
		dist += CAM_DIST_DELTA;

		// Prevent the cam_out from going any further
		// NOTE: Without this, it _appears_ it's not moving, but
		// the transparency changes so it is... this fixes it.
		if( dist > CAM_MAX_DIST )
			dist = CAM_MAX_DIST;
	}

	if (m_fCameraDistanceMove)
	{
		int x, y;
		GetWindowCenter( x, y );

		if (m_nCameraY>y)
		{
			if(dist<c_maxdistance.GetFloat())
			{
				dist +=CAM_DIST_DELTA * ((m_nCameraY-y)/2);
			}
			if (dist>c_maxdistance.GetFloat())
			{
				dist=c_maxdistance.GetFloat();
			}
		}
		else if (m_nCameraY<y)
		{
			if (dist>c_mindistance.GetFloat())
			{
				dist -= (CAM_DIST_DELTA)*((y-m_nCameraY)/2);
			}
			if (dist<c_mindistance.GetFloat())
			{
				dist=c_mindistance.GetFloat();
			}
		}
		//set old mouse coordinates to current mouse coordinates
		//since we are done with the mouse
		m_nCameraOldX=m_nCameraX*gHUD.GetSensitivity();
		m_nCameraOldY=m_nCameraY*gHUD.GetSensitivity();
		ResetMouse();
	}
	
	// update ideal
	cam_idealpitch.SetValue( camAngles[ PITCH ] );
	cam_idealyaw.SetValue( camAngles[ YAW ] );
	cam_idealdist.SetValue( dist );
	
	// Move towards ideal
	VectorCopy( m_vecCameraOffset, camAngles );
	
	engine->GetViewAngles( viewangles );
	
	if( cam_snapto.GetInt() )
	{
		camAngles[ YAW ] = cam_idealyaw.GetFloat() + viewangles[ YAW ];
		camAngles[ PITCH ] = cam_idealpitch.GetFloat() + viewangles[ PITCH ];
		camAngles[ 2 ] = cam_idealdist.GetFloat();
	}
	else
    	{
        	if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw.GetFloat() )
            		camAngles[ YAW ] = MoveToward( camAngles[ YAW ],
                                                       cam_idealyaw.GetFloat() + viewangles[ YAW ],
                                                       CAM_ANGLE_SPEED );
 
        	if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch.GetFloat() )
            		camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ],
                                                    cam_idealpitch.GetFloat() + viewangles[ PITCH ],
                                                    CAM_ANGLE_SPEED );
 
        	if( !C_BasePlayer::GetLocalPlayer() ) {
            	// this code can be hit from the main menu, where it will crash
            		camAngles[ 2 ] = dist; // if there's no localplayer to calc from
        }
        else {
            trace_t tr;
            float adjDist = dist;
            C_BasePlayer* localPlayer = C_BasePlayer::GetLocalPlayer();

            Vector origin = localPlayer->GetLocalOrigin(); // find our player's origin
            origin += localPlayer->GetViewOffset(); // and from there, his eye position

            AngleVectors( QAngle(camAngles.x, camAngles.y, camAngles.z),
                         &camForward, NULL, NULL ); // get the forward vector

            UTIL_TraceHull( origin, origin - (camForward * dist),
                            CAM_HULL_MIN, CAM_HULL_MAX,
                            MASK_SOLID, NULL, &tr ); /* use our previously #defined hull to
                                                        collision trace */

            if( tr.fraction < 1.0 ) {
                adjDist = dist * tr.fraction; // move the camera closer if it hit something
            }
            else {
                adjDist = dist; // no trace hit, use cam_idealdist without adjusting it
            }

			if ( adjDist < START_TRANS_DIST ) {
                                // make him translucent
				localPlayer->SetRenderMode( kRenderTransColor );
                                // closer = less opacity
				localPlayer->SetRenderColorA( (byte)(adjDist * TRANS_DELTA) );
			}

            if( adjDist < CAM_MIN_DIST )
                adjDist = CAM_MIN_DIST; // clamp up to minimum

            if( adjDist > CAM_MAX_DIST )
                adjDist = CAM_MAX_DIST; // clamp down to maximum

            camAngles[ 2 ] = adjDist;
        }
    }

    m_vecCameraOffset[ 0 ] = camAngles[ 0 ];
    m_vecCameraOffset[ 1 ] = camAngles[ 1 ];
    m_vecCameraOffset[ 2 ] = camAngles[ 2 ];
}

void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); }
void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); }
void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); }
void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); }
void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); }
void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); }
void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); }
void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); }
void CAM_InDown(void) { KeyDown( &cam_in ); }
void CAM_InUp(void) { KeyUp( &cam_in ); }
void CAM_OutDown(void) { KeyDown( &cam_out ); }
void CAM_OutUp(void) { KeyUp( &cam_out ); }

/*
==============================
CAM_ToThirdPerson

==============================
*/
void CInput::CAM_ToThirdPerson(void)
{ 
	QAngle viewangles;

// Do allow third person in TF2 for now
#if !defined( TF2_CLIENT_DLL ) && !defined( CSTRIKE_DLL )

#if !defined( _DEBUG )
	if ( gpGlobals->maxClients > 1 )
	{
		// no thirdperson in multiplayer.
		return;
	}
#endif

#endif

	engine->GetViewAngles( viewangles );

	if( !m_fCameraInThirdPerson )
	{		
		m_fCameraInThirdPerson = true;

		
		m_vecCameraOffset[ YAW ] = viewangles[ YAW ]; 
		m_vecCameraOffset[ PITCH ] = viewangles[ PITCH ]; 
		m_vecCameraOffset[ 2 ] = CAM_SWITCH_DIST; 

		// Set model to player because when a map first loads
		// it doesn't set the model... sort of a hack.
		//C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
		//pPlayer->SetModel("player");
	}

	cam_command.SetValue( 0 );
}

/*
==============================
CAM_ToFirstPerson

==============================
*/
void CInput::CAM_ToFirstPerson(void)
{
	m_fCameraInThirdPerson = false;
	cam_command.SetValue( 0 );
}

/*
==============================
CAM_ToFirstPerson

==============================
*/
bool CInput::CAM_IsOrthographic(void) const
{
	return m_CameraIsOrthographic;
}


/*
==============================
CAM_ToFirstPerson

==============================
*/
void CInput::CAM_OrthographicSize(float& w, float& h) const
{
	w = c_orthowidth.GetFloat(); h = c_orthoheight.GetFloat();
}


/*
==============================
CAM_ToFirstPerson

==============================
*/
void CInput::CAM_ToOrthographic(void)
{	
	m_fCameraInThirdPerson = false;
	m_CameraIsOrthographic = true;
	cam_command.SetValue( 0 );
}

/*
==============================
CAM_StartMouseMove

==============================
*/
void CInput::CAM_StartMouseMove(void)
{
	float flSensitivity;
		
	//only move the cam with mouse if we are in third person.
	if ( m_fCameraInThirdPerson )
	{
		//set appropriate flags and initialize the old mouse position
		//variables for mouse camera movement
		if (!m_fCameraMovingWithMouse)
		{
			int cpx, cpy;

			m_fCameraMovingWithMouse=true;
			m_fCameraInterceptingMouse=true;
			
			GetMousePos(cpx, cpy);

			m_nCameraX = cpx;
			m_nCameraY = cpy;

			if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 )
			{
				m_nCameraOldX=m_nCameraX*flSensitivity;
				m_nCameraOldY=m_nCameraY*flSensitivity;
			}
			else
			{
				m_nCameraOldX=m_nCameraX;
				m_nCameraOldY=m_nCameraY;
			}
		}
	}
	//we are not in 3rd person view..therefore do not allow camera movement
	else
	{   
		m_fCameraMovingWithMouse=false;
		m_fCameraInterceptingMouse=false;
	}
}

/*
==============================
CAM_EndMouseMove

the key has been released for camera movement
tell the engine that mouse camera movement is off
==============================
*/
void CInput::CAM_EndMouseMove(void)
{
   m_fCameraMovingWithMouse=false;
   m_fCameraInterceptingMouse=false;
}

/*
==============================
CAM_StartDistance

routines to start the process of moving the cam in or out 
using the mouse
==============================
*/
void CInput::CAM_StartDistance(void)
{
	//only move the cam with mouse if we are in third person.
	if ( m_fCameraInThirdPerson )
	{
	  //set appropriate flags and initialize the old mouse position
	  //variables for mouse camera movement
	  if (!m_fCameraDistanceMove)
	  {
		  int cpx, cpy;

		  m_fCameraDistanceMove=true;
		  m_fCameraMovingWithMouse=true;
		  m_fCameraInterceptingMouse=true;
		  GetMousePos(cpx, cpy);

		  m_nCameraX = cpx;
		  m_nCameraY = cpy;

		  m_nCameraOldX=m_nCameraX*gHUD.GetSensitivity();
		  m_nCameraOldY=m_nCameraY*gHUD.GetSensitivity();
	  }
	}
	//we are not in 3rd person view..therefore do not allow camera movement
	else
	{   
		m_fCameraDistanceMove=false;
		m_fCameraMovingWithMouse=false;
		m_fCameraInterceptingMouse=false;
	}
}

/*
==============================
CAM_EndDistance

the key has been released for camera movement
tell the engine that mouse camera movement is off
==============================
*/
void CInput::CAM_EndDistance(void)
{
   m_fCameraDistanceMove=false;
   m_fCameraMovingWithMouse=false;
   m_fCameraInterceptingMouse=false;
}

/*
==============================
CAM_IsThirdPerson

==============================
*/
int CInput::CAM_IsThirdPerson( void )
{
	return m_fCameraInThirdPerson;
}

/*
==============================
CAM_GetCameraOffset

==============================
*/
void CInput::CAM_GetCameraOffset( Vector& ofs )
{
	VectorCopy( m_vecCameraOffset, ofs );
}

/*
==============================
CAM_InterceptingMouse

==============================
*/
int CInput::CAM_InterceptingMouse( void )
{
	return m_fCameraInterceptingMouse;
}

static ConCommand startpitchup( "+campitchup", CAM_PitchUpDown );
static ConCommand endpitcup( "-campitchup", CAM_PitchUpUp );
static ConCommand startpitchdown( "+campitchdown", CAM_PitchDownDown );
static ConCommand endpitchdown( "-campitchdown", CAM_PitchDownUp );
static ConCommand startcamyawleft( "+camyawleft", CAM_YawLeftDown );
static ConCommand endcamyawleft( "-camyawleft", CAM_YawLeftUp );
static ConCommand startcamyawright( "+camyawright", CAM_YawRightDown );
static ConCommand endcamyawright( "-camyawright", CAM_YawRightUp );
static ConCommand startcamin( "+camin", CAM_InDown );
static ConCommand endcamin( "-camin", CAM_InUp );
static ConCommand startcamout( "+camout", CAM_OutDown );
static ConCommand camout( "-camout", CAM_OutUp );
static ConCommand thirdperson( "thirdperson", ::CAM_ToThirdPerson,
                               "Switch to thirdperson camera.", FCVAR_CHEAT );
static ConCommand firstperson( "firstperson", ::CAM_ToFirstPerson, "Switch to firstperson camera." );
static ConCommand camortho( "camortho", ::CAM_ToOrthographic,
                            "Switch to orthographic camera.", FCVAR_CHEAT );
static ConCommand startcammousemove( "+cammousemove",::CAM_StartMouseMove);
static ConCommand endcammousemove( "-cammousemove",::CAM_EndMouseMove);
static ConCommand startcamdistance( "+camdistance", ::CAM_StartDistance );
static ConCommand endcamdistance( "-camdistance", ::CAM_EndDistance );
static ConCommand snapto( "snapto", CAM_ToggleSnapto );
/*
==============================
Init_Camera

==============================
*/
void CInput::Init_Camera( void )
{
	m_CameraIsOrthographic = false;
}

c_basecombatweapon.cpp

Функция DrawModel должен выглядеть так:

//-----------------------------------------------------------------------------
// Purpose: Render the weapon. Draw the Viewmodel if the weapon's being carried
//			by this player, otherwise draw the worldmodel.
//-----------------------------------------------------------------------------
int C_BaseCombatWeapon::DrawModel( int flags )
{
	VPROF_BUDGET( "C_BaseCombatWeapon::DrawModel", VPROF_BUDGETGROUP_MODEL_RENDERING );
	if ( !m_bReadyToDraw )
		return 0;

	if ( !IsVisible() )
		return 0;

	// check if local player chases owner of this weapon in first person
	C_BasePlayer *localplayer = C_BasePlayer::GetLocalPlayer();

	// Get rid of view model, crosshair and weapon in 3rd person
	// Once we actually get weapons working, we'll let it draw only the weapon
	if (localplayer)
	{
		if (input->CAM_IsThirdPerson())
		{
                        if(localplayer == GetOwner())
                        {
			SetModel( GetWorldModel() );
			localplayer->m_Local.m_iHideHUD |= HIDEHUD_CROSSHAIR;
			return false;
			//return BaseClass:: DrawModel( flags ); 
                                                                   /* Uncomment this if you want to be
                                                                    able to do weapon things
                                                                    (it will display the weapon). */
                        }
		}
	} 

	if ( localplayer && localplayer->IsObserver() && GetOwner() )
	{
		// don't draw weapon if chasing this guy as spectator
		// we don't check that in ShouldDraw() since this may change
		// without notification 
		
		if ( localplayer->GetObserverMode() == OBS_MODE_IN_EYE &&
			 localplayer->GetObserverTarget() == GetOwner() ) 
			return false;
	}

	return BaseClass::DrawModel( flags );
}

См. также