Ru/Third Person Camera

== Эта статья не подходит для движка Orange Box ==
Для Orange Box версии движка смотрите статью 
==Обзор==
В этом уроке описано, как сделать вид от третьего лица со следующими функциями:
* Обнаружение столкновения
* Масштабирование колесиком мыши
* Прозрачность модели, если камера слишком близко
* Скрытие рук Гордона в режиме от третьего лица
* Скрытие оружия в режиме от третьего лица (или первого лица)
* Скрытие crosshair в режиме от третьего лица (или первого лица)
* Скрытие модели игрока в режиме от первого лица
* Добавление кнопки переключения
Спасибо за Third Person Camera статьям сThe Wavelength. Этот туториал модификация нескольких статьей, удобна для понимания.
Спасибо за перевод Google Переводчик
==Шаг первый: in_camera.cpp==
Это руководство предполагает, что вы используете Single Player Mod и Microsoft Visual Studio 2003/2005/2008/2010.
<BR>Откройте 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;
}
В пределах этого куска кода:
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)
#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 );
} 
</DIV>
==
выше код должен идти внутрь hl2_player.cpp. это, то должна быть определена в hl2_player.h
поэтому в строке 174 поставить:
void SetAnimation ( PLAYER_ANIM playerAnim );
==
==Заключение==
Теперь вы имеете рабочий вид от третьего/первого лица. Если вы хотите назначить кнопку по умолчания для "+camchange", смотрите вики статьи.
Если вы не скрывают модели игрока и оружия, вы увидите, уродливые модели, которая должна представлять Гордона Фримена. 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 );
}
== См. также ==
*
*