Vector vecIronsightPosOffset;
QAngle angIronsightAngOffset;
float flIronsightFOVOffset;
weapon_parse.cpp
在 FileWeaponInfo_t::Parse: 里添加如下代码
KeyValues *pSights = pKeyValuesData->FindKey( "IronSight" );
if (pSights)
vecIronsightPosOffset.x = pSights->GetFloat( "forward", 0.0f );
vecIronsightPosOffset.y = pSights->GetFloat( "right", 0.0f );
vecIronsightPosOffset.z = pSights->GetFloat( "up", 0.0f );
angIronsightAngOffset[PITCH] = pSights->GetFloat( "pitch", 0.0f );
angIronsightAngOffset[YAW] = pSights->GetFloat( "yaw", 0.0f );
angIronsightAngOffset[ROLL] = pSights->GetFloat( "roll", 0.0f );
flIronsightFOVOffset = pSights->GetFloat( "fov", 0.0f );
//note: you can set a bool here if you'd like to disable ironsights for weapons with no IronSight-key
vecIronsightPosOffset = vec3_origin;
angIronsightAngOffset.Init();
flIronsightFOVOffset = 0.0f;
weapon_smg1.txt
这是一个如何在你的武器脚本里添加武器机瞄系统位移量数值的例子
IronSight
"forward" "-10"
"right" "-6.91"
"up" "0.185"
"roll" "-20"
"fov" "-20"
获取位移量
现在添加一些功能性代码来得到我们从武器脚本文件里解析到的位移量数值
额外添加一些 控制台变量(en) 来覆写掉旧的解析的数值,这样就可以很容易的通过 控制台(en)来改变新的武器模型偏移量数值。
在那之前, 我们需要在开头包含 "c_baseplayer.h" 头文件来允许使用一些代码,因为要在客户端进行一些处理,
basecombatweapon_shared.cpp
基本的, 你需要在包含 "c_baseplayer.h" 头文件时加上 #ifdef CLIENT_DLL 标签。不然编译的时候会出错。
#ifdef CLIENT_DLL
#include "c_baseplayer.h"
#endif
你应该加在这段代码的下面:(译者注:似乎不需要?)
#if defined ( TF_DLL ) || defined ( TF_CLIENT_DLL )
#include "tf_shareddefs.h"
#endif
basecombatweapon_shared.h
添加在 public 段
Vector GetIronsightPositionOffset( void ) const;
QAngle GetIronsightAngleOffset( void ) const;
float GetIronsightFOVOffset( void ) const;
basecombatweapon_shared.cpp
添加这些功能性代码 (直接做这一步会导致错误)
Vector CBaseCombatWeapon::GetIronsightPositionOffset( void ) const
if( viewmodel_adjust_enabled.GetBool() )
return Vector( viewmodel_adjust_forward.GetFloat(), viewmodel_adjust_right.GetFloat(), viewmodel_adjust_up.GetFloat() );
return GetWpnData().vecIronsightPosOffset;
QAngle CBaseCombatWeapon::GetIronsightAngleOffset( void ) const
if( viewmodel_adjust_enabled.GetBool() )
return QAngle( viewmodel_adjust_pitch.GetFloat(), viewmodel_adjust_yaw.GetFloat(), viewmodel_adjust_roll.GetFloat() );
return GetWpnData().angIronsightAngOffset;
float CBaseCombatWeapon::GetIronsightFOVOffset( void ) const
if( viewmodel_adjust_enabled.GetBool() )
return viewmodel_adjust_fov.GetFloat();
return GetWpnData().flIronsightFOVOffset;
basecombatweapon_shared.cpp
这些变量通常在包含头文件后定义
//forward declarations of callbacks used by viewmodel_adjust_enable and viewmodel_adjust_fov
void vm_adjust_enable_callback( IConVar *pConVar, char const *pOldString, float flOldValue );
void vm_adjust_fov_callback( IConVar *pConVar, const
char *pOldString, float flOldValue );
ConVar viewmodel_adjust_forward( "viewmodel_adjust_forward", "0", FCVAR_REPLICATED );
ConVar viewmodel_adjust_right( "viewmodel_adjust_right", "0", FCVAR_REPLICATED );
ConVar viewmodel_adjust_up( "viewmodel_adjust_up", "0", FCVAR_REPLICATED );
ConVar viewmodel_adjust_pitch( "viewmodel_adjust_pitch", "0", FCVAR_REPLICATED );
ConVar viewmodel_adjust_yaw( "viewmodel_adjust_yaw", "0", FCVAR_REPLICATED );
ConVar viewmodel_adjust_roll( "viewmodel_adjust_roll", "0", FCVAR_REPLICATED );
ConVar viewmodel_adjust_fov( "viewmodel_adjust_fov", "0", FCVAR_REPLICATED, "Note: this feature is not available during any kind of zoom", vm_adjust_fov_callback );
ConVar viewmodel_adjust_enabled( "viewmodel_adjust_enabled", "0", FCVAR_REPLICATED|FCVAR_CHEAT, "enabled viewmodel adjusting", vm_adjust_enable_callback );
包括这些:
void vm_adjust_enable_callback( IConVar *pConVar, char const *pOldString, float flOldValue )
ConVarRef sv_cheats( "sv_cheats" );
if( !sv_cheats.IsValid() || sv_cheats.GetBool() )
return;
ConVarRef var( pConVar );
if( var.GetBool() )
var.SetValue( "0" );
void vm_adjust_fov_callback( IConVar *pConVar, char const *pOldString, float flOldValue )
if( !viewmodel_adjust_enabled.GetBool() )
return;
ConVarRef var( pConVar );
CBasePlayer *pPlayer =
#ifdef GAME_DLL
UTIL_GetCommandClient();
#else
C_BasePlayer::GetLocalPlayer();
#endif
if( !pPlayer )
return;
if( !pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV() + var.GetFloat(), 0.1f ) )
Warning( "Could not set FOV\n" );
var.SetValue( "0" );
添加开启机瞄的函数系统
你肯定想要能使用上面定义好的机瞄系统
basecombatweapon_shared.h
添加这两个NetWork变量
CNetworkVar( bool, m_bIsIronsighted );
CNetworkVar( float, m_flIronsightedTime );
basecombatweapon_shared.cpp
在 CBaseCombatWeapon::CBaseCombatWeapon() 里添加两个构造函数,并给他们默认值
m_bIsIronsighted = false;
m_flIronsightedTime = 0.0f;
链接表 (位于DT_BaseCombatWeapon):
SendPropBool( SENDINFO( m_bIsIronsighted ) ),
SendPropFloat( SENDINFO( m_flIronsightedTime ) ),
RecvPropInt( RECVINFO( m_bIsIronsighted ), 0, RecvProxy_ToggleSights ), //note: RecvPropBool is actually RecvPropInt (see its implementation), but we need a proxy
RecvPropFloat( RECVINFO( m_flIronsightedTime ) ),
(译者注:SendProp应该和原先的同类定义放在一起,RecvPropInt也是如此)
我们需要一个 RecvProxy 在这个变量上,我们不想要布尔值更新,但我们想要通过在 服务器 端上的变化来开启机瞄
proxy(代理)系统的代码:
#ifdef CLIENT_DLL
void RecvProxy_ToggleSights( const CRecvProxyData* pData, void* pStruct, void* pOut )
CBaseCombatWeapon *pWeapon = (CBaseCombatWeapon*)pStruct;
if( pData->m_Value.m_Int )
pWeapon->EnableIronsights();
pWeapon->DisableIronsights();
#endif
预测(?)表(CBaseCombatWeapon):
DEFINE_PRED_FIELD( m_bIsIronsighted, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_flIronsightedTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
如果你想要在游戏里保存变量, 在数据描述里添加:
DEFINE_FIELD( m_bIsIronsighted, FIELD_BOOLEAN ),
DEFINE_FIELD( m_flIronsightedTime, FIELD_FLOAT ),
basecombatweapon_shared.h
添加机瞄变量的参数:
virtual bool HasIronsights( void ) { return true; } //default yes; override and return false for weapons with no ironsights (like weapon_crowbar)
bool IsIronsighted( void );
void ToggleIronsights( void );
void EnableIronsights( void );
void DisableIronsights
( void );
void SetIronsightTime( void );
basecombatweapon_shared.cpp
同时定义他们的函数:
bool CBaseCombatWeapon::IsIronsighted( void )
return ( m_bIsIronsighted || viewmodel_adjust_enabled.GetBool() );
void CBaseCombatWeapon::ToggleIronsights( void )
if( m_bIsIronsighted )
DisableIronsights();
EnableIronsights();
void CBaseCombatWeapon::EnableIronsights( void )
#ifdef CLIENT_DLL
if( !prediction->IsFirstTimePredicted() )
return;
#endif
if( !HasIronsights() || m_bIsIronsighted )
return;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if( !pOwner )
return;
if( pOwner->SetFOV( this, pOwner->GetDefaultFOV() + GetIronsightFOVOffset(), 1.0f ) ) //modify the last value to adjust how fast the fov is applied
m_bIsIronsighted = true;
SetIronsightTime();
void CBaseCombatWeapon::DisableIronsights( void )
#ifdef CLIENT_DLL
if( !prediction->IsFirstTimePredicted() )
return;
#endif
if( !HasIronsights() || !m_bIsIronsighted )
return;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if( !pOwner )
return;
if( pOwner->SetFOV( this, 0, 0.4f ) ) //modify the last value to adjust how fast the fov is applied
m_bIsIronsighted = false;
SetIronsightTime();
void CBaseCombatWeapon::SetIronsightTime( void )
m_flIronsightedTime = gpGlobals->curtime;
prediction 的使用需要在client端上包含 prediction.h 头文件。
Toggle-command
ConCommand
你也许需要设置一个 命令(en) 来在普通和机瞄模式中切换,你把它放在哪里都没关系(我是放在上面定义过的ConVar变量的后面),只要你已经包含了CBaseCombatWeapon和CBasePlayer的头文件(推荐就放在basecombatweapon_shared.cpp里)
#ifdef CLIENT_DLL
void CC_ToggleIronSights( void )
CBasePlayer* pPlayer = C_BasePlayer::GetLocalPlayer();
if( pPlayer == NULL )
return;
CBaseCombatWeapon *pWeapon = pPlayer->GetActiveWeapon();
if( pWeapon == NULL )
return;
pWeapon->ToggleIronsights();
engine->ServerCmd( "toggle_ironsight" ); //forward to server
static ConCommand toggle_ironsight("toggle_ironsight", CC_ToggleIronSights);
#endif
player.cpp
接着在CBasePlayer::ClientCommand里, 在返回false前添加:
else if( stricmp( cmd, "toggle_ironsight" ) == 0 )
CBaseCombatWeapon *pWeapon = GetActiveWeapon();
if( pWeapon != NULL )
pWeapon->ToggleIronsights();
return true;
自动切换机瞄模式
basecombatweapon_shared.cpp
添加
到下面的函数中:
- bool CBaseCombatWeapon::Holster( CBaseCombatWeapon *pSwitchingTo ) 切换武器
- bool CBaseCombatWeapon::DefaultReload( int iClipSize1, int iClipSize2, int iActivity ) 武器装填
- void CBaseCombatWeapon::Drop( const Vector &vecVelocity ) 扔掉武器(也许添加了扔武器的功能可以用?这个反正不是必须,只为上面两个添加,最后的效果也挺好
注意:bool CBaseCombatWeapon::DefaultDeploy - 在这里添加也可以,这样会在用完武器弹药后自动换枪时解除机瞄模式
weapon_shotgun.cpp
Find: bool CWeaponShotgun::StartReload( void )
在某处添加
DisableIronsights();
调整viewmodel
接下来最后一步就是将武器的手臂移动到我们想要的位置
仍然有一些小问题要调整, 尽管Viewmodel-bob(不太清楚这是什么)在使用机瞄时仍然在运作并且当viewmodel启用机瞄并旋转时,viewmodel会缓慢移动得太多
baseviewmodel_shared.cpp
void CBaseViewModel::CalcIronsights( Vector &pos, QAngle &ang )
CBaseCombatWeapon *pWeapon = GetOwningWeapon();
if ( !pWeapon )
return;
//get delta time for interpolation
float delta = ( gpGlobals->curtime - pWeapon->m_flIronsightedTime ) * 2.5f; //modify this value to adjust how fast the interpolation is
float exp = ( pWeapon->IsIronsighted() ) ?
( delta > 1.0f ) ? 1.0f : delta : //normal blending
( delta >
1.0f ) ? 0.0f : 1.0f - delta; //reverse interpolation
if( exp <= 0.001f ) //fully not ironsighted; save performance
return;
Vector newPos = pos;
QAngle newAng = ang;
Vector vForward, vRight, vUp, vOffset;
AngleVectors( newAng, &vForward, &vRight, &vUp );
vOffset = pWeapon->GetIronsightPositionOffset();
newPos += vForward * vOffset.x;
newPos += vRight * vOffset.y;
newPos += vUp * vOffset.z;
newAng += pWeapon->GetIronsightAngleOffset();
//fov is handled by CBaseCombatWeapon
pos += ( newPos - pos ) * exp;
ang += ( newAng - ang ) * exp;
让这段代码在CBaseViewModel::CalcViewModelView里运作:
void CBaseViewModel::CalcViewModelView( CBasePlayer *owner, const Vector& eyePosition, const QAngle& eyeAngles )
// UNDONE: Calc this on the server? Disabled for now as it seems unnecessary to have this info on the server
#if defined( CLIENT_DLL )
QAngle vmangoriginal = eyeAngles;
QAngle vmangles = eyeAngles;
Vector vmorigin = eyePosition;
CBaseCombatWeapon *pWeapon = m_hWeapon.Get();
//Allow weapon lagging
//only if not in ironsight-mode
if( pWeapon == NULL || !pWeapon->IsIronsighted() )
if ( pWeapon != NULL )
#if defined( CLIENT_DLL )
if ( !prediction->InPrediction() )
#endif
// add weapon-specific bob
pWeapon->AddViewmodelBob( this, vmorigin, vmangles );
// Add model-specific bob even if no weapon associated (for head bob for off hand models)
AddViewModelBob( owner, vmorigin, vmangles );
// Add lag
CalcViewModelLag( vmorigin, vmangles, vmangoriginal );
#if defined( CLIENT_DLL )
if ( !prediction->InPrediction() )
// Let the viewmodel shake at about 10% of the amplitude of the player's view
vieweffects->ApplyShake( vmorigin, vmangles, 0.1 );
#endif
CalcIronsights( vmorigin, vmangles );
SetLocalOrigin( vmorigin );
SetLocalAngles( vmangles );
#endif
baseviewmodel_shared.h
别忘了定义新的函数功能:
void CalcIronsights( Vector &pos, QAngle &ang );
单人模式修复 (武器模型不固定在机瞄视角上)
大多数时候武器模型(viewmodel) 启用机瞄后并不保持在绝对的位置上
修复挺简单(武器混合和混合出).
转到 basecombatweapon_shared.cpp
当你添加完EnableIronsight 和 DisableIronsight后,把他们修改成:
void CBaseCombatWeapon::EnableIronsights( void )
#ifdef CLIENT_DLL
if( !prediction->IsFirstTimePredicted() )
return;
#endif*/
if( !HasIronsights() || m_bIsIronsighted )
return;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if( !pOwner )
return;
if( pOwner->SetFOV( this, pOwner->GetDefaultFOV() + GetIronsightFOVOffset(), 0.4f ) ) //modify the last value to adjust how fast the fov is applied
m_bIsIronsighted = true;
SetIronsightTime();
void CBaseCombatWeapon::DisableIronsights( void )
#ifdef CLIENT_DLL
if( !prediction->IsFirstTimePredicted() )
return;
#endif*/
// We are not using prediction in singleplayer
if( !HasIronsights() || !m_bIsIronsighted )
return;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if( !pOwner )
return;
if( pOwner->SetFOV( this, 0, 0.2f ) ) //modify the last value to adjust how fast the fov is applied
m_bIsIronsighted = false;
SetIronsightTime();
--Dexter127(