How do idPlayer angles work?

From modwiki

Jump to: navigation, search

Each frame of the game the player gets a chance to Think. In idPlayer::Think a call is made to EvaluateControls which checks the state of the players usercmd (controls passed from engine) and updates state of the player accordingly.

EvaluateControls calls UpdateViewAngles which is responsible for setting up the player’s viewAngles based on the usercmd.angles passed from the engine.

 
// circularly clamp the angles with deltas
for ( i = 0; i < 3; i++ ) {
	cmdAngles[i] = SHORT2ANGLE( usercmd.angles[i] );
	if ( influenceActive == INFLUENCE_LEVEL3 ) {
		viewAngles[i] += idMath::ClampFloat( -1.0f, 1.0f, idMath::AngleDelta( idMath::AngleNormalize180( SHORT2ANGLE( usercmd.angles[i]) + deltaViewAngles[i] ) , viewAngles[i] ) );
	} else {
		viewAngles[i] = idMath::AngleNormalize180( SHORT2ANGLE( usercmd.angles[i]) + deltaViewAngles[i] );
	}
}

cmdAngles is the idAngles representation of usercmd.angles, which is an array of shorts. I think they are converted to shorts for more efficient network synchronization, but not sure. Anyway, SHORTTOANGLE scales a short value 1-65536 to an angle 1-360. The loop above first sets up the cmdAngles and then sets the viewAngles to the usercmd.angle + the deltaViewAngle.

The deltaViewAngles of a player during normal walking around and turning seems to always be 0’s. I looked around the codebase and found:

 
// delta view angles to allow movers to rotate the view of the actor
const idAngles & GetDeltaViewAngles( void ) const;
void SetDeltaViewAngles( const idAngles &delta );
 

So it seems that deltaViewAngles are specifically for outside influence of the players view angles. I will look at an example of this “exterior influence� later. So under “normal� circumstances with no outside influence the loop above sets the viewAngles equal to the usercmd.angles passed from the engine. I will assume no such influence exists for now (because my test map doesn’t have any, whahahahahha)

Later in UpdateViewAngles you will see:

 
	// orient the model towards the direction we're looking
	SetAngles( idAngles( 0, viewAngles.yaw, 0 ) );

SetAngles is called given an idAngles that represents the players current yaw .

 
/*
================
idEntity::SetAngles
================
*/
void idEntity::SetAngles( const idAngles &ang ) {
	SetAxis( ang.ToMat3() );
}

Convert the angles to a an idMat3 and pass it along.

 
/*
================
idEntity::SetAxis
================
*/
void idEntity::SetAxis( const idMat3 &axis ) {
 
	if ( GetPhysics()->IsType( idPhysics_Actor::Type ) ) {
		static_cast<idActor *>(this)->viewAxis = axis;
	} else {
		GetPhysics()->SetAxis( axis );
	}
 
	UpdateVisuals();
}

In this case we have an idPhysics_Player, which inherits from idPhysics_Actor, so we set the viewAxis (declared at the idActor level) to the axis which was transformed from the current yaw of the viewAngles.

Then we call UpdateVisuals:

 
/*
================
idEntity::UpdateVisuals
================
*/
void idEntity::UpdateVisuals( void ) {
	UpdateModel();
	UpdateSound();
}

Which calls UpdateModel, which along with other things calls UpdateModelTransform:

 
/*
================
idEntity::UpdateModelTransform
================
*/
void idEntity::UpdateModelTransform( void ) {
	idVec3 origin;
	idMat3 axis;
 
	if ( GetPhysicsToVisualTransform( origin, axis ) ) {
		renderEntity.axis = axis * GetPhysics()->GetAxis();
		renderEntity.origin = GetPhysics()->GetOrigin() + origin * renderEntity.axis;
	} else {
		renderEntity.axis = GetPhysics()->GetAxis();
		renderEntity.origin = GetPhysics()->GetOrigin();
	}
}

UpdateModelTransform first calls idPlayers GetPhysicsToVisualTransform, which in one codepath (the easy one ;)) just sets axis and origin like so:

 
} else {
 
	axis = viewAxis;
	origin = modelOffset;
}
return true;

So the viewAxis set to our yaw earlier is now used to set the renderEntity.axis (look above)

Now, after the angles are updated and we get back to Think() a call to Move() is made.

In Move() you will find:

 
physicsObj.SetPlayerInput( usercmd, viewAngles );

SetPlayerInput just passes the state we have been looking at onto the idPlayer_Physics object so it can use it later for processing. Move then calls:

 
RunPhysics();

RunPhysics is implemented in idEntity. In it’s implementation you can find:

 
moved = part->physics->Evaluate( endTime - startTime, endTime );

Evaluate calls into the idPhysics_Player object for player specific physics evaluation. It makes a call to

 
idPhysics_Player::MovePlayer( timeStepMSec );

In MovePlayer we finally see some setup for view stuff

 
	// view vectors
	viewAngles.ToVectors( &viewForward, NULL, NULL );
	viewForward *= clipModelAxis;
	viewRight = gravityNormal.Cross( viewForward );
	viewRight.Normalize();

I am wondering if viewForward and viewRight are used like in Programming Game AI by Example. If they are: The heading and side vectors define a local coordinate system for the player. Note that the local coordinate system is aligned to the player’s view.

MovePlayer then calls:

 
idPhysics_Player::WalkMove();

WalkMove uses the vectors viewForward and viewRight that have been set up from viewAngles to define the wish direction, wish speed, and acceleration. The implementation details are still tough for me �

TODO: FIGURE OUT HOW WALKMOVE WORKS AND ADD IT TO THE ANNOTATED API

WalkMove then passes these to idPhysics_Player::Accelerate. Accelerate is an interesting method, with two implementations. The second implementation matches my book to the T, the first produces a better feel I guess.

So I am fuzzy on a lot of details about implementation down at the WalkMove and Accelerate level. Vectors representing direction, acceleration, force, the kitchen sink. But at this point one thing is clear. Based on the players viewAngles, which were updated to match the usercmd.angles (barring outside influence beyond the mouse input) we have applied physics to the player to update his position, velocity, and stuff.

More later...

Personal tools
Main
id Tech 5