//----------------------------------------------------------------------------- // 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 ); } }
float CSDKPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving ) { // Get the player's current velocity and speed. Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); float flSpeed = vecVelocity.Length2D(); // Determine if the player is considered moving or not. bool bMoving = ( flSpeed > MOVING_MINIMUM_SPEED ); // Initialize the return data. *bIsMoving = false; float flReturn = 1.0f; // If we are moving. if ( bMoving ) { // float flGroundSpeed = GetInterpolatedGroundSpeed(); float flGroundSpeed = GetCurrentMaxGroundSpeed(); if ( flGroundSpeed < 0.001f ) { flReturn = 0.01; } else { // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below flReturn = flSpeed / flGroundSpeed; flReturn = clamp( flReturn, 0.01f, 10.0f ); } *bIsMoving = true; } return flReturn; }
float CBasePlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving ) { // Determine ideal playback rate Vector vel; GetOuterAbsVelocity( vel ); float speed = vel.Length2D(); bool isMoving = ( speed > MOVING_MINIMUM_SPEED ); *bIsMoving = false; float flReturnValue = 1; if ( isMoving && CanThePlayerMove() ) { float flGroundSpeed = GetInterpolatedGroundSpeed(); if ( flGroundSpeed < 0.001f ) { flReturnValue = 0.01; } else { // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below flReturnValue = speed / flGroundSpeed; flReturnValue = clamp( flReturnValue, 0.01, 10 ); // don't go nuts here. } *bIsMoving = true; } return flReturnValue; }
void CSDKPlayerAnimState::EstimateYaw( void ) { // Get the frame time. float flDeltaTime = gpGlobals->frametime * m_pSDKPlayer->GetSlowMoMultiplier(); if ( flDeltaTime == 0.0f ) return; // Get the player's velocity and angles. Vector vecEstVelocity; GetOuterAbsVelocity( vecEstVelocity ); QAngle angles = GetBasePlayer()->GetLocalAngles(); // If we are not moving, sync up the feet and eyes slowly. if (m_pSDKPlayer->m_Shared.IsProne()) { // Don't touch it } else if ( vecEstVelocity.x == 0.0f && vecEstVelocity.y == 0.0f ) { float flYawDelta = angles[YAW] - m_PoseParameterData.m_flEstimateYaw; flYawDelta = AngleNormalize( flYawDelta ); if ( flDeltaTime < 0.25f ) { flYawDelta *= ( flDeltaTime * 4.0f ); } else { flYawDelta *= flDeltaTime; } m_PoseParameterData.m_flEstimateYaw += flYawDelta; m_PoseParameterData.m_flEstimateYaw = AngleNormalize( m_PoseParameterData.m_flEstimateYaw ); } else if (m_pSDKPlayer->m_Shared.IsAimedIn() || m_pSDKPlayer->m_Shared.IsDiving() || m_pSDKPlayer->m_Shared.IsRolling() || m_pSDKPlayer->m_Shared.IsSliding()) { m_PoseParameterData.m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI ); m_PoseParameterData.m_flEstimateYaw = clamp( m_PoseParameterData.m_flEstimateYaw, -180.0f, 180.0f ); } else { QAngle angDir; VectorAngles(vecEstVelocity, angDir); if (fabs(AngleNormalize(angDir[YAW] - m_flEyeYaw)) <= 90) m_bFacingForward = true; else if (fabs(AngleNormalize(angDir[YAW] - m_flEyeYaw)) >= 91) m_bFacingForward = false; float flYawDelta = AngleNormalize(m_flGoalFeetYaw - m_flCurrentFeetYaw); if (m_bFacingForward) m_PoseParameterData.m_flEstimateYaw = flYawDelta; else m_PoseParameterData.m_flEstimateYaw = 180-flYawDelta; } }
//----------------------------------------------------------------------------- // Purpose: bool CPortalPlayerAnimState::HandleJumping( Activity &idealActivity ) { Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); if ( ( vecVelocity.z > 300.0f || m_bInAirWalk ) ) { // Check to see if we were in an airwalk and now we are basically on the ground. if ( GetBasePlayer()->GetFlags() & FL_ONGROUND ) { m_bInAirWalk = false; RestartMainSequence(); RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND ); } else { // In an air walk. idealActivity = ACT_MP_AIRWALK; m_bInAirWalk = true; } } // Jumping. else { if ( m_bJumping ) { if ( m_bFirstJumpFrame ) { m_bFirstJumpFrame = false; RestartMainSequence(); // Reset the animation. } // Don't check if he's on the ground for a sec.. sometimes the client still has the // on-ground flag set right when the message comes in. else if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f ) { if ( GetBasePlayer()->GetFlags() & FL_ONGROUND ) { m_bJumping = false; RestartMainSequence(); RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND ); } } // if we're still jumping if ( m_bJumping ) { idealActivity = ACT_MP_JUMP_START; } } } if ( m_bJumping || m_bInAirWalk ) return true; return false; }
//----------------------------------------------------------------------------- // Purpose: bool CSDKPlayerAnimState::HandleJumping( Activity &idealActivity ) { Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); if ( m_bJumping ) { if ( m_bFirstJumpFrame ) { m_bFirstJumpFrame = false; RestartMainSequence(); // Reset the animation. } // Reset if we hit water and start swimming. if ( m_pSDKPlayer->GetWaterLevel() >= WL_Waist ) { m_bJumping = false; RestartMainSequence(); } // Don't check if he's on the ground for a sec.. sometimes the client still has the // on-ground flag set right when the message comes in. else if ( m_pSDKPlayer->GetCurrentTime() - m_flJumpStartTime > 0.2f ) { if ( m_pSDKPlayer->GetFlags() & FL_ONGROUND ) { m_bJumping = false; RestartMainSequence(); RestartGesture( GESTURE_SLOT_JUMP, ACT_DA_JUMP_LAND ); } } // if we're still jumping if ( m_bJumping ) { if ( m_pSDKPlayer->GetCurrentTime() - m_flJumpStartTime > 0.5 ) idealActivity = ACT_DA_JUMP_FLOAT; else idealActivity = ACT_DA_JUMP_START; } } if (!m_bJumping && !(m_pSDKPlayer->GetFlags() & FL_ONGROUND) && !m_pSDKPlayer->m_Shared.IsSliding () && !m_pSDKPlayer->m_Shared.IsRolling () && m_pSDKPlayer->GetAbsVelocity ().z < -270) { idealActivity = ACT_DA_JUMP_FLOAT; return true; } if ( m_bJumping ) return true; return false; }
//----------------------------------------------------------------------------- // Purpose: // Input : dt - //----------------------------------------------------------------------------- void CBasePlayerAnimState::EstimateYaw() { Vector est_velocity; GetOuterAbsVelocity( est_velocity ); float flLength = est_velocity.Length2D(); if ( flLength > MOVING_MINIMUM_SPEED ) { m_flGaitYaw = atan2( est_velocity[1], est_velocity[0] ); m_flGaitYaw = RAD2DEG( m_flGaitYaw ); m_flGaitYaw = AngleNormalize( m_flGaitYaw ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPlayerAnimState::ComputePlaybackRate() { // Determine ideal playback rate Vector vel; GetOuterAbsVelocity( vel ); float speed = vel.Length2D(); bool isMoving = ( speed > 0.5f ) ? true : false; Activity currentActivity = GetOuter()->GetSequenceActivity( GetOuter()->GetSequence() ); switch ( currentActivity ) { case ACT_WALK: case ACT_RUN: case ACT_IDLE: { float maxspeed = GetOuter()->MaxSpeed(); if ( isMoving && ( maxspeed > 1.0f ) ) { float flFactor = 1.0f; // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below float flWantedRate = ( speed * flFactor ) / maxspeed; flWantedRate = clamp( flWantedRate, 0.1, 10 ); // don't go nuts here. GetOuter()->SetPlaybackRate( flWantedRate ); // BUG BUG: // This stuff really should be m_flPlaybackRate = speed / m_flGroundSpeed } else { GetOuter()->SetPlaybackRate( 1.0f ); } } break; default: { GetOuter()->SetPlaybackRate( 1.0f ); } break; } }
//----------------------------------------------------------------------------- // 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: //----------------------------------------------------------------------------- void CSDKPlayerAnimState::EstimateYaw( void ) { // Get the frame time. float flDeltaTime = gpGlobals->frametime; if ( flDeltaTime == 0.0f ) return; // Get the player's velocity and angles. Vector vecEstVelocity; GetOuterAbsVelocity( vecEstVelocity ); QAngle angles = GetBasePlayer()->GetLocalAngles(); // If we are not moving, sync up the feet and eyes slowly. if ( vecEstVelocity.x == 0.0f && vecEstVelocity.y == 0.0f ) { float flYawDelta = angles[YAW] - m_PoseParameterData.m_flEstimateYaw; flYawDelta = AngleNormalize( flYawDelta ); if ( flDeltaTime < 0.25f ) { flYawDelta *= ( flDeltaTime * 4.0f ); } else { flYawDelta *= flDeltaTime; } m_PoseParameterData.m_flEstimateYaw += flYawDelta; AngleNormalize( m_PoseParameterData.m_flEstimateYaw ); } else { m_PoseParameterData.m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI ); m_PoseParameterData.m_flEstimateYaw = clamp( m_PoseParameterData.m_flEstimateYaw, -180.0f, 180.0f ); } }
void CSDKPlayerAnimState::ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr ) { if (m_pSDKPlayer->m_Shared.IsSliding() && !m_pSDKPlayer->m_Shared.IsDiveSliding()) { Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); QAngle angDir; VectorAngles(vecVelocity, angDir); //if (m_bFacingForward) m_flGoalFeetYaw = angDir[YAW]; //else // m_flGoalFeetYaw = AngleNormalize(angDir[YAW] + 180); m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw ); if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) { ConvergeYawAngles( m_flGoalFeetYaw, 720.0f, gpGlobals->frametime * m_pSDKPlayer->GetSlowMoMultiplier(), m_flCurrentFeetYaw ); m_flLastAimTurnTime = m_pSDKPlayer->GetCurrentTime(); } QAngle angSlide; VectorAngles(m_pSDKPlayer->m_Shared.GetSlideDirection(), angSlide); m_angRender[YAW] = angSlide.y; // Get the view yaw. float flAngle = AngleNormalize( m_flEyeYaw ); // Calc side to side turning - the view vs. movement yaw. float flAimYaw = angSlide.y - flAngle; flAimYaw = AngleNormalize( flAimYaw ); // Set the aim yaw and save. GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimYaw, flAimYaw ); m_DebugAnimData.m_flAimYaw = flAimYaw; // Turn off a force aim yaw - either we have already updated or we don't need to. m_bForceAimYaw = false; #ifndef CLIENT_DLL QAngle angle = GetBasePlayer()->GetAbsAngles(); angle[YAW] = m_flCurrentFeetYaw; GetBasePlayer()->SetAbsAngles( angle ); #endif return; } if (m_bFlipping) { m_angRender[YAW] = m_flEyeYaw; #ifndef CLIENT_DLL QAngle angle = GetBasePlayer()->GetAbsAngles(); angle[YAW] = m_flCurrentFeetYaw; GetBasePlayer()->SetAbsAngles( angle ); #endif return; } // Get the movement velocity. Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); // Check to see if we are moving. bool bMoving = ( vecVelocity.Length() > 1.0f ) ? true : false; if ( m_pSDKPlayer->m_Shared.IsProne() ) { m_flGoalFeetYaw = m_flCurrentFeetYaw = m_flEyeYaw; } else if ( bMoving || m_bForceAimYaw ) { if (m_pSDKPlayer->m_Shared.IsAimedIn() || m_pSDKPlayer->m_Shared.IsDiving() || m_pSDKPlayer->m_Shared.IsRolling() || m_pSDKPlayer->m_Shared.IsSliding()) { // The feet match the eye direction when moving - the move yaw takes care of the rest. m_flGoalFeetYaw = m_flEyeYaw; } else { QAngle angDir; VectorAngles(vecVelocity, angDir); if (m_bFacingForward) { m_flGoalFeetYaw = angDir[YAW]; } else { m_flGoalFeetYaw = AngleNormalize(angDir[YAW] + 180); } } } // Else if we are not moving. else { // Initialize the feet. if ( m_PoseParameterData.m_flLastAimTurnTime <= 0.0f ) { m_flGoalFeetYaw = m_flEyeYaw; m_flCurrentFeetYaw = m_flEyeYaw; m_PoseParameterData.m_flLastAimTurnTime = m_pSDKPlayer->GetCurrentTime(); } // Make sure the feet yaw isn't too far out of sync with the eye yaw. // TODO: Do something better here! else { float flYawDelta = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw ); if ( fabs( flYawDelta ) > 75.0f ) { float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f; m_flGoalFeetYaw += ( 75.0f * flSide ); } } } // Fix up the feet yaw. m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw ); if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) { if ( m_bForceAimYaw ) { m_flCurrentFeetYaw = m_flGoalFeetYaw; } else { ConvergeYawAnglesThroughZero( m_flGoalFeetYaw, 720.0f, gpGlobals->frametime * m_pSDKPlayer->GetSlowMoMultiplier(), m_flCurrentFeetYaw ); m_flLastAimTurnTime = m_pSDKPlayer->GetCurrentTime(); } } if (m_pSDKPlayer->m_Shared.IsDiving()) m_flCurrentFeetYaw = m_flGoalFeetYaw; // Rotate the body into position. m_angRender[YAW] = m_flCurrentFeetYaw; // Find the aim(torso) yaw base on the eye and feet yaws. float flAimYaw = m_flEyeYaw - m_flCurrentFeetYaw; if (m_pSDKPlayer->IsInThirdPerson()) flAimYaw = m_flCharacterEyeYaw - m_flCurrentFeetYaw; flAimYaw = AngleNormalize( flAimYaw ); // Set the aim yaw and save. GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimYaw, -flAimYaw ); m_DebugAnimData.m_flAimYaw = flAimYaw; // Turn off a force aim yaw - either we have already updated or we don't need to. m_bForceAimYaw = false; #ifndef CLIENT_DLL QAngle angle = GetBasePlayer()->GetAbsAngles(); angle[YAW] = m_flCurrentFeetYaw; GetBasePlayer()->SetAbsAngles( angle ); #endif }
//----------------------------------------------------------------------------- // Purpose: bool CTFPlayerAnimState::HandleJumping( Activity &idealActivity ) { Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); // Don't allow a firing heavy to jump or air walk. if ( m_pTFPlayer->GetPlayerClass()->IsClass( TF_CLASS_HEAVYWEAPONS ) && m_pTFPlayer->m_Shared.InCond( TF_COND_AIMING ) ) return false; // Handle air walking before handling jumping - air walking supersedes jump TFPlayerClassData_t *pData = m_pTFPlayer->GetPlayerClass()->GetData(); bool bValidAirWalkClass = ( pData && pData->m_bDontDoAirwalk == false ); if ( bValidAirWalkClass && ( vecVelocity.z > 300.0f || m_bInAirWalk ) ) { // Check to see if we were in an airwalk and now we are basically on the ground. if ( ( GetBasePlayer()->GetFlags() & FL_ONGROUND ) && m_bInAirWalk ) { m_bInAirWalk = false; RestartMainSequence(); RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND ); } else if ( GetBasePlayer()->GetWaterLevel() >= WL_Waist ) { // Turn off air walking and reset the animation. m_bInAirWalk = false; RestartMainSequence(); } else if ( ( GetBasePlayer()->GetFlags() & FL_ONGROUND ) == 0 ) { // In an air walk. idealActivity = ACT_MP_AIRWALK; m_bInAirWalk = true; } } // Jumping. else { if ( m_bJumping ) { // Remove me once all classes are doing the new jump TFPlayerClassData_t *pData = m_pTFPlayer->GetPlayerClass()->GetData(); bool bNewJump = ( pData && pData->m_bDontDoNewJump == false ); if ( m_bFirstJumpFrame ) { m_bFirstJumpFrame = false; RestartMainSequence(); // Reset the animation. } // Reset if we hit water and start swimming. if ( GetBasePlayer()->GetWaterLevel() >= WL_Waist ) { m_bJumping = false; RestartMainSequence(); } // Don't check if he's on the ground for a sec.. sometimes the client still has the // on-ground flag set right when the message comes in. else if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f ) { if ( GetBasePlayer()->GetFlags() & FL_ONGROUND ) { m_bJumping = false; RestartMainSequence(); if ( bNewJump ) { RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND ); } } } // if we're still jumping if ( m_bJumping ) { if ( bNewJump ) { if ( gpGlobals->curtime - m_flJumpStartTime > 0.5 ) { idealActivity = ACT_MP_JUMP_FLOAT; } else { idealActivity = ACT_MP_JUMP_START; } } else { idealActivity = ACT_MP_JUMP; } } } } if ( m_bJumping || m_bInAirWalk ) return true; return false; }
void CPlayerAnimState::ComputePoseParam_BodyYaw() { // See if we even have a blender for pitch int upper_body_yaw = GetOuter()->LookupPoseParameter( "body_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 = tf2_feetyawrate.GetFloat(); Vector vel; GetOuterAbsVelocity( vel ); bool isMoving = ( vel.Length() > 0.1f ) ? true : false; if ( isMoving ) { m_flLastTurnTime = 0.0f; m_nTurningInPlace = TURN_NONE; m_flGoalFeetYaw = m_flEyeYaw; flGoalTorsoYaw = 0.0f; turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw ); m_flCurrentTorsoYaw = m_flEyeYaw - m_flCurrentFeetYaw; } else { // Just stopped moving, try and clamp feet if ( m_flLastTurnTime <= 0.0f ) { m_flLastTurnTime = gpGlobals->curtime; m_flLastYaw = m_flEyeYaw; // Snap feet to be perfectly aligned with torso/eyes m_flGoalFeetYaw = m_flEyeYaw; m_flCurrentFeetYaw = m_flGoalFeetYaw; m_nTurningInPlace = TURN_NONE; } // If rotating in place, update stasis timer if ( m_flLastYaw != m_flEyeYaw ) { m_flLastTurnTime = gpGlobals->curtime; m_flLastYaw = m_flEyeYaw; } if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) { m_flLastTurnTime = gpGlobals->curtime; } turning = ConvergeAngles( m_flGoalFeetYaw, turnrate, gpGlobals->frametime, m_flCurrentFeetYaw ); // See how far off current feetyaw is from true yaw float yawdelta = m_flEyeYaw - 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 > MAX_TORSO_ANGLE ) { 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 + tf2_facefronttime.GetFloat() ) ) { m_flGoalFeetYaw = m_flEyeYaw; 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 = m_flEyeYaw - m_flCurrentFeetYaw; } // Snap upper body into position since the delta is already smoothed for the feet flGoalTorsoYaw = yawdelta; m_flCurrentTorsoYaw = flGoalTorsoYaw; } 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; } } // Counter rotate upper body as needed ConvergeAngles( flGoalTorsoYaw, turnrate, gpGlobals->frametime, m_flCurrentTorsoYaw ); // Rotate entire body into position m_angRender[YAW] = m_flCurrentFeetYaw; m_angRender[PITCH] = m_angRender[ROLL] = 0; SetOuterPoseParameter( upper_body_yaw, clamp( m_flCurrentTorsoYaw, -90.0f, 90.0f ) ); }
void CBasePlayerAnimState::ComputePoseParam_BodyYaw() { VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyYaw" ); // Find out which way he's running (m_flEyeYaw is the way he's looking). Vector vel; GetOuterAbsVelocity( vel ); bool bIsMoving = vel.Length2D() > MOVING_MINIMUM_SPEED; // If we just initialized this guy (maybe he just came into the PVS), then immediately // set his feet in the right direction, otherwise they'll spin around from 0 to the // right direction every time someone switches spectator targets. if ( !m_bCurrentFeetYawInitialized ) { m_bCurrentFeetYawInitialized = true; m_flGoalFeetYaw = m_flCurrentFeetYaw = m_flEyeYaw; m_flLastTurnTime = 0.0f; } else if ( bIsMoving ) { // player is moving, feet yaw = aiming yaw if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY || m_AnimConfig.m_LegAnimType == LEGANIM_8WAY ) { // His feet point in the direction his eyes are, but they can run in any direction. m_flGoalFeetYaw = m_flEyeYaw; } else { m_flGoalFeetYaw = RAD2DEG( atan2( vel.y, vel.x ) ); // If he's running backwards, flip his feet backwards. Vector vEyeYaw( cos( DEG2RAD( m_flEyeYaw ) ), sin( DEG2RAD( m_flEyeYaw ) ), 0 ); Vector vFeetYaw( cos( DEG2RAD( m_flGoalFeetYaw ) ), sin( DEG2RAD( m_flGoalFeetYaw ) ), 0 ); if ( vEyeYaw.Dot( vFeetYaw ) < -0.01 ) { m_flGoalFeetYaw += 180; } } } else if ( (gpGlobals->curtime - m_flLastTurnTime) > mp_facefronttime.GetFloat() ) { // player didn't move & turn for quite some time m_flGoalFeetYaw = m_flEyeYaw; } else { // If he's rotated his view further than the model can turn, make him face forward. float flDiff = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw ); if ( fabs(flDiff) > m_AnimConfig.m_flMaxBodyYawDegrees ) { if ( flDiff > 0 ) m_flGoalFeetYaw -= m_AnimConfig.m_flMaxBodyYawDegrees; else m_flGoalFeetYaw += m_AnimConfig.m_flMaxBodyYawDegrees; } } m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw ); if ( m_flCurrentFeetYaw != m_flGoalFeetYaw ) { ConvergeAngles( m_flGoalFeetYaw, GetFeetYawRate(), m_AnimConfig.m_flMaxBodyYawDegrees, gpGlobals->frametime, m_flCurrentFeetYaw ); m_flLastTurnTime = gpGlobals->curtime; } float flCurrentTorsoYaw = AngleNormalize( m_flEyeYaw - m_flCurrentFeetYaw ); // Rotate entire body into position m_angRender[YAW] = m_flCurrentFeetYaw; m_angRender[PITCH] = m_angRender[ROLL] = 0; SetOuterBodyYaw( flCurrentTorsoYaw ); g_flLastBodyYaw = flCurrentTorsoYaw; }
float CBasePlayerAnimState::GetOuterXYSpeed() const { Vector vel; GetOuterAbsVelocity( vel ); return vel.Length2D(); }
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: bool CHL2MPPlayerAnimState::HandleJumping( Activity &idealActivity ) { Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); if ( m_bJumping ) { static bool bNewJump = false; //Tony; hl2mp players only have a 'hop' if ( m_bFirstJumpFrame ) { m_bFirstJumpFrame = false; RestartMainSequence(); // Reset the animation. } // Reset if we hit water and start swimming. if ( m_pHL2MPPlayer->GetWaterLevel() >= WL_Waist ) { m_bJumping = false; RestartMainSequence(); } // Don't check if he's on the ground for a sec.. sometimes the client still has the // on-ground flag set right when the message comes in. else if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f ) { if ( m_pHL2MPPlayer->GetFlags() & FL_ONGROUND ) { m_bJumping = false; RestartMainSequence(); if ( bNewJump ) { RestartGesture( GESTURE_SLOT_JUMP, ACT_MP_JUMP_LAND ); } } } // if we're still jumping if ( m_bJumping ) { if ( bNewJump ) { if ( gpGlobals->curtime - m_flJumpStartTime > 0.5 ) { idealActivity = ACT_MP_JUMP_FLOAT; } else { idealActivity = ACT_MP_JUMP_START; } } else { idealActivity = ACT_MP_JUMP; } } } if ( m_bJumping ) return true; return false; }
// ----------------------------------------------------------------------------- void CBasePlayerAnimState::DebugShowAnimState( int iStartLine ) { Vector vOuterVel; GetOuterAbsVelocity( vOuterVel ); int iLine = iStartLine; AnimStatePrintf( iLine++, "main: %s(%d), cycle: %.2f cyclerate: %.2f playbackrate: %.2f\n", GetSequenceName( m_pOuter->GetModelPtr(), m_pOuter->GetSequence() ), m_pOuter->GetSequence(), m_pOuter->GetCycle(), m_pOuter->GetSequenceCycleRate(m_pOuter->GetModelPtr(), m_pOuter->GetSequence()), m_pOuter->GetPlaybackRate() ); if ( m_AnimConfig.m_LegAnimType == LEGANIM_8WAY ) { CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( MAIN_IDLE_SEQUENCE_LAYER ); AnimStatePrintf( iLine++, "idle: %s, weight: %.2f\n", GetSequenceName( m_pOuter->GetModelPtr(), pLayer->GetSequence() ), (float)pLayer->GetWeight() ); } for ( int i=0; i < m_pOuter->GetNumAnimOverlays()-1; i++ ) { CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( AIMSEQUENCE_LAYER + i ); #ifdef CLIENT_DLL AnimStatePrintf( iLine++, "%s(%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)", !pLayer->IsActive() ? "-- ": (pLayer->GetSequence() == 0 ? "-- " : (showanimstate_activities.GetBool()) ? GetSequenceActivityName( m_pOuter->GetModelPtr(), pLayer->GetSequence() ) : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->GetSequence() ) ), !pLayer->IsActive() ? 0 : (int)pLayer->GetSequence(), !pLayer->IsActive() ? 0 : (float)pLayer->GetWeight(), !pLayer->IsActive() ? 0 : (float)pLayer->GetCycle(), !pLayer->IsActive() ? 0 : (int)pLayer->GetOrder(), i ); #else AnimStatePrintf( iLine++, "%s(%d), flags (%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)", !pLayer->IsActive() ? "-- " : ( pLayer->GetSequence() == 0 ? "-- " : (showanimstate_activities.GetBool()) ? GetSequenceActivityName( m_pOuter->GetModelPtr(), pLayer->GetSequence() ) : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->GetSequence() ) ), !pLayer->IsActive() ? 0 : (int)pLayer->GetSequence(), !pLayer->IsActive() ? 0 : (int)pLayer->m_fFlags,// Doesn't exist on client !pLayer->IsActive() ? 0 : (float)pLayer->GetWeight(), !pLayer->IsActive() ? 0 : (float)pLayer->GetCycle(), !pLayer->IsActive() ? 0 : (int)pLayer->m_nOrder, i ); #endif } AnimStatePrintf( iLine++, "vel: %.2f, time: %.2f, MAX: %.2f, animspeed: %.2f", vOuterVel.Length2D(), gpGlobals->curtime, GetInterpolatedGroundSpeed(), m_pOuter->GetSequenceGroundSpeed(m_pOuter->GetSequence()) ); if ( m_AnimConfig.m_LegAnimType == LEGANIM_8WAY ) { AnimStatePrintf( iLine++, "ent yaw: %.2f, body_yaw: %.2f, move_yaw: %.2f, gait_yaw: %.2f, body_pitch: %.2f", m_angRender[YAW], g_flLastBodyYaw, m_flLastMoveYaw, m_flGaitYaw, g_flLastBodyPitch ); } else { AnimStatePrintf( iLine++, "ent yaw: %.2f, body_yaw: %.2f, body_pitch: %.2f, move_x: %.2f, move_y: %.2f", m_angRender[YAW], g_flLastBodyYaw, g_flLastBodyPitch, m_vLastMovePose.x, m_vLastMovePose.y ); } // Draw a red triangle on the ground for the eye yaw. float flBaseSize = 10; float flHeight = 80; Vector vBasePos = GetOuter()->GetAbsOrigin() + Vector( 0, 0, 3 ); QAngle angles( 0, 0, 0 ); angles[YAW] = m_flEyeYaw; Vector vForward, vRight, vUp; AngleVectors( angles, &vForward, &vRight, &vUp ); debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 255, 0, 0, 255, false, 0.01 ); // Draw a blue triangle on the ground for the body yaw. angles[YAW] = m_angRender[YAW]; AngleVectors( angles, &vForward, &vRight, &vUp ); debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 0, 0, 255, 255, false, 0.01 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2MPPlayerAnimState::EstimateYaw( void ) { // Get the frame time. float flDeltaTime = gpGlobals->frametime; if ( flDeltaTime == 0.0f ) return; #if 0 // 9way // Get the player's velocity and angles. Vector vecEstVelocity; GetOuterAbsVelocity( vecEstVelocity ); QAngle angles = GetBasePlayer()->GetLocalAngles(); // If we are not moving, sync up the feet and eyes slowly. if ( vecEstVelocity.x == 0.0f && vecEstVelocity.y == 0.0f ) { float flYawDelta = angles[YAW] - m_PoseParameterData.m_flEstimateYaw; flYawDelta = AngleNormalize( flYawDelta ); if ( flDeltaTime < 0.25f ) { flYawDelta *= ( flDeltaTime * 4.0f ); } else { flYawDelta *= flDeltaTime; } m_PoseParameterData.m_flEstimateYaw += flYawDelta; AngleNormalize( m_PoseParameterData.m_flEstimateYaw ); } else { m_PoseParameterData.m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI ); m_PoseParameterData.m_flEstimateYaw = clamp( m_PoseParameterData.m_flEstimateYaw, -180.0f, 180.0f ); } #else float dt = gpGlobals->frametime; // Get the player's velocity and angles. Vector vecEstVelocity; GetOuterAbsVelocity( vecEstVelocity ); QAngle angles = GetBasePlayer()->GetLocalAngles(); if ( vecEstVelocity.y == 0 && vecEstVelocity.x == 0 ) { float flYawDiff = angles[YAW] - m_PoseParameterData.m_flEstimateYaw; 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_PoseParameterData.m_flEstimateYaw += flYawDiff; m_PoseParameterData.m_flEstimateYaw = m_PoseParameterData.m_flEstimateYaw - (int)(m_PoseParameterData.m_flEstimateYaw / 360) * 360; } else { m_PoseParameterData.m_flEstimateYaw = (atan2(vecEstVelocity.y, vecEstVelocity.x) * 180 / M_PI); if (m_PoseParameterData.m_flEstimateYaw > 180) m_PoseParameterData.m_flEstimateYaw = 180; else if (m_PoseParameterData.m_flEstimateYaw < -180) m_PoseParameterData.m_flEstimateYaw = -180; } #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CHL2MPPlayerAnimState::ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr ) { // Get the movement velocity. Vector vecVelocity; GetOuterAbsVelocity( vecVelocity ); // Check to see if we are moving. bool bMoving = ( vecVelocity.Length() > 1.0f ) ? true : false; //DHL - Skillet #ifdef CLIENT_DLL if ( GetBasePlayer()->IsLocalPlayer() && input->CAM_IsThirdPerson() ) m_bForceAimYaw = true; #endif // If we are moving or are prone and undeployed. if ( bMoving || m_bForceAimYaw ) { // The feet match the eye direction when moving - the move yaw takes care of the rest. m_flGoalFeetYaw = m_flEyeYaw; } // Else if we are not moving. else { // Initialize the feet. if ( m_PoseParameterData.m_flLastAimTurnTime <= 0.0f ) { m_flGoalFeetYaw = m_flEyeYaw; m_flCurrentFeetYaw = m_flEyeYaw; m_PoseParameterData.m_flLastAimTurnTime = gpGlobals->curtime; } // Make sure the feet yaw isn't too far out of sync with the eye yaw. // TODO: Do something better here! else { float flYawDelta = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw ); if ( fabs( flYawDelta ) > 45.0f ) { float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f; m_flGoalFeetYaw += ( 45.0f * flSide ); } } } // Fix up the feet yaw. m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw ); if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) { if ( m_bForceAimYaw ) { m_flCurrentFeetYaw = m_flGoalFeetYaw; } else { ConvergeYawAngles( m_flGoalFeetYaw, 720.0f, gpGlobals->frametime, m_flCurrentFeetYaw ); m_flLastAimTurnTime = gpGlobals->curtime; } } // Rotate the body into position. m_angRender[YAW] = m_flCurrentFeetYaw; // Find the aim(torso) yaw base on the eye and feet yaws. float flAimYaw = m_flEyeYaw - m_flCurrentFeetYaw; flAimYaw = AngleNormalize( flAimYaw ); // Set the aim yaw and save. GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimYaw, flAimYaw ); m_DebugAnimData.m_flAimYaw = flAimYaw; // Turn off a force aim yaw - either we have already updated or we don't need to. m_bForceAimYaw = false; #ifndef CLIENT_DLL QAngle angle = GetBasePlayer()->GetAbsAngles(); angle[YAW] = m_flCurrentFeetYaw; GetBasePlayer()->SetAbsAngles( angle ); #endif }