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

From Valve Developer Community
Jump to: navigation, search
English (en)русский (ru)
... Icon-Important.png
Icon-broom.png
This article or section needs to be cleaned up to conform to a higher standard of quality.
For help, see the VDC Editing Help and Wikipedia cleanup process. Also, remember to check for any notes left by the tagger at this article's talk page.


Эта статья не подходит для движка 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.pngNote:ВЫ можете изменить 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.pngNote:Если вы планируете добавить еще команды с клавиатуры, вы можете просто добавить:
#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 );
}

См. также