void CPlayerRotation::Process() { //FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); // float forceLookLen2(m_player.m_stats.forceLookVector.len2()); if (forceLookLen2>0.001f && !g_vr->initialized()) // no forced look in VR please { float forceLookLen(cry_sqrtf(forceLookLen2)); Vec3 forceLook(m_player.m_stats.forceLookVector); forceLook *= 1.0f/forceLookLen; forceLook = m_player.m_viewQuatFinal.GetInverted() * forceLook; float smoothSpeed(6.6f * forceLookLen); m_deltaAngles.x += asin(forceLook.z) * min(1.0f,m_frameTime*smoothSpeed); m_deltaAngles.z += cry_atan2f(-forceLook.x,forceLook.y) * min(1.0f,m_frameTime*smoothSpeed); CHECKQNAN_VEC(m_deltaAngles); } ProcessAngularImpulses(); ProcessLean(); if (m_stats.inAir && m_stats.inZeroG) ProcessFlyingZeroG(); else if (m_stats.inFreefall.Value()==1) ProcessFreeFall(); else if (m_stats.inFreefall.Value()==2) ProcessParachute(); else { if(!g_vr->initialized()) { ProcessNormalRoll(); ClampAngles(); } ProcessNormal(); } //CHECKQNAN_MAT33(m_viewMtx); //update freelook when linked to an entity SLinkStats *pLinkStats = &m_player.m_linkStats; if (pLinkStats->linkID) { IEntity *pLinked = pLinkStats->GetLinked(); if (pLinked) { //at this point m_baseQuat and m_viewQuat contain the previous frame rotation, I'm using them to calculate the delta rotation. m_baseQuatLinked *= m_player.m_baseQuat.GetInverted() * m_baseQuat; m_viewQuatLinked *= m_player.m_viewQuat.GetInverted() * m_viewQuat; m_baseQuat = pLinked->GetRotation() * m_baseQuatLinked; m_viewQuat = pLinked->GetRotation() * m_viewQuatLinked; } } // m_viewQuatFinal = m_viewQuat; //TEST: * Quat::CreateRotationXYZ(m_player.m_viewAnglesOffset); }
void CPlayerRotation::ProcessParachute() { //thats necessary when passing from groundG to normalG //m_baseQuat = m_viewQuat; Ang3 desiredAngVel(m_deltaAngles.x, m_deltaAngles.y * 0.5f - m_deltaAngles.z * 1.0f, m_deltaAngles.z); float rotInertia(7.7f); //align to gravity vector Vec3 vRef(m_viewQuat.GetInverted() * Vec3(0, 0, 1)); float alignAngleY = cry_atan2f(vRef.x, vRef.z); desiredAngVel.y += alignAngleY * 0.05f; Interpolate(m_angularVel, desiredAngVel, rotInertia, m_frameTime); Ang3 finalAngle(m_angularVel + m_angularImpulseDelta); //limit Z angle float viewPitch(GetLocalPitch()); float zLimit(-1.3f); if (viewPitch + finalAngle.x < zLimit) { finalAngle.x = zLimit - viewPitch; } m_viewQuat *= Quat::CreateRotationZ(finalAngle.z) * Quat::CreateRotationX(finalAngle.x) * Quat::CreateRotationY(finalAngle.y); m_viewQuat.Normalize(); Vec3 up(Vec3(0, 0, 1)); Vec3 right(m_viewQuat.GetColumn0()); Vec3 forward((up % right).GetNormalized()); m_baseQuat = Quat(Matrix33::CreateFromVectors(forward % up, forward, up)); //m_viewQuat = m_baseQuat; m_viewRoll = 0; m_upVector = m_baseQuat.GetColumn2(); }
void CPlayerRotation::ProcessForcedLookDirection( const Quat& lastViewQuat, float frameTime ) { const float forceLookLenSqr(m_forceLookVector.len2()); if (forceLookLenSqr < 0.001f) return; const float forceLookLen(cry_sqrtf(forceLookLenSqr)); Vec3 forceLook(m_forceLookVector); forceLook *= (float)__fres(forceLookLen); forceLook = lastViewQuat.GetInverted() * forceLook; const float smoothSpeed(6.6f * forceLookLen); float blendAmount = min(1.0f,frameTime*smoothSpeed); if(!m_bForcedLookAtBlendingEnabled) { blendAmount = 1.0f; } m_deltaAngles.x += asinf(forceLook.z) * blendAmount; m_deltaAngles.z += cry_atan2f(-forceLook.x,forceLook.y) * blendAmount; PR_CHECKQNAN_VEC(m_deltaAngles); }
void CNetPlayerInput::DoSetState(const SSerializedPlayerInput& input ) { m_curInput = input; m_pPlayer->GetGameObject()->ChangedNetworkState( INPUT_ASPECT ); CMovementRequest moveRequest; moveRequest.SetStance( (EStance)m_curInput.stance ); if(IsDemoPlayback()) { Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection); Ang3 deltaAngles(asin(localVDir.z),0,cry_atan2f(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } //else { moveRequest.SetLookTarget( m_pPlayer->GetEntity()->GetWorldPos() + 10.0f * m_curInput.lookDirection ); moveRequest.SetAimTarget(moveRequest.GetLookTarget()); } float pseudoSpeed = 0.0f; if (m_curInput.deltaMovement.len2() > 0.0f) { pseudoSpeed = m_pPlayer->CalculatePseudoSpeed(m_curInput.sprint); } moveRequest.SetPseudoSpeed(pseudoSpeed); moveRequest.SetAllowStrafing(true); float lean=0.0f; if (m_curInput.leanl) lean-=1.0f; if (m_curInput.leanr) lean+=1.0f; moveRequest.SetLean(lean); m_pPlayer->GetMovementController()->RequestMovement(moveRequest); // debug.. if (g_pGameCVars->g_debugNetPlayerInput & 1) { IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin( string("net_player_input_") + m_pPlayer->GetEntity()->GetName(), true ); pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,1), 1.0f ); // pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,1), 1.0f ); Vec3 wp(m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2)); pPD->AddDirection( wp, 1.5f, m_curInput.deltaMovement, ColorF(1,0,0,1), 1.0f ); pPD->AddDirection( wp, 1.5f, m_curInput.lookDirection, ColorF(0,1,0,1), 1.0f ); } }
void CCoherentUISystem::UpdateHUD() { static Vec3 lastPosition = Vec3Constants<Vec3::value_type>::fVec3_Zero; static float lastRotation = 0; CCoherentViewListener* pHUDListener = NULL; pHUDListener = ( m_HudViewListener ? m_HudViewListener.get() : NULL ); if ( pHUDListener ) { CCamera& camera = gEnv->pSystem->GetViewCamera(); Vec3 viewDir = camera.GetViewdir(); float rotation = cry_atan2f( viewDir.y, viewDir.x ) * 180.0f / 3.14159f; // Adjust rotation so it is the same as in the game rotation = -rotation - 135.0f; Coherent::UI::View* pView = pHUDListener->GetView(); if ( pView && pHUDListener->IsReadyForBindings() ) { if ( rotation != lastRotation ) { pView->TriggerEvent( "SetAbsoluteCompassRotation", rotation ); // Adjust the rotation for the map, too... pView->TriggerEvent( "SetPlayerRotationOnMap", rotation - 45.0f ); lastRotation = rotation; } Vec3 cameraPosition = camera.GetPosition(); if ( ( cameraPosition - lastPosition ).GetLengthSquared() > VEC_EPSILON ) { pView->TriggerEvent( "SetPlayerPositionOnMap", cameraPosition.x, cameraPosition.y ); lastPosition = cameraPosition; } } } }
void CNetPlayerInput::DoSetState(const SSerializedPlayerInput& input ) { // PLAYERPREDICTION m_newInterpolation |= (input.position != m_curInput.position) || (input.deltaMovement != m_curInput.deltaMovement); m_curInput = input; CHANGED_NETWORK_STATE(m_pPlayer, IPlayerInput::INPUT_ASPECT ); // not having these set seems to stop a remote avatars rotation being reflected m_curInput.aiming = true; m_curInput.allowStrafing = true; m_curInput.usinglookik = true; // ~PLAYERPREDICTION IAIActor* pAIActor = CastToIAIActorSafe(m_pPlayer->GetEntity()->GetAI()); if (pAIActor) pAIActor->GetState().bodystate=input.bodystate; CMovementRequest moveRequest; moveRequest.SetStance( (EStance)m_curInput.stance ); if(IsDemoPlayback()) { Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection); Ang3 deltaAngles(asinf(localVDir.z),0,cry_atan2f(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } { if (m_curInput.usinglookik) moveRequest.SetLookTarget( m_pPlayer->GetEntity()->GetWorldPos() + 10.0f * m_curInput.lookDirection ); else moveRequest.ClearLookTarget(); if (m_curInput.aiming) moveRequest.SetAimTarget(moveRequest.GetLookTarget()); else moveRequest.ClearAimTarget(); } /* float pseudoSpeed = 0.0f; if (m_curInput.deltaMovement.len2() > 0.0f) { pseudoSpeed = m_pPlayer->CalculatePseudoSpeed(m_curInput.sprint); } */ // PLAYERPREDICTION moveRequest.SetPseudoSpeed(CalculatePseudoSpeed()); // ~PLAYERPREDICTION moveRequest.SetAllowStrafing(input.allowStrafing); float lean=0.0f; if (m_curInput.leanl) lean-=1.0f; if (m_curInput.leanr) lean+=1.0f; moveRequest.SetLean(lean); m_pPlayer->GetMovementController()->RequestMovement(moveRequest); IAnimationGraphState *pState=0; if (m_pPlayer->GetAnimatedCharacter()) pState=m_pPlayer->GetAnimatedCharacter()->GetAnimationGraphState(); // PLAYERPREDICTION if (pState) { pState->SetInput(m_pPlayer->m_inputAiming, m_curInput.aiming); pState->SetInput(m_pPlayer->m_inputUsingLookIK, m_curInput.usinglookik); } #if !defined(_RELEASE) // debug.. if (g_pGameCVars->g_debugNetPlayerInput & 1) { IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin( string("net_player_input_") + m_pPlayer->GetEntity()->GetName(), true ); pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,1), 1.0f ); // pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,1), 1.0f ); Vec3 wp(m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2)); pPD->AddDirection( wp, 1.5f, m_curInput.deltaMovement, ColorF(1,0,0,1), 1.0f ); pPD->AddDirection( wp, 1.5f, m_curInput.lookDirection, ColorF(0,1,0,1), 1.0f ); } #endif // ~PLAYERPREDICTION }
void CNetPlayerInput::UpdateMoveRequest() { CMovementRequest moveRequest; SMovementState moveState; m_pPlayer->GetMovementController()->GetMovementState(moveState); Quat worldRot = m_pPlayer->GetBaseQuat(); // m_pPlayer->GetEntity()->GetWorldRotation(); Vec3 deltaMovement = worldRot.GetInverted().GetNormalized() * m_curInput.deltaMovement; // absolutely ensure length is correct deltaMovement = deltaMovement.GetNormalizedSafe(ZERO) * m_curInput.deltaMovement.GetLength(); moveRequest.AddDeltaMovement( deltaMovement ); if( IsDemoPlayback() ) { Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection); Ang3 deltaAngles(asinf(localVDir.z),0,cry_atan2f(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } //else { //--- Vector slerp actually produces QNans if the vectors are exactly opposite, in that case snap to the target if (m_lookDir.Dot(m_curInput.lookDirection) < (float)-0.99f) { m_lookDir = m_curInput.lookDirection; } else { m_lookDir.SetSlerp(m_lookDir, m_curInput.lookDirection, g_pGameCVars->pl_netAimLerpFactor); } Vec3 distantTarget = moveState.eyePosition + 1000.0f * m_lookDir; Vec3 lookTarget = distantTarget; if (m_curInput.usinglookik) moveRequest.SetLookTarget( lookTarget ); else moveRequest.ClearLookTarget(); if (m_curInput.aiming) moveRequest.SetAimTarget( lookTarget ); else moveRequest.ClearAimTarget(); if (m_curInput.deltaMovement.GetLengthSquared() > sqr(0.02f)) // 0.2f is almost stopped moveRequest.SetBodyTarget( distantTarget ); else moveRequest.ClearBodyTarget(); } moveRequest.SetAllowStrafing(m_curInput.allowStrafing); if(m_pPlayer->IsPlayer()) moveRequest.SetPseudoSpeed(CalculatePseudoSpeed()); else moveRequest.SetPseudoSpeed(m_curInput.pseudoSpeed); float lean=0.0f; if (m_curInput.leanl) lean-=1.0f; if (m_curInput.leanr) lean+=1.0f; if (fabsf(lean)>0.01f) moveRequest.SetLean(lean); else moveRequest.ClearLean(); moveRequest.SetStance( (EStance)m_curInput.stance ); m_pPlayer->GetMovementController()->RequestMovement(moveRequest); if (m_curInput.sprint) m_pPlayer->m_actions |= ACTION_SPRINT; else m_pPlayer->m_actions &= ~ACTION_SPRINT; if (m_curInput.leanl) m_pPlayer->m_actions |= ACTION_LEANLEFT; else m_pPlayer->m_actions &= ~ACTION_LEANLEFT; if (m_curInput.leanr) m_pPlayer->m_actions |= ACTION_LEANRIGHT; else m_pPlayer->m_actions &= ~ACTION_LEANRIGHT; #if !defined(_RELEASE) // debug.. if (g_pGameCVars->g_debugNetPlayerInput & 2) { IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin( string("update_player_input_") + m_pPlayer->GetEntity()->GetName(), true ); Vec3 wp = m_pPlayer->GetEntity()->GetWorldPos(); wp.z += 2.0f; pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,0.3f), 1.0f ); // pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,0.3f), 1.0f ); pPD->AddDirection( m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2), 1, m_curInput.deltaMovement, ColorF(1,0,0,0.3f), 1.0f ); } #endif //m_curInput.deltaMovement.zero(); }
void CPlayerInput::PreUpdate() { CMovementRequest request; // get rotation into a manageable form float mouseSensitivity; if (m_pPlayer->InZeroG()) mouseSensitivity = 0.00333f*MAX(0.01f, g_pGameCVars->cl_sensitivityZeroG); else mouseSensitivity = 0.00333f*MAX(0.01f, g_pGameCVars->cl_sensitivity); mouseSensitivity *= gf_PI / 180.0f;//doesnt make much sense, but after all helps to keep reasonable values for the sensitivity cvars //these 2 could be moved to CPlayerRotation mouseSensitivity *= m_pPlayer->m_params.viewSensitivity; mouseSensitivity *= m_pPlayer->GetMassFactor(); COffHand * pOffHand=static_cast<COffHand*>(m_pPlayer->GetWeaponByClass(CItem::sOffHandClass)); if(pOffHand && (pOffHand->GetOffHandState()&eOHS_HOLDING_NPC)) mouseSensitivity *= pOffHand->GetObjectMassScale(); // When carrying object/enemy, adapt mouse sensitiviy to feel the weight // Designers requested we ignore single-handed objects (1 == m_iCarryingObject) if(2 == m_iCarryingObject) { mouseSensitivity /= 2.0f; } if(m_fCrouchPressedTime>0.0f) { float fNow = gEnv->pTimer->GetAsyncTime().GetMilliSeconds(); if((fNow - m_fCrouchPressedTime) > 300.0f) { if(m_actions & ACTION_CROUCH) { m_actions &= ~ACTION_CROUCH; m_actions |= ACTION_PRONE; } m_fCrouchPressedTime = -1.0f; } } Ang3 deltaRotation(m_deltaRotation * mouseSensitivity); if (m_pStats->isFrozen.Value() && m_pPlayer->IsPlayer() && m_pPlayer->GetHealth()>0) { float sMin = g_pGameCVars->cl_frozenSensMin; float sMax = g_pGameCVars->cl_frozenSensMax; float mult = sMin + (sMax-sMin)*(1.f-m_pPlayer->GetFrozenAmount(true)); deltaRotation *= mult; m_pPlayer->UpdateUnfreezeInput(m_deltaRotation, m_deltaMovement-m_deltaMovementPrev, mult); } // apply rotation from xinput controller if(!m_bDisabledXIRot) { // Controller framerate compensation needs frame time! // The constant is to counter for small frame time values. // adjust some too small values, should be handled differently later on Ang3 xiDeltaRot=m_xi_deltaRotation*gEnv->pTimer->GetFrameTime() * mouseSensitivity * 50.0f; SmoothControllerInput(xiDeltaRot); ControlCameraMode(); // Applying aspect modifiers if (g_pGameCVars->ctrl_aspectCorrection > 0) { int vx, vy, vw, vh; gEnv->pRenderer->GetViewport(&vx, &vy, &vw, &vh); float med=((float)vw+vh)/2.0f; float crW=((float)vw)/med; float crH=((float)vh)/med; xiDeltaRot.x*=g_pGameCVars->ctrl_aspectCorrection == 2 ? crW : crH; xiDeltaRot.z*=g_pGameCVars->ctrl_aspectCorrection == 2 ? crH : crW; } if(g_pGameCVars->cl_invertController) xiDeltaRot.x*=-1; deltaRotation+=xiDeltaRot; IVehicle *pVehicle = m_pPlayer->GetLinkedVehicle(); if (pVehicle) { if (m_pPlayer->m_pVehicleClient) { m_pPlayer->m_pVehicleClient->PreUpdate(pVehicle, m_pPlayer->GetEntityId(), gEnv->pTimer->GetFrameTime()); } //FIXME:not really good m_actions = 0; m_deltaMovement.Set(0,0,0); m_deltaRotation.Set(0,0,0); } } if(m_bUseXIInput) { m_deltaMovement.x = m_xi_deltaMovement.x; m_deltaMovement.y = m_xi_deltaMovement.y; m_deltaMovement.z = 0; if (m_xi_deltaMovement.len2()>0.0f) m_actions |= ACTION_MOVE; else m_actions &= ~ACTION_MOVE; } bool animControlled(m_pPlayer->m_stats.animationControlled); // If there was a recent serialization, ignore the delta rotation, since it's accumulated over several frames. if ((m_lastSerializeFrameID + 2) > gEnv->pRenderer->GetFrameID()) deltaRotation.Set(0,0,0); //if(m_pPlayer->m_stats.isOnLadder) //deltaRotation.z = 0.0f; const SCVars* pGameCVars = g_pGameCVars; if(pGameCVars->cl_cam_orbit != 0 && m_pPlayer->IsClient() && m_pPlayer->IsThirdPerson()) { static bool IsInit = false; if (!IsInit) { m_pPlayer->m_camViewMtxFinal = Matrix33(gEnv->pRenderer->GetCamera().GetViewMatrix()); IsInit = true; } float frameTime=gEnv->pTimer->GetFrameTime(); float frameTimeNormalised=(frameTime>1 ? 1 : frameTime<0.0001f ? 0.0001f : frameTime)*30; // 1/30th => 1 1/60th =>0.5 etc float frameTimeClamped=(frameTime>1 ? 1 : frameTime<0.0001f ? 0.0001f : frameTime); m_pCameraInputHelper->UpdateCameraInput(deltaRotation, frameTimeClamped,frameTimeNormalised); // also modifies deltaRotation. } if (!animControlled) request.AddDeltaRotation( deltaRotation ); // add some movement... if (!m_pStats->isFrozen.Value() && !animControlled) request.AddDeltaMovement( FilterMovement(m_deltaMovement) ); m_deltaMovementPrev = m_deltaMovement; // handle actions if (m_actions & ACTION_JUMP) { if (m_pPlayer->GetStance() != STANCE_PRONE) request.SetJump(); else m_actions &= ~ACTION_JUMP; //m_actions &= ~ACTION_PRONE; /*if (m_pPlayer->GetStance() != STANCE_PRONE) { if(m_pPlayer->GetStance() == STANCE_STAND || m_pPlayer->TrySetStance(STANCE_STAND)) request.SetJump(); } else if(!m_pPlayer->TrySetStance(STANCE_STAND)) m_actions &= ~ACTION_JUMP; else m_actions &= ~ACTION_PRONE;*/ } if (m_pPlayer->m_stats.isOnLadder) { m_actions &= ~ACTION_PRONE; m_actions &= ~ACTION_CROUCH; } request.SetStance(FigureOutStance()); float pseudoSpeed = 0.0f; if (m_deltaMovement.len2() > 0.0f) { pseudoSpeed = m_pPlayer->CalculatePseudoSpeed(m_pPlayer->m_stats.bSprinting); } /* design changed: sprinting with controller is removed from full stick up to Left Bumper if(m_bUseXIInput && m_xi_deltaMovement.len2() > 0.999f) { m_actions |= ACTION_SPRINT; } else if(m_bUseXIInput) { m_actions &= ~ACTION_SPRINT; }*/ request.SetPseudoSpeed(pseudoSpeed); if (m_deltaMovement.GetLength() > 0.1f) { float moveAngle = (float)RAD2DEG(fabs_tpl(cry_atan2f(-m_deltaMovement.x, fabsf(m_deltaMovement.y)<0.01f?0.01f:m_deltaMovement.y))); request.SetAllowStrafing(moveAngle > 20.0f); } else { request.SetAllowStrafing(true); } // send the movement request to the appropriate spot! m_pPlayer->m_pMovementController->RequestMovement( request ); m_pPlayer->m_actions = m_actions; // reset things for next frame that need to be m_lastMouseRawInput = m_deltaRotation; m_deltaRotation = Ang3(0,0,0); //static float color[] = {1,1,1,1}; //gEnv->pRenderer->Draw2dLabel(100,50,1.5,color,false,"deltaMovement:%f,%f", m_deltaMovement.x,m_deltaMovement.y); // PLAYERPREDICTION m_pPlayer->GetGameObject()->ChangedNetworkState(INPUT_ASPECT); // ~PLAYERPREDICTION }
void CPlayerRotation::ClampAngles() { { //cap up/down looking float minAngle,maxAngle; GetStanceAngleLimits(minAngle,maxAngle); float currentViewPitch=GetLocalPitch(); float newPitch = currentViewPitch + m_deltaAngles.x; if(newPitch < minAngle) newPitch = minAngle; else if(newPitch > maxAngle) newPitch = maxAngle; m_deltaAngles.x = newPitch - currentViewPitch; } { //further limit the view if necessary float limitV = m_params.vLimitRangeV; float limitH = m_params.vLimitRangeH; Vec3 limitDir = m_params.vLimitDir; float limitVUp = m_params.vLimitRangeVUp; float limitVDown = m_params.vLimitRangeVDown; if(m_player.m_stats.isFrozen.Value()) { float clampMin = g_pGameCVars->cl_frozenAngleMin; float clampMax = g_pGameCVars->cl_frozenAngleMax; float frozenLimit = DEG2RAD(clampMin + (clampMax-clampMin)*(1.f-m_player.GetFrozenAmount(true))); if(limitV == 0 || limitV>frozenLimit) limitV = frozenLimit; if(limitH == 0 || limitH>frozenLimit) limitH = frozenLimit; if(g_pGameCVars->cl_debugFreezeShake) { static float color[] = {1,1,1,1}; gEnv->pRenderer->Draw2dLabel(100,200,1.5,color,false,"limit: %f", RAD2DEG(frozenLimit)); } } if(m_player.m_stats.isOnLadder) { limitDir = -m_player.m_stats.ladderOrientation; limitH = DEG2RAD(40.0f); } if((limitH+limitV+limitVUp+limitVDown) && limitDir.len2()>0.1f) { //A matrix is built around the view limit, and then the player view angles are checked with it. //Later, if necessary the upVector could be made customizable. Vec3 forward(limitDir); Vec3 up(m_baseQuat.GetColumn2()); Vec3 right(-(up % forward)); right.Normalize(); Matrix33 limitMtx; limitMtx.SetFromVectors(right,forward,right%forward); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(m_player.GetEntity()->GetWorldPos(), ColorB(0,0,255,255), m_player.GetEntity()->GetWorldPos() + limitMtx.GetColumn(0), ColorB(0,0,255,255)); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(m_player.GetEntity()->GetWorldPos(), ColorB(0,255,0,255), m_player.GetEntity()->GetWorldPos() + limitMtx.GetColumn(1), ColorB(0,255,0,255)); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(m_player.GetEntity()->GetWorldPos(), ColorB(255,0,0,255), m_player.GetEntity()->GetWorldPos() + limitMtx.GetColumn(2), ColorB(255,0,0,255)); limitMtx.Invert(); Vec3 localDir(limitMtx * m_viewQuat.GetColumn1()); // Vec3 localDir(limitMtx * m_player.GetEntity()->GetWorldRotation().GetColumn1()); Ang3 limit; if(limitV) { limit.x = asinf(localDir.z) + m_deltaAngles.x; float deltaX(limitV - fabs(limit.x)); if(deltaX < 0.0f) m_deltaAngles.x += deltaX*(limit.x>0.0f?1.0f:-1.0f); } if(limitVUp || limitVDown) { limit.x = asinf(localDir.z) + m_deltaAngles.x; if(limit.x>=limitVUp && limitVUp!=0) { float deltaXUp(limitVUp - limit.x); m_deltaAngles.x += deltaXUp; } if(limit.x<=limitVDown && limitVDown!=0) { float deltaXDown(limitVDown - limit.x); m_deltaAngles.x += deltaXDown; } } if(limitH) { limit.z = cry_atan2f(-localDir.x,localDir.y) + m_deltaAngles.z; float deltaZ(limitH - fabs(limit.z)); if(deltaZ < 0.0f) m_deltaAngles.z += deltaZ*(limit.z>0.0f?1.0f:-1.0f); } } } }
void CPlayerRotation::ProcessFlyingZeroG() { bool bEnableGyroVerticalFade = (g_pGameCVars->pl_zeroGEnableGyroFade > 0); bool bEnableGyroSpeedFade = (g_pGameCVars->pl_zeroGEnableGyroFade < 2); //thats necessary when passing from groundG to normalG m_baseQuat = m_viewQuat; assert(m_baseQuat.IsValid()); //m_baseQuat = Quat::CreateSlerp(m_viewQuat,m_player.GetEntity()->GetRotation() * Quat::CreateRotationZ(gf_PI),0.5f); Ang3 desiredAngVel(m_deltaAngles.x,m_deltaAngles.y * 0.3f,m_deltaAngles.z); //view recoil in zeroG cause the player to rotate desiredAngVel.x += m_viewAnglesOffset.x * 0.1f; desiredAngVel.z += m_viewAnglesOffset.z * 0.1f; //so once used reset it. m_viewAnglesOffset.Set(0,0,0); //gyroscope: the gyroscope just apply the right roll speed to compensate the rotation, that way effects like //propulsion particles and such can be done easily just by using the angularVel float rotInertia(g_pGameCVars->pl_zeroGAimResponsiveness); if(m_player.GravityBootsOn() && m_stats.gBootsSpotNormal.len2()>0.01f) { Vec3 vRef(m_baseQuat.GetInverted() * m_stats.gBootsSpotNormal); Ang3 alignAngle(0,0,0); alignAngle.y = cry_atan2f(vRef.x, vRef.z); alignAngle.x = cry_atan2f(vRef.y, vRef.z); desiredAngVel.y += alignAngle.y * 0.05f; desiredAngVel.x -= alignAngle.x * 0.05f; } if(m_actions & ACTION_GYROSCOPE && desiredAngVel.y==0) { // we want to fade out the gyroscopic effect Vec3 vRef(m_baseQuat.GetInverted() * m_stats.zeroGUp); Ang3 alignAngle(0,0,0); alignAngle.y = cry_atan2f(vRef.x,vRef.z); float gyroFade = 1.0f; if(bEnableGyroVerticalFade) { float gyroFadeAngleInner = g_pGameCVars->pl_zeroGGyroFadeAngleInner; float gyroFadeAngleOuter = g_pGameCVars->pl_zeroGGyroFadeAngleOuter; float gyroFadeAngleSpan = gyroFadeAngleOuter - gyroFadeAngleInner; float gyroFadeAngleSpanInv = 1.0f / gyroFadeAngleSpan; float viewVerticalAlignment = abs(m_viewQuat.GetFwdZ()); float viewVerticalAngle = RAD2DEG(cry_asinf(viewVerticalAlignment)); gyroFade = 1.0f - CLAMP((viewVerticalAngle - gyroFadeAngleInner) * gyroFadeAngleSpanInv, 0.0f, 1.0f); gyroFade = cry_powf(gyroFade, g_pGameCVars->pl_zeroGGyroFadeExp); } float speedFade = 1.0f; if(bEnableGyroSpeedFade) { float speed = m_player.GetLastRequestedVelocity().GetLength(); speedFade = 1.0f - std::min(1.0f, speed / 5.0f); } desiredAngVel.y += alignAngle.y * speedFade * gyroFade * m_frameTime * g_pGameCVars->pl_zeroGGyroStrength; //rotInertia = 3.0f; } m_absRoll = fabs(desiredAngVel.y); Interpolate(m_angularVel,desiredAngVel,rotInertia,m_frameTime); Ang3 finalAngle(m_angularVel + m_angularImpulseDelta); m_baseQuat *= Quat::CreateRotationZ(finalAngle.z) * Quat::CreateRotationX(finalAngle.x) * Quat::CreateRotationY(finalAngle.y); m_baseQuat.NormalizeSafe(); /*IEntity *pEnt = m_player.GetEntity(); Vec3 offsetToCenter(Vec3(0,0,m_player.GetStanceInfo(m_player.GetStance())->heightCollider)); Vec3 finalPos(pEnt->GetWorldTM() * offsetToCenter); Quat newBaseQuat(m_baseQuat * Quat::CreateRotationZ(finalAngle.z) * Quat::CreateRotationX(finalAngle.x) * Quat::CreateRotationY(finalAngle.y)); Vec3 newPos(pEnt->GetWorldPos() + m_baseQuat * offsetToCenter); pEnt->SetPos(pEnt->GetWorldPos() + (finalPos - newPos),ENTITY_XFORM_USER);*/ //CHECKQNAN_MAT33(m_baseMtx); m_viewQuat = m_baseQuat; m_viewRoll = 0; m_upVector = m_baseQuat.GetColumn2(); }
void CNetPlayerInput::PreUpdate() { IPhysicalEntity * pPhysEnt = m_pPlayer->GetEntity()->GetPhysics(); if (!pPhysEnt) return; CMovementRequest moveRequest; SMovementState moveState; m_pPlayer->GetMovementController()->GetMovementState(moveState); Quat worldRot = m_pPlayer->GetBaseQuat(); // m_pPlayer->GetEntity()->GetWorldRotation(); Vec3 deltaMovement = worldRot.GetInverted().GetNormalized() * m_curInput.deltaMovement; // absolutely ensure length is correct deltaMovement = deltaMovement.GetNormalizedSafe(ZERO) * m_curInput.deltaMovement.GetLength(); moveRequest.AddDeltaMovement( deltaMovement ); if( IsDemoPlayback() ) { Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection); Ang3 deltaAngles(asin(localVDir.z),0,cry_atan2f(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } //else { Vec3 distantTarget = moveState.eyePosition + 1000.0f * m_curInput.lookDirection; Vec3 lookTarget = distantTarget; if (gEnv->bClient && m_pPlayer->GetGameObject()->IsProbablyVisible()) { // post-process aim direction ray_hit hit; static const int obj_types = ent_all; // ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_living; static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; bool rayHitAny = 0 != gEnv->pPhysicalWorld->RayWorldIntersection( moveState.eyePosition, 150.0f * m_curInput.lookDirection, obj_types, flags, &hit, 1, pPhysEnt ); if (rayHitAny) { lookTarget = hit.pt; } static float proneDist = 1.0f; static float crouchDist = 0.6f; static float standDist = 0.3f; float dist = standDist; if(m_pPlayer->GetStance() == STANCE_CROUCH) dist = crouchDist; else if(m_pPlayer->GetStance() == STANCE_PRONE) dist = proneDist; if((lookTarget - moveState.eyePosition).GetLength2D() < dist) { Vec3 eyeToTarget2d = lookTarget - moveState.eyePosition; eyeToTarget2d.z = 0.0f; eyeToTarget2d.NormalizeSafe(); eyeToTarget2d *= dist; ray_hit newhit; bool rayHitAny = 0 != gEnv->pPhysicalWorld->RayWorldIntersection( moveState.eyePosition + eyeToTarget2d, 3 * Vec3(0,0,-1), obj_types, flags, &newhit, 1, pPhysEnt ); if (rayHitAny) { lookTarget = newhit.pt; } } // SNH: new approach. Make sure the aimTarget is at least 1.5m away, // if not, pick a point 1m down the vector instead. Vec3 dir = lookTarget - moveState.eyePosition; static float minDist = 1.5f; if(dir.GetLengthSquared() < minDist) { lookTarget = moveState.eyePosition + dir.GetNormalizedSafe(); } // draw eye pos for comparison //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(moveState.eyePosition, 0.04f, ColorF(0.3f,0.2f,0.7f,1.0f)); } moveRequest.SetLookTarget( lookTarget ); moveRequest.SetAimTarget( lookTarget ); if (m_curInput.deltaMovement.GetLengthSquared() > sqr(0.2f)) // 0.2f is almost stopped moveRequest.SetBodyTarget( distantTarget ); else moveRequest.ClearBodyTarget(); } moveRequest.SetAllowStrafing(true); float pseudoSpeed = 0.0f; if (m_curInput.deltaMovement.len2() > 0.0f) { pseudoSpeed = m_pPlayer->CalculatePseudoSpeed(m_curInput.sprint); } moveRequest.SetPseudoSpeed(pseudoSpeed); float lean=0.0f; if (m_curInput.leanl) lean-=1.0f; if (m_curInput.leanr) lean+=1.0f; if (fabsf(lean)>0.01f) moveRequest.SetLean(lean); else moveRequest.ClearLean(); m_pPlayer->GetMovementController()->RequestMovement(moveRequest); if (m_curInput.sprint) m_pPlayer->m_actions |= ACTION_SPRINT; else m_pPlayer->m_actions &= ~ACTION_SPRINT; if (m_curInput.leanl) m_pPlayer->m_actions |= ACTION_LEANLEFT; else m_pPlayer->m_actions &= ~ACTION_LEANLEFT; if (m_curInput.leanr) m_pPlayer->m_actions |= ACTION_LEANRIGHT; else m_pPlayer->m_actions &= ~ACTION_LEANRIGHT; // debug.. if (g_pGameCVars->g_debugNetPlayerInput & 2) { IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin( string("update_player_input_") + m_pPlayer->GetEntity()->GetName(), true ); Vec3 wp = m_pPlayer->GetEntity()->GetWorldPos(); wp.z += 2.0f; pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,0.3f), 1.0f ); // pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,0.3f), 1.0f ); pPD->AddDirection( m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2), 1, m_curInput.deltaMovement, ColorF(1,0,0,0.3f), 1.0f ); } //m_curInput.deltaMovement.zero(); }
void CPlayerRotation::ClampAngles( float minAngle, float maxAngle ) { //Cap up/down looking { const float currentViewPitch = GetLocalPitch(); const float newPitch = clamp(currentViewPitch + m_deltaAngles.x, minAngle, maxAngle); m_deltaAngles.x = newPitch - currentViewPitch; } //Further limit the view if necessary { const SViewLimitParams& viewLimits = m_player.m_params.viewLimits; const Vec3 limitDir = viewLimits.GetViewLimitDir(); if (limitDir.len2() < 0.1f) return; const float limitV = viewLimits.GetViewLimitRangeV(); const float limitH = viewLimits.GetViewLimitRangeH(); const float limitVUp = viewLimits.GetViewLimitRangeVUp(); const float limitVDown = viewLimits.GetViewLimitRangeVDown(); if ((limitH+limitV+fabsf(limitVUp)+fabsf(limitVDown)) > 0.0f) { //A matrix is built around the view limit, and then the player view angles are checked with it. //Later, if necessary the upVector could be made customizable. const Vec3 forward(limitDir); const Vec3 up(m_baseQuat.GetColumn2()); const Vec3 right((-(up % forward)).GetNormalized()); Matrix33 limitMtx; limitMtx.SetFromVectors(right,forward,right%forward); limitMtx.Invert(); const Vec3 localDir(limitMtx * m_viewQuat.GetColumn1()); Ang3 limit; if (limitV) { limit.x = asinf(localDir.z) + m_deltaAngles.x; const float deltaX(limitV - fabs(limit.x)); m_deltaAngles.x = m_deltaAngles.x + (float)__fsel(deltaX, 0.0f, deltaX * (float)__fsel(limit.x, 1.0f, -1.0f)); } if (limitVUp || limitVDown) { limit.x = asinf(localDir.z) + m_deltaAngles.x; const float deltaXUp(limitVUp - limit.x); float fNewDeltaX = m_deltaAngles.x; const float fDeltaXUpIncrement = (float)__fsel( deltaXUp, 0.0f, deltaXUp); fNewDeltaX = fNewDeltaX + (float)__fsel(-fabsf(limitVUp), 0.0f, fDeltaXUpIncrement); const float deltaXDown(limitVDown - limit.x); const float fDeltaXDownIncrement = (float)__fsel( deltaXDown, deltaXDown, 0.0f); fNewDeltaX = fNewDeltaX + (float)__fsel(-fabsf(limitVDown), 0.0f, fDeltaXDownIncrement); m_deltaAngles.x = fNewDeltaX; } if (limitH) { limit.z = cry_atan2f(-localDir.x,localDir.y) + m_deltaAngles.z; const float deltaZ(limitH - fabs(limit.z)); m_deltaAngles.z = m_deltaAngles.z + (float)__fsel(deltaZ, 0.0f, deltaZ * (float)__fsel(limit.z, 1.0f, -1.0f)); } } } }