Ноги в режиме от первого лица

From Valve Developer Community
Jump to: navigation, search
English

Примечание: Работает только в 2007 версии движка( OB )

Это не работает в мультиплеере, потому что заменяет модель thirdperson на модель без рук и головы.

Примечание:Не работает в 2013 версии движка

Рекомендуется

  • Valve's Source Engine code ( 2007 ) Single Player.
  • Программы для 3д моделирование ( XSI, 3DS Max, Blender etc )
  • Модели ( доступные здесь Here ) <-- Исправленные текстуры
  • Мозг

Система анимации.

Вам необходимо использовать код Malortie для работы.

Создайте два файла в shared папке вашего мода.

Первый это "singleplayer_animstate.h".

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Single Player animation state 'handler'. This utility is used
//            to evaluate the pose parameter value based on the direction
//            and speed of the player.
//
//====================================================================================//

#ifndef SINGLEPLAYER_ANIMSTATE_H
#define SINGLEPLAYER_ANIMSTATE_H
#ifdef _WIN32
#pragma once
#endif

#include "cbase.h"

#ifdef CLIENT_DLL
#include "c_baseplayer.h"
#else
#include "player.h"
#endif

class CSinglePlayerAnimState
{
public:
    enum
    {
        TURN_NONE = 0,
        TURN_LEFT,
        TURN_RIGHT
    };

    CSinglePlayerAnimState( CBasePlayer *pPlayer );

    void Init( CBasePlayer *pPlayer );

    Activity            BodyYawTranslateActivity( Activity activity );

    void                Update();

    const QAngle&        GetRenderAngles();
               
    void                GetPoseParameters( CStudioHdr *pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM] );

    CBasePlayer        *GetBasePlayer();

    void Release();

private:
    void                GetOuterAbsVelocity( Vector& vel );

    int                    ConvergeAngles( float goal,float maxrate, float dt, float& current );

    void                EstimateYaw( void );
    void                ComputePoseParam_BodyYaw( void );
    void                ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
    void                ComputePoseParam_BodyLookYaw( void );
    void                ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr );
    void                ComputePlaybackRate();

    CBasePlayer        *m_pPlayer;

    float                m_flGaitYaw;
    float                m_flStoredCycle;

    float                m_flGoalFeetYaw;
    float                m_flCurrentFeetYaw;

    float                m_flCurrentTorsoYaw;

    float                m_flLastYaw;
    float                m_flLastTurnTime;

    int                    m_nTurningInPlace;

    QAngle                m_angRender;

    float                m_flTurnCorrectionTime;
};

CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer );

#endif // SINGLEPLAYER_ANIMSTATE_H


Файл завершен добавляем второй файл "singleplayer_animstate.cpp"


//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Single Player animation state 'handler'. This utility is used
//            to evaluate the pose parameter value based on the direction
//            and speed of the player.
//
//====================================================================================//

#include "cbase.h"
#include "singleplayer_animstate.h"
#include "tier0/vprof.h"
#include "animation.h"
#include "studio.h"
#include "apparent_velocity_helper.h"
#include "utldict.h"
#include "filesystem.h"

extern ConVar mp_facefronttime, mp_feetyawrate, mp_ik;

#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION        15.0f

CSinglePlayerAnimState *CreatePlayerAnimationState( CBasePlayer *pPlayer )
{
    MDLCACHE_CRITICAL_SECTION();

    CSinglePlayerAnimState *pState = new CSinglePlayerAnimState( pPlayer );
    pState->Init(pPlayer);

    return pState;
}

// Below this many degrees, slow down turning rate linearly
#define FADE_TURN_DEGREES    45.0f
// After this, need to start turning feet
#define MAX_TORSO_ANGLE        90.0f
// Below this amount, don't play a turning animation/perform IK
#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION        15.0f

//static ConVar tf2_feetyawrunscale( "tf2_feetyawrunscale", "2", FCVAR_REPLICATED, "Multiplier on tf2_feetyawrate to allow turning faster when running." );
extern ConVar sv_backspeed;
extern ConVar mp_feetyawrate;
extern ConVar mp_facefronttime;
extern ConVar mp_ik;

CSinglePlayerAnimState::CSinglePlayerAnimState( CBasePlayer *pPlayer ): m_pPlayer( pPlayer )
{
    m_flGaitYaw = 0.0f;
    m_flGoalFeetYaw = 0.0f;
    m_flCurrentFeetYaw = 0.0f;
    m_flCurrentTorsoYaw = 0.0f;
    m_flLastYaw = 0.0f;
    m_flLastTurnTime = 0.0f;
    m_flTurnCorrectionTime = 0.0f;

    m_pPlayer = NULL;
};

void CSinglePlayerAnimState::Init( CBasePlayer *pPlayer )
{
    m_pPlayer = pPlayer;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::Update()
{
    m_angRender = GetBasePlayer()->GetLocalAngles();

    ComputePoseParam_BodyYaw();
    ComputePoseParam_BodyPitch(GetBasePlayer()->GetModelPtr());
    ComputePoseParam_BodyLookYaw();
    ComputePoseParam_HeadPitch(GetBasePlayer()->GetModelPtr());

    ComputePlaybackRate();
}

void CSinglePlayerAnimState::Release()
{
    delete this;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePlaybackRate()
{
    // Determine ideal playback rate
    Vector vel;
    GetOuterAbsVelocity( vel );

    float speed = vel.Length2D();

    bool isMoving = ( speed > 0.5f ) ? true : false;

    float maxspeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
   
    if ( isMoving && ( maxspeed > 0.0f ) )
    {
        float flFactor = 1.0f;

        // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
        GetBasePlayer()->SetPlaybackRate( ( speed * flFactor ) / maxspeed );

        // BUG BUG:
        // This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed
    }
    else
    {
        GetBasePlayer()->SetPlaybackRate( 1.0f );
    }
}

//-----------------------------------------------------------------------------
// Purpose:
// Output : CBasePlayer
//-----------------------------------------------------------------------------
CBasePlayer *CSinglePlayerAnimState::GetBasePlayer()
{
    return m_pPlayer;
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : dt -
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::EstimateYaw( void )
{
    float dt = gpGlobals->frametime;

    if ( !dt )
    {
        return;
    }

    Vector est_velocity;
    QAngle    angles;

    GetOuterAbsVelocity( est_velocity );

    angles = GetBasePlayer()->GetLocalAngles();

    if ( est_velocity[1] == 0 && est_velocity[0] == 0 )
    {
        float flYawDiff = angles[YAW] - m_flGaitYaw;
        flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360;
        if (flYawDiff > 180)
            flYawDiff -= 360;
        if (flYawDiff < -180)
            flYawDiff += 360;

        if (dt < 0.25)
            flYawDiff *= dt * 4;
        else
            flYawDiff *= dt;

        m_flGaitYaw += flYawDiff;
        m_flGaitYaw = m_flGaitYaw - (int)(m_flGaitYaw / 360) * 360;
    }
    else
    {
        m_flGaitYaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI);

        if (m_flGaitYaw > 180)
            m_flGaitYaw = 180;
        else if (m_flGaitYaw < -180)
            m_flGaitYaw = -180;
    }
}

//-----------------------------------------------------------------------------
// Purpose: Override for backpeddling
// Input  : dt -
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyYaw( void )
{
    int iYaw = GetBasePlayer()->LookupPoseParameter( "move_yaw" );
    if ( iYaw < 0 )
        return;

    // view direction relative to movement
    float flYaw;     

    EstimateYaw();

    QAngle    angles = GetBasePlayer()->GetLocalAngles();
    float ang = angles[ YAW ];
    if ( ang > 180.0f )
    {
        ang -= 360.0f;
    }
    else if ( ang < -180.0f )
    {
        ang += 360.0f;
    }

    // calc side to side turning
    flYaw = ang - m_flGaitYaw;
    // Invert for mapping into 8way blend
    flYaw = -flYaw;
    flYaw = flYaw - (int)(flYaw / 360) * 360;

    if (flYaw < -180)
    {
        flYaw = flYaw + 360;
    }
    else if (flYaw > 180)
    {
        flYaw = flYaw - 360;
    }
   
    GetBasePlayer()->SetPoseParameter( iYaw, flYaw );

#ifndef CLIENT_DLL
        //Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
        GetBasePlayer()->SetLocalAngles( QAngle( GetBasePlayer()->EyeAngles().x, m_flCurrentFeetYaw, 0 ) );
#endif
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
{
    // Get pitch from v_angle
    float flPitch = GetBasePlayer()->GetLocalAngles()[ PITCH ];

    if ( flPitch > 180.0f )
    {
        flPitch -= 360.0f;
    }
    flPitch = clamp( flPitch, -90, 90 );

    QAngle absangles = GetBasePlayer()->GetAbsAngles();
    absangles.x = 0.0f;
    m_angRender = absangles;

    // See if we have a blender for pitch
    GetBasePlayer()->SetPoseParameter( pStudioHdr, "aim_pitch", flPitch );
}

//-----------------------------------------------------------------------------
// Purpose:
// Input  : goal -
//            maxrate -
//            dt -
//            current -
// Output : int
//-----------------------------------------------------------------------------
int CSinglePlayerAnimState::ConvergeAngles( float goal,float maxrate, float dt, float& current )
{
    int direction = TURN_NONE;

    float anglediff = goal - current;
    float anglediffabs = fabs( anglediff );

    anglediff = AngleNormalize( anglediff );

    float scale = 1.0f;
    if ( anglediffabs <= FADE_TURN_DEGREES )
    {
        scale = anglediffabs / FADE_TURN_DEGREES;
        // Always do at least a bit of the turn ( 1% )
        scale = clamp( scale, 0.01f, 1.0f );
    }

    float maxmove = maxrate * dt * scale;

    if ( fabs( anglediff ) < maxmove )
    {
        current = goal;
    }
    else
    {
        if ( anglediff > 0 )
        {
            current += maxmove;
            direction = TURN_LEFT;
        }
        else
        {
            current -= maxmove;
            direction = TURN_RIGHT;
        }
    }

    current = AngleNormalize( current );

    return direction;
}

void CSinglePlayerAnimState::ComputePoseParam_BodyLookYaw( void )
{
    QAngle absangles = GetBasePlayer()->GetAbsAngles();
    absangles.y = AngleNormalize( absangles.y );
    m_angRender = absangles;

    // See if we even have a blender for pitch
    int upper_body_yaw = GetBasePlayer()->LookupPoseParameter( "aim_yaw" );
    if ( upper_body_yaw < 0 )
    {
        return;
    }

    // Assume upper and lower bodies are aligned and that we're not turning
    float flGoalTorsoYaw = 0.0f;
    int turning = TURN_NONE;
    float turnrate = 360.0f;

    Vector vel;
   
    GetOuterAbsVelocity( vel );

    bool isMoving = ( vel.Length() > 1.0f ) ? true : false;

    if ( !isMoving )
    {
        // Just stopped moving, try and clamp feet
        if ( m_flLastTurnTime <= 0.0f )
        {
            m_flLastTurnTime    = gpGlobals->curtime;
            m_flLastYaw            = GetBasePlayer()->EyeAngles().y;
            // Snap feet to be perfectly aligned with torso/eyes
            m_flGoalFeetYaw        = GetBasePlayer()->EyeAngles().y;
            m_flCurrentFeetYaw    = m_flGoalFeetYaw;
            m_nTurningInPlace    = TURN_NONE;
        }

        // If rotating in place, update stasis timer

        if ( m_flLastYaw != GetBasePlayer()->EyeAngles().y )
        {
            m_flLastTurnTime    = gpGlobals->curtime;
            m_flLastYaw            = GetBasePlayer()->EyeAngles().y;
        }

        if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
        {
            m_flLastTurnTime    = gpGlobals->curtime;
        }

        turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );

        QAngle eyeAngles = GetBasePlayer()->EyeAngles();
        QAngle vAngle = GetBasePlayer()->GetLocalAngles();

        // See how far off current feetyaw is from true yaw
        float yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;
        yawdelta = AngleNormalize( yawdelta );

        bool rotated_too_far = false;

        float yawmagnitude = fabs( yawdelta );

        // If too far, then need to turn in place
        if ( yawmagnitude > 45 )
        {
            rotated_too_far = true;
        }

        // Standing still for a while, rotate feet around to face forward
        // Or rotated too far
        // FIXME:  Play an in place turning animation
        if ( rotated_too_far ||
            ( gpGlobals->curtime > m_flLastTurnTime + mp_facefronttime.GetFloat() ) )
        {
            m_flGoalFeetYaw        = GetBasePlayer()->EyeAngles().y;
            m_flLastTurnTime    = gpGlobals->curtime;

        /*    float yd = m_flCurrentFeetYaw - m_flGoalFeetYaw;
            if ( yd > 0 )
            {
                m_nTurningInPlace = TURN_RIGHT;
            }
            else if ( yd < 0 )
            {
                m_nTurningInPlace = TURN_LEFT;
            }
            else
            {
                m_nTurningInPlace = TURN_NONE;
            }

            turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw );
            yawdelta = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;*/

        }

        // Snap upper body into position since the delta is already smoothed for the feet
        flGoalTorsoYaw = yawdelta;
        m_flCurrentTorsoYaw = flGoalTorsoYaw;
    }
    else
    {
        m_flLastTurnTime = 0.0f;
        m_nTurningInPlace = TURN_NONE;
        m_flCurrentFeetYaw = m_flGoalFeetYaw = GetBasePlayer()->EyeAngles().y;
        flGoalTorsoYaw = 0.0f;
        m_flCurrentTorsoYaw = GetBasePlayer()->EyeAngles().y - m_flCurrentFeetYaw;
    }

    if ( turning == TURN_NONE )
    {
        m_nTurningInPlace = turning;
    }

    if ( m_nTurningInPlace != TURN_NONE )
    {
        // If we're close to finishing the turn, then turn off the turning animation
        if ( fabs( m_flCurrentFeetYaw - m_flGoalFeetYaw ) < MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION )
        {
            m_nTurningInPlace = TURN_NONE;
        }
    }

    // Rotate entire body into position
    absangles = GetBasePlayer()->GetAbsAngles();
    absangles.y = m_flCurrentFeetYaw;
    m_angRender = absangles;

    GetBasePlayer()->SetPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -60.0f, 60.0f ) );

    /*
    // FIXME: Adrian, what is this?
    int body_yaw = GetBasePlayer()->LookupPoseParameter( "body_yaw" );

    if ( body_yaw >= 0 )
    {
        GetBasePlayer()->SetPoseParameter( body_yaw, 30 );
    }
    */

}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSinglePlayerAnimState::ComputePoseParam_HeadPitch( CStudioHdr *pStudioHdr )
{
    // Get pitch from v_angle
    int iHeadPitch = GetBasePlayer()->LookupPoseParameter("head_pitch");

    float flPitch = GetBasePlayer()->EyeAngles()[PITCH];

    if ( flPitch > 180.0f )
    {
        flPitch -= 360.0f;
    }
    flPitch = clamp( flPitch, -90, 90 );

    QAngle absangles = GetBasePlayer()->GetAbsAngles();
    absangles.x = 0.0f;
    m_angRender = absangles;

    GetBasePlayer()->SetPoseParameter( pStudioHdr, iHeadPitch, flPitch );
}

 
//-----------------------------------------------------------------------------
// Purpose:
// Input  : activity -
// Output : Activity
//-----------------------------------------------------------------------------
Activity CSinglePlayerAnimState::BodyYawTranslateActivity( Activity activity )
{
    // Not even standing still, sigh
    if ( activity != ACT_IDLE )
        return activity;

    // Not turning
    switch ( m_nTurningInPlace )
    {
    default:
    case TURN_NONE:
        return activity;
    /*
    case TURN_RIGHT:
        return ACT_TURNRIGHT45;
    case TURN_LEFT:
        return ACT_TURNLEFT45;
    */
    case TURN_RIGHT:
    case TURN_LEFT:
        return mp_ik.GetBool() ? ACT_TURN : activity;
    }

    Assert( 0 );
    return activity;
}

const QAngle& CSinglePlayerAnimState::GetRenderAngles()
{
    return m_angRender;
}

void CSinglePlayerAnimState::GetOuterAbsVelocity( Vector& vel )
{
#if defined( CLIENT_DLL )
    GetBasePlayer()->EstimateAbsVelocity( vel );
#else
    vel = GetBasePlayer()->GetAbsVelocity();
#endif
}


Полная реализация

В "c_baseplayer.cpp" иищем следующие функцию:

bool IsInFreezeCam( void )

И внизу добавляем:

bool IsInEye( void )
{
	C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
	if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
	return true;
}


Потом, в этом файле ищем:

bool C_BasePlayer::ShouldDraw()

И заменяем на:

bool C_BasePlayer::ShouldDraw()
{
	return BaseClass::ShouldDraw();
}

static ConVar cl_legs("cl_legs", "1", FCVAR_CHEAT, "Enable or disable player leg rendering", true, 0, true, 1);
static ConVar cl_legs_origin_shift("cl_legs_origin_shift", "-17", FCVAR_CHEAT, "Amount in game units to shift the player model relative to the direction the player is facing");
static ConVar cl_legs_clip_height("cl_legs_clip_height", "0", FCVAR_CHEAT, "Amount in game units of the player model to render up to [0 = disable]", true, 0, false, 0);

const Vector& C_BasePlayer::GetRenderOrigin( void )
{
	// If we're not observing this player, or if we're not drawing it at the
	// moment then use the normal absolute origin.
	// NOTE: the GetCurrentlyDrawingEntity check is here to make sure the
	// shadow is rendered from the correct origin
	if(!IsInEye() || view->GetCurrentlyDrawingEntity() != this)
		return BaseClass::GetRenderOrigin();
	
	// Get the forward vector
	static Vector forward; // static because this method returns a reference
	AngleVectors(GetRenderAngles(), &forward);
	
	// Shift the render origin by a fixed amount
	forward *= cl_legs_origin_shift.GetFloat();
	forward += GetAbsOrigin();
	
	return forward;
}


Теперь в функции
int C_BasePlayer::DrawModel( int flags )
Добавляем:
CMatRenderContextPtr context(materials);

        if(cl_legs_clip_height.GetInt() > 0)
        {
                context->SetHeightClipMode(MATERIAL_HEIGHTCLIPMODE_RENDER_BELOW_HEIGHT);
                context->SetHeightClipZ(GetAbsOrigin().z+cl_legs_clip_height.GetFloat());
        }


Теперь, ищем функцию
void C_BasePlayer::AddEntity( void )
и под этим
// Add in lighting effects
CreateLightEffects();

добавляем

SetLocalAnglesDim(X_INDEX, 0 );


Сейчас, в "c_baseplayer.h", ищем

bool IsInFreezeCam( void );

и под этим добавляем:

bool IsInEye( void );

В этом же файле ищем:

virtual int DrawModel( int flags );

И добавляем:

const Vector& C_BasePlayer::GetRenderOrigin();


Потом, открываем "hl2_player.cpp" и добавляем
#define PLAYER_MODEL "models/player.mdl"

После всех #define.


Сейчас ищем:
void CHL2_Player::Precache( void )

И добавляем

PrecacheModel(PLAYER_MODEL);


Теперь, ищем
void CHL2_Player::Spawn(void)

и ищем следующею линию

SetModel( "models/player.mdl" );

и заменяем на

SetModel( PLAYER_MODEL );


Сейчас, Ищем

CHL2_Player::~CHL2_Player( void )

и заменяем на:

	
CHL2_Player::~CHL2_Player( void )
{
	// FPLEGS - Destructor defualt empty! Added code below!
	// Clears the animation state.
	if ( m_pPlayerAnimState != NULL )
	{
	    m_pPlayerAnimState->Release();
	    m_pPlayerAnimState = NULL;
	}
}


Так, ищем

CHL2_Player::CHL2_Player()

и заменяем на:

CHL2_Player::CHL2_Player()
{
	// FPLEGS
	m_pPlayerAnimState = CreatePlayerAnimationState(this);
	m_angEyeAngles.Init();
	// FPLEGS END

	m_nNumMissPositions	= 0;
	m_pPlayerAISquad = 0;
	m_bSprintEnabled = true;

	m_flArmorReductionTime = 0.0f;
	m_iArmorReductionFrom = 0;
}


Сейчас, поднимите голову верх:
void CHL2_Player::PostThink( void )

и замените на:

void CHL2_Player::PostThink( void )
{
	BaseClass::PostThink();

	if ( !g_fGameOver && !IsPlayerLockedInPlace() && IsAlive() )
	{
		 HandleAdmireGlovesAnimation();
	}

	// FPLEGS
	m_angEyeAngles = EyeAngles();
	QAngle angles = GetLocalAngles();
	angles[PITCH] = 0;
	SetLocalAngles( angles );
	m_pPlayerAnimState->Update();
}


Сейчас,Добавьте это в конец файла:

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_HL2MP_RUN;
 
    if ( playerAnim == PLAYER_JUMP )
    {
        if ( HasWeapons() )
            idealActivity = ACT_HL2MP_JUMP;
        else
            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_HL2MP_GESTURE_RANGE_ATTACK;
        }
    }
    else if ( playerAnim == PLAYER_RELOAD )
    {
        idealActivity = ACT_HL2MP_GESTURE_RELOAD;
    }
    else if ( playerAnim == PLAYER_IDLE || playerAnim == PLAYER_WALK )
    {
        if ( !( GetFlags() & FL_ONGROUND ) && ( GetActivity( ) == ACT_HL2MP_JUMP || GetActivity( ) == ACT_JUMP ) )    // Still jumping
        {
            idealActivity = GetActivity( );
        }   
        else if ( GetWaterLevel() > 1 )
        {
            if ( speed == 0 )
            {
                if ( HasWeapons() )
                    idealActivity = ACT_HL2MP_IDLE;
                else
                    idealActivity = ACT_IDLE;
            }
            else
            {
                if ( HasWeapons() )
                    idealActivity = ACT_HL2MP_RUN;
                else
                    idealActivity = ACT_RUN;
            }
        }
        else
        {
            if ( GetFlags() & FL_DUCKING )
            {
                if ( speed > 0 )
                {
                    if ( HasWeapons() )
                        idealActivity = ACT_HL2MP_WALK_CROUCH;
                    else
                        idealActivity = ACT_WALK_CROUCH;
                }
                else
                {
                    if ( HasWeapons() )
                        idealActivity = ACT_HL2MP_IDLE_CROUCH;
                    else
                        idealActivity = ACT_COVER_LOW;
                }
            }
            else
            {
                if ( speed > 0 )
                {
                    {
                        if ( HasWeapons() )
                            idealActivity = ACT_HL2MP_RUN;
                        else
                        {
                            if ( speed > HL2_WALK_SPEED + 20.0f )
                                idealActivity = ACT_RUN;
                            else
                                idealActivity = ACT_WALK;
                        }
                    }
                }
                else
                {
                    if ( HasWeapons() )
                    idealActivity = ACT_HL2MP_IDLE;
                    else
                    idealActivity = ACT_IDLE;
                }
            }
        }
 
        //idealActivity = TranslateTeamActivity( idealActivity );
    }
 
    if ( IsInAVehicle() )
    {
        idealActivity = ACT_COVER_LOW;
    }
 
    if ( idealActivity == ACT_HL2MP_GESTURE_RANGE_ATTACK )
    {
        RestartGesture( Weapon_TranslateActivity( idealActivity ) );
 
        // FIXME: this seems a bit wacked
        Weapon_SetActivity( Weapon_TranslateActivity( ACT_RANGE_ATTACK1 ), 0 );
 
        return;
    }
    else if ( idealActivity == ACT_HL2MP_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.h" и добавляем
#include "singleplayer_animstate.h"

в начала файла.


Сейчас, идем в конец "public:" в классе
class CHL2_Player : public
и добавляем
void SetAnimation( PLAYER_ANIM playerAnim );


сейчас,идём в конец класс, в "private:" секцую добавляем

	CSinglePlayerAnimState *m_pPlayerAnimState;
	QAngle m_angEyeAngles;

Weapon activity list tables

в weapon_357.cpp:

В описание класса, ниже макроса "DECLARE_DATADESC()", добавляем следующею линию:

DECLARE_ACTTABLE();

ниже класса на 50 линию,где-то добавляем следующею таблицу :

acttable_t CWeapon357::m_acttable[] =
{
    { ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_PISTOL,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_PISTOL,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_PISTOL,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_PISTOL,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_PISTOL,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_PISTOL,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_PISTOL,                false },
};

IMPLEMENT_ACTTABLE( CWeapon357 );

в weapon_ar2.cpp:

There is already an activity list. At it's foot, after // { ACT_RANGE_ATTACK2, ACT_RANGE_ATTACK_AR2_GRENADE, true },

add the following list:

{ ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_AR2,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_AR2,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_AR2,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_AR2,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_AR2,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_GESTURE_RELOAD_SMG1,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_AR2,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_AR2,                false },

In weapon_crossbow.cpp:

In the class description, around line 450, under the macro "DECLARE_DATADESC()", add this line:

DECLARE_ACTTABLE();

Under the class definition around line 489, add this activity table list:

acttable_t CWeaponCrossbow::m_acttable[] =
{
    { ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_CROSSBOW,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_CROSSBOW,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_CROSSBOW,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_CROSSBOW,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_CROSSBOW,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_CROSSBOW,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_CROSSBOW,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_SHOTGUN,                false },
};

IMPLEMENT_ACTTABLE( CWeaponCrossbow );


In weapon_crowbar.cpp:

There is already an activity list. At it's foot, after { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false },

add the following list:

{ ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_SLAM, true },
    { ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_MELEE,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_MELEE,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_MELEE,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_MELEE,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_MELEE,            false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_MELEE,                    false },

In weapon_frag.cpp:

There is already an activity list. At it's foot, after { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true },

add the following list:

{ ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_GRENADE,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_GRENADE,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_GRENADE,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_GRENADE,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_GRENADE,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_GRENADE,        false },
    { ACT_HL2MP_JUMP,

In weapon_physcannon.cpp:

In the class description, around line 1203, under the macro "DECLARE_DATADESC()", add this line:

DECLARE_ACTTABLE();

Under the class definition around line 1374, add this activity table list:

acttable_t CWeaponPhysCannon::m_acttable[] =
{
    { ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_PHYSGUN,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_PHYSGUN,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_PHYSGUN,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_PHYSGUN,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_PHYSGUN,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_PHYSGUN,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_PHYSGUN,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_SLAM,                false },
};

IMPLEMENT_ACTTABLE( CWeaponPhysCannon );


In weapon_pistol.cpp:

There is already an activity list. At it's foot, after { ACT_RUN, ACT_RUN_PISTOL, false },

add the following list:

{ ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_PISTOL,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_PISTOL,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_PISTOL,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_PISTOL,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_PISTOL,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_PISTOL,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_PISTOL,                false },

In weapon_rpg.cpp:

There is already an activity list. At it's foot, after { ACT_COVER_LOW, ACT_COVER_LOW_RPG, true },

add the following list:

{ ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_RPG,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_RPG,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_RPG,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_RPG,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_RPG,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_RPG,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_RPG,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_RPG,                false },


In weapon_shotgun.cpp:

There is already an activity list. At it's foot, after { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },

add the following list:

{ ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_SHOTGUN,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_SHOTGUN,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_SHOTGUN,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_SHOTGUN,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_SHOTGUN,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_HL2MP_GESTURE_RELOAD_SHOTGUN,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_SHOTGUN,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_SHOTGUN,                false },

In weapon_smg1.cpp:

There is already an activity list. At it's foot, after { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, true },

add the following list:

{ ACT_HL2MP_IDLE,                    ACT_HL2MP_IDLE_SMG1,                    false },
    { ACT_HL2MP_RUN,                    ACT_HL2MP_RUN_SMG1,                    false },
    { ACT_HL2MP_IDLE_CROUCH,            ACT_HL2MP_IDLE_CROUCH_SMG1,            false },
    { ACT_HL2MP_WALK_CROUCH,            ACT_HL2MP_WALK_CROUCH_SMG1,            false },
    { ACT_HL2MP_GESTURE_RANGE_ATTACK,    ACT_HL2MP_GESTURE_RANGE_ATTACK_SMG1,    false },
    { ACT_HL2MP_GESTURE_RELOAD,            ACT_GESTURE_RELOAD_SMG1,        false },
    { ACT_HL2MP_JUMP,                    ACT_HL2MP_JUMP_SMG1,                    false },
    { ACT_RANGE_ATTACK1,                ACT_RANGE_ATTACK_SMG1,                false },

Создание модели

Если ты хочешь создать свою модель, скачайте оригинальные player.mdl SMD файлы вот ссылка здесь.

При создание модели делайте её как gordon_body_ref.smd или как на картинки здесь.

Конечный продукт

Посмотрите конечный продукт здесь на youtube.

Благодарность

  • Код анимации для сингла - Malortie
  • Weapon Activity Tables - Malortie
  • Другое - Zombie Killa
  • Gordon Freeman - VALVe and DPFilms
  • Туториал - ExoBacon
  • Перевёл - я