M PlayerAnimState: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
(now actually animates! blend sequences get stuck though :-/)
Line 2: Line 2:


There are two versions: <code>CBasePlayerAnimState</code> and <code>CMultiPlayerAnimState</code>.
There are two versions: <code>CBasePlayerAnimState</code> and <code>CMultiPlayerAnimState</code>.
{{note|Your player must be using a model set up with the appropriate [[blend sequence]]s for any of this to work. Unfortunately there are several different schemes floating around: Ep1, OB and Counter-Strike players are all driven by different sequences! Check <code>m_PlayerAnimState->SetupPoseParameters()</code> to see what your code is looking for.}}


== Usage ==
== Usage ==


; <code>Update( [[float]] eyeYaw, float eyePitch )</code>
; <code>Update( [[float]] eyeYaw, float eyePitch )</code>
: Manages ambient, looping animations (running/swimming, aiming, breathing) based on player velocity and look direction every frame. Typically called from:
: Manages ambient, looping animations (running/swimming, aiming, breathing) based on player velocity and look direction every frame. {{tip|<code>CMultiPlayerAnimState</code> will have your model playing one of the <code>ACT_MP</code> activities (search in Visual Studio's Class View for a list). You will probably want to add [[acttable_t|activity translation tables]] to your weapons to turn these into activities pertaining to the weapon currently being held. Missing or incomplete translation tables are the number one cause of "jesus pose" players.}} {{note|Your player model must be set up with the appropriate [[blend sequence]]s for this to work. Unfortunately there are several different schemes floating around: Ep1, OB and Counter-Strike players are all driven differently. Check <code>SetupPoseParameters()</code> to see what your AnimState object is looking for.}}
:* <code>CBasePlayer::PostThink()</code>
:* <code>C_BasePlayer::UpdateClientSideAnimation()</code>
; <code>DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 )</code>
; <code>DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 )</code>
: Begins a discrete, event-based animation (crouching, shooting, reloading) whenever called. <code>PlayerAnimEvent_t</code> is an enum value that defines what type of animation event this is; it is translated into an [[activity]] elsewhere depending on the status of the player (weapon held, swimming, etc).
: Begins a discrete, event-based animation (crouching, shooting, reloading) whenever called. <code>PlayerAnimEvent_t</code> is an enum value that defines what type of animation event this is; it is translated into an [[activity]] elsewhere depending on the status of the player (weapon held, swimming, etc).
Line 83: Line 79:
MDLCACHE_CRITICAL_SECTION();
MDLCACHE_CRITICAL_SECTION();
m_PlayerAnimState->DoAnimationEvent( event, nData );
m_PlayerAnimState->DoAnimationEvent( event, nData );
}
</source>
You will also want to expand <code>TranslateActivity()</code> to poll weapons for [[acttable_t|activity translation tables]]:
<source lang=cpp>
Activity CMultiPlayerAnimState::TranslateActivity( Activity actDesired )
{
// Existing swimming code...
if ( GetBasePlayer()->GetActiveWeapon() )
actDesired = GetBasePlayer()->GetActiveWeapon()->ActivityOverride( actDesired, false );
return actDesired;
}
}
</source>
</source>

Revision as of 15:45, 2 February 2010

The m_PlayerAnimState object maintains a player's animation state. It is shared code.

There are two versions: CBasePlayerAnimState and CMultiPlayerAnimState.

Usage

Update( float eyeYaw, float eyePitch )
Manages ambient, looping animations (running/swimming, aiming, breathing) based on player velocity and look direction every frame.
Tip.pngTip:CMultiPlayerAnimState will have your model playing one of the ACT_MP activities (search in Visual Studio's Class View for a list). You will probably want to add activity translation tables to your weapons to turn these into activities pertaining to the weapon currently being held. Missing or incomplete translation tables are the number one cause of "jesus pose" players.
Note.pngNote:Your player model must be set up with the appropriate blend sequences for this to work. Unfortunately there are several different schemes floating around: Ep1, OB and Counter-Strike players are all driven differently. Check SetupPoseParameters() to see what your AnimState object is looking for.
DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 )
Begins a discrete, event-based animation (crouching, shooting, reloading) whenever called. PlayerAnimEvent_t is an enum value that defines what type of animation event this is; it is translated into an activity elsewhere depending on the status of the player (weapon held, swimming, etc).

Implementation

You must define m_PlayerAnimState in both your client and server classes:

class CMyPlayer : public CBasePlayer // and on client!
{
	// ...
	CMultiPlayerAnimState* m_PlayerAnimState;
	// ...
};

And then initialise it in shared code:

inline void CMyPlayer::Spawn_Shared()
{
	MultiPlayerMovementData_t mv;
	mv.m_flSprintSpeed = -1;
	mv.m_flRunSpeed = 200;
	mv.m_flWalkSpeed = 80;
	mv.m_flBodyYawRate = 180;
	m_PlayerAnimState = new CMultiPlayerAnimState( this,mv );

	UseClientSideAnimation();
}

Now you need to hook things up. On the server:

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

	// Keep the model upright; pose params will handle pitch aiming.
	QAngle angles = GetLocalAngles();
	angles[PITCH] = 0;
	SetLocalAngles( angles );

	m_PlayerAnimState->Update( EyeAngles()[YAW], EyeAngles()[PITCH] );
}

void CMyPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
{
	m_PlayerAnimState->DoAnimationEvent( event, nData );
	TE_PlayerAnimEvent( this, event, nData );	// Transmit to other clients. Comment this out in SP.
}

And on the client:

#include "prediction.h"
#include "c_basetempentity.h"

void C_MyPlayer::UpdateClientSideAnimation()
{
	m_PlayerAnimState->Update( EyeAngles()[YAW], EyeAngles()[PITCH] );
}

void C_MyPlayer::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
{
	if ( IsLocalPlayer() && prediction->InPrediction() && !prediction->IsFirstTimePredicted() ) )
		return;
 
	MDLCACHE_CRITICAL_SECTION();
	m_PlayerAnimState->DoAnimationEvent( event, nData );
}

You will also want to expand TranslateActivity() to poll weapons for activity translation tables:

Activity CMultiPlayerAnimState::TranslateActivity( Activity actDesired )
{
	
	// Existing swimming code...

	if ( GetBasePlayer()->GetActiveWeapon() )
		actDesired = GetBasePlayer()->GetActiveWeapon()->ActivityOverride( actDesired, false );

	return actDesired;
}

Dispatching to clients

In multiplayer you must dispatch animation events to all onlooking clients, a job which is not performed by CBasePlayer. See m_PlayerAnimState/TempEnt for the temporary entity used by Valve.