//------------------------------------------------------------------------ void CNetworkMovementHelicopterCrysis2::Read(CVehicleMovementHelicopter* pMovement) { if(!gEnv->bServer) { if (m_netSyncFlags & k_syncLookMoveSpeed) { CMovementRequest newRequest; if(!m_lookTarget.IsZero()) { newRequest.SetLookTarget(m_lookTarget); } if(!m_moveTarget.IsZero()) { newRequest.SetMoveTarget(m_moveTarget); newRequest.SetBodyTarget(m_moveTarget); } if(m_desiredSpeed != 0.f) { newRequest.SetDesiredSpeed(m_desiredSpeed); } pMovement->RequestMovement(newRequest); } if ((m_netSyncFlags&(k_controlPos|k_syncPos))==(k_controlPos|k_syncPos)) { // Let the helicoptor fix the network error if (!m_currentPos.IsZero(0.5f)) pMovement->UpdateNetworkError(m_currentPos, m_currentRot); } } }
void CTerraPlayerInput::PreUpdate() { CMovementRequest request; //Make a movement request if(!m_DeltaMovement.IsZero()) { request.AddDeltaMovement(m_DeltaMovement.normalized()); m_pPlayer->GetMovementController()->RequestMovement(request); } }
//------------------------------------------------------------------------ bool CVehicleMovementTank::RequestMovement(CMovementRequest& movementRequest) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_movementAction.isAI = true; if (!m_isEnginePowered) return false; CryAutoCriticalSection lk(m_lock); if (movementRequest.HasLookTarget()) m_aiRequest.SetLookTarget(movementRequest.GetLookTarget()); else m_aiRequest.ClearLookTarget(); if (movementRequest.HasMoveTarget()) { Vec3 entityPos = m_pEntity->GetWorldPos(); Vec3 start(entityPos); Vec3 end( movementRequest.GetMoveTarget() ); Vec3 pos = ( end - start ) * 100.0f; pos +=start; m_aiRequest.SetMoveTarget( pos ); } else m_aiRequest.ClearMoveTarget(); float fDesiredSpeed = 0.f; if (movementRequest.HasDesiredSpeed()) m_aiRequest.SetDesiredSpeed(fDesiredSpeed = movementRequest.GetDesiredSpeed()); else m_aiRequest.ClearDesiredSpeed(); if (movementRequest.HasForcedNavigation()) { Vec3 entityPos = m_pEntity->GetWorldPos(); m_aiRequest.SetForcedNavigation(movementRequest.GetForcedNavigation()); m_aiRequest.SetDesiredSpeed(movementRequest.GetForcedNavigation().GetLength()); m_aiRequest.SetMoveTarget(entityPos+movementRequest.GetForcedNavigation().GetNormalizedSafe()*100.0f); } else m_aiRequest.ClearForcedNavigation(); if (fabs(fDesiredSpeed) > FLT_EPSILON) { m_pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics, true); } return true; }
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 ); } }
bool CFlyerMovementController::RequestMovement(CMovementRequest& movementRequest) { CFlyer::SMovementRequestParams movementRequestParams(movementRequest); if (movementRequest.HasForcedNavigation()) { movementRequestParams.vMoveDir = movementRequest.GetForcedNavigation(); movementRequestParams.fDesiredSpeed = movementRequestParams.vMoveDir.GetLength(); movementRequestParams.vMoveDir.NormalizeSafe(); } m_pFlyer->SetActorMovement(movementRequestParams); return true; }
void Mouse::OnHardwareMouseEvent( int iX,int iY,EHARDWAREMOUSEEVENT eHardwareMouseEvent, int wheelDelta ) { m_x = iX; m_y = iY; if(eHardwareMouseEvent == HARDWAREMOUSEEVENT_LBUTTONDOWN) { CryLogAlways("LEFT BUTTON PRESSED"); CryLogAlways("requesting movement..."); CPlayer* pPlayer = CPlayer::GetHero(); Vec3 pos; getWorldCoords(pos.x, pos.y, pos.z); m_clickFeedback.Start(pos); CMovementRequest request; request.SetMoveTarget(pos); pPlayer->GetMovementController()->RequestMovement(request); setCursor(); } if (eHardwareMouseEvent == HARDWAREMOUSEEVENT_LBUTTONUP) { } if(eHardwareMouseEvent == HARDWAREMOUSEEVENT_RBUTTONDOWN) { CryLogAlways("RIGHT BUTTON PRESSED"); getEntityUnderCursor(); } if(eHardwareMouseEvent == HARDWAREMOUSEEVENT_RBUTTONUP) { CryLogAlways("RIGHT BUTTON RELEASED"); } if (eHardwareMouseEvent == HARDWAREMOUSEEVENT_WHEEL) { CryLogAlways("WHEEL MOVED"); m_wheelDelta -= static_cast<float>(wheelDelta) * gEnv->pTimer->GetFrameTime(); if (m_wheelDelta > 0) m_wheelDelta = 0; else if (m_wheelDelta < -10) m_wheelDelta = -10; getEntityUnderCursor(); } }
//------------------------------------------------------------------------ bool CVehicleMovementHelicopter::RequestMovement(CMovementRequest &movementRequest) { FUNCTION_PROFILER(gEnv->pSystem, PROFILE_GAME); m_movementAction.isAI = true; if(!m_isEnginePowered) return false; CryAutoCriticalSection lk(m_lock); if(movementRequest.HasLookTarget()) m_aiRequest.SetLookTarget(movementRequest.GetLookTarget()); else m_aiRequest.ClearLookTarget(); if(movementRequest.HasMoveTarget()) { Vec3 entityPos = m_pEntity->GetWorldPos(); Vec3 start(entityPos); Vec3 end(movementRequest.GetMoveTarget()); Vec3 pos = (end - start) * 100.0f; pos +=start; m_aiRequest.SetMoveTarget(pos); } else m_aiRequest.ClearMoveTarget(); if(movementRequest.HasDesiredSpeed()) m_aiRequest.SetDesiredSpeed(movementRequest.GetDesiredSpeed()); else m_aiRequest.ClearDesiredSpeed(); if(movementRequest.HasForcedNavigation()) { Vec3 entityPos = m_pEntity->GetWorldPos(); m_aiRequest.SetForcedNavigation(movementRequest.GetForcedNavigation()); m_aiRequest.SetDesiredSpeed(movementRequest.GetForcedNavigation().GetLength()); m_aiRequest.SetMoveTarget(entityPos+movementRequest.GetForcedNavigation().GetNormalizedSafe()*100.0f); } else m_aiRequest.ClearForcedNavigation(); return true; }
void CNetPlayerInput::DoSetState(const SSerializedPlayerInput& input ) { m_newInterpolation |= (input.position != m_curInput.position) || (input.deltaMovement != m_curInput.deltaMovement); const bool wasSprinting = m_curInput.sprint; m_curInput = input; CHANGED_NETWORK_STATE(m_pPlayer, CPlayer::ASPECT_INPUT_CLIENT ); if(wasSprinting != input.sprint) { SInputEventData inputEventData( SInputEventData::EInputEvent_Sprint, m_pPlayer->GetEntityId(), CCryName("sprint"), input.sprint ? eAAM_OnPress : eAAM_OnRelease, 0.f ); m_pPlayer->StateMachineHandleEventMovement( SStateEventPlayerInput( &inputEventData ) ); } // 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; 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,atan2_tpl(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } moveRequest.SetPseudoSpeed(CalculatePseudoSpeed()); moveRequest.SetAllowStrafing(input.allowStrafing); m_pPlayer->GetMovementController()->RequestMovement(moveRequest); #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 }
bool CTerraMovementController::RequestMovement(CMovementRequest& request) { if(request.HasDeltaRotation()) m_moveRequest.AddDeltaRotation(request.GetDeltaRotation()); if(request.HasDeltaMovement()) m_moveRequest.AddDeltaMovement(request.GetDeltaMovement()); if(request.HasPseudoSpeed()) m_moveRequest.SetPseudoSpeed(request.GetPseudoSpeed()); return true; }
void CVehicleMovementMPVTOL::SPathing::UpdatePathFollowing( const EntityId vtolId, const float dt, CVehicleMovementMPVTOL& rMovement, const SVehiclePhysicsStatus& physStatus, const Vec3& posNoise ) { //CryWatch("VTOL: id[%d] path[%p] loc[%f] error[%f] wait[%f]", vtolId, pCachedPathPtr, pathingData.location, networkError, waitTime ); if(!pCachedPathPtr) return; networkError *= max(0.f, 1.f-(dt*2.0f)); float networkAdj = networkError; if(waitTime > 0.f) { waitTime -= dt; if(waitTime < 0.f) { waitTime = 0.f; targetSpeed = defaultSpeed; } else { networkAdj = 0.f; targetSpeed = 0.0f; } } CWaypointPath::TNodeId currentInerpolatedNode = interpolatedNode; Vec3 targetPos; if(pCachedPathPtr->GetPosAfterDistance(currentNode, physStatus.centerOfMass, g_pGameCVars->g_VTOLPathingLookAheadDistance, targetPos, interpolatedNode, currentNode, pathingData.location, shouldLoop)) { QuatT location; CWaypointPath::TNodeId locationNode = -1; pCachedPathPtr->GetPathLoc(pathingData.location, location, locationNode); const Vec3 forward(targetPos-location.t); const Vec3 side(forward.y, -forward.x, 0.f); Vec3 noise(side.GetNormalizedSafe(physStatus.q.GetColumn0())*posNoise.x); noise.z = posNoise.z; targetPos += noise; if(waitTime<=0.f && currentInerpolatedNode!=interpolatedNode) { float fValueOut = 0.f; CWaypointPath::E_NodeDataType dataTypeOut; if(pCachedPathPtr->HasDataAtNode(interpolatedNode, dataTypeOut, fValueOut)) { if(dataTypeOut == CWaypointPath::ENDT_Speed) { targetSpeed = fValueOut; } else if(dataTypeOut == CWaypointPath::ENDT_Wait && fValueOut > 0.f) { targetSpeed = speed = 0.f; waitTime = fValueOut; } } else { targetSpeed = defaultSpeed; } } SmoothCD(speed, accel, dt, targetSpeed, 0.2f); const float finalSpeed = max(0.f, speed + clamp( networkAdj, -speed, g_pGameCVars->v_MPVTOLNetworkCatchupSpeedLimit )); const float scalar = clamp( (speed>0.1f) ? finalSpeed/speed : 1.f, 1.f, 3.f ); CMovementRequest movementRequest; movementRequest.SetDesiredSpeed(finalSpeed); movementRequest.SetMoveTarget(targetPos); movementRequest.SetBodyTarget(targetPos); movementRequest.SetLookTarget(targetPos); rMovement.RequestMovement(movementRequest); rMovement.SetYawResponseScalar(scalar); } else { pathComplete |= 0x1; } }
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 }
//------------------------------------------------------------------------ bool CVehicleMovementHelicopter::RequestMovement(CMovementRequest& movementRequest) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_movementAction.isAI = true; //StartEngine(0); if (m_HoverAnim && !(m_HoverAnim->GetAnimTime() < 1.0f - FLT_EPSILON)) { m_HoverAnim->StartAnimation(); } CryAutoCriticalSection lk(m_lock); if (movementRequest.HasLookTarget()) m_aiRequest.SetLookTarget(movementRequest.GetLookTarget()); else m_aiRequest.ClearLookTarget(); if (movementRequest.HasBodyTarget()) m_aiRequest.SetBodyTarget(movementRequest.GetBodyTarget()); else m_aiRequest.ClearBodyTarget(); if (movementRequest.HasDesiredBodyDirectionAtTarget()) m_aiRequest.SetDesiredBodyDirectionAtTarget(movementRequest.GetDesiredBodyDirectionAtTarget()); else m_aiRequest.ClearDesiredBodyDirectionAtTarget(); if (movementRequest.HasMoveTarget()) { Vec3 end( movementRequest.GetMoveTarget() ); if(m_bExtendMoveTarget) { Vec3 entityPos = m_pEntity->GetWorldPos(); Vec3 start(entityPos); Vec3 pos = ( end - start ) * 100.0f; pos +=start; m_aiRequest.SetMoveTarget( pos ); } else { m_aiRequest.SetMoveTarget( end ); } if (!m_isEnginePowered) { StartDriving(0); } } else m_aiRequest.ClearMoveTarget(); float fDesiredSpeed = 0.0f; if (movementRequest.HasDesiredSpeed()) fDesiredSpeed = movementRequest.GetDesiredSpeed(); else m_aiRequest.ClearDesiredSpeed(); if (movementRequest.HasForcedNavigation()) { const Vec3 forcedNavigation = movementRequest.GetForcedNavigation(); const Vec3 entityPos = m_pEntity->GetWorldPos(); m_aiRequest.SetForcedNavigation(forcedNavigation); m_aiRequest.SetMoveTarget(entityPos+forcedNavigation.GetNormalizedSafe()*100.0f); if (fabsf(fDesiredSpeed) <= FLT_EPSILON) fDesiredSpeed = forcedNavigation.GetLength(); } else m_aiRequest.ClearForcedNavigation(); m_aiRequest.SetDesiredSpeed(fDesiredSpeed * m_EnginePerformance); m_pVehicle->NeedsUpdate(IVehicle::eVUF_AwakePhysics, false); return true; }
STransitionSelectionParams::STransitionSelectionParams( const CMovementTransitions& transitions, const CPlayer& player, const CMovementRequest& request, const Vec3& playerPos, const SMovementTransitionsSample& oldSample, const SMovementTransitionsSample& newSample, const bool bHasLockedBodyTarget, const Vec3& targetBodyDirection, const Lineseg& safeLine, const CTimeValue runningDuration, const uint8 _allowedTransitionFlags, const float entitySpeed2D, const float entitySpeed2DAvg, const SExactPositioningTarget*const pExactPositioningTarget, const EStance stance, SActorFrameMovementParams*const pMoveParams) : m_transitionType(eTT_None), m_transitionDistance(0.0f), m_pseudoSpeed(0.0f), m_travelAngle(0.0f), m_jukeAngle(0.0f), m_stance(stance) { // TODO: check for flatness? m_travelAngle = Ang3::CreateRadZ( newSample.bodyDirection, oldSample.moveDirection ); // probably should be oldSample? m_context = request.HasContext() ? request.GetContext() : 0; // -------------------------------------------------------------------------- // Calculate vToMoveTarget, vAfterMoveTarget, distToMoveTarget, distAfterMoveTarget & allowedTransitionFlags Vec3 vToMoveTarget, vAfterMoveTarget; float distToMoveTarget, distAfterMoveTarget; uint8 allowedTransitionFlags = _allowedTransitionFlags; { if (request.HasMoveTarget()) { const Vec3& vMoveTarget = request.GetMoveTarget(); vToMoveTarget = vMoveTarget - playerPos; distToMoveTarget = vToMoveTarget.GetLength2D(); m_future.hasMoveTarget = true; m_future.vMoveTarget = vMoveTarget; // Disallow certain transitions when preparing an exact positioning target // and fudge the distance to make sure we don't start when too close to it if (pExactPositioningTarget && pExactPositioningTarget->preparing && !pExactPositioningTarget->activated) { allowedTransitionFlags &= ~BIT(eTT_Stop); allowedTransitionFlags &= ~BIT(eTT_DirectionChange); const Vec3& exactPosLocation = pExactPositioningTarget->location.t; const float distFromMoveTargetToExactPosSquared = vMoveTarget.GetSquaredDistance(exactPosLocation); const float minimumDangerDistance = 0.1f; const float maxDistanceTraveledPerFrame = gEnv->pTimer->GetFrameTime() * 12.5f; const float dangerDistance = max(minimumDangerDistance, maxDistanceTraveledPerFrame); const bool moveTargetIsWithinDangerDistance = (distFromMoveTargetToExactPosSquared <= sqr(dangerDistance)); if (moveTargetIsWithinDangerDistance) { // Fudge distToMoveTarget so we start at least distanceTraveledInTwoFrames // This only works for eTT_Start transitions (but we disabled the others above) distToMoveTarget = max(0.0f, distToMoveTarget - dangerDistance); } } if (request.HasInflectionPoint()) { const Vec3& vInflectionPoint = request.GetInflectionPoint(); vAfterMoveTarget = vInflectionPoint - vMoveTarget; distAfterMoveTarget = vAfterMoveTarget.GetLength2D(); } else { vAfterMoveTarget.zero(); distAfterMoveTarget = 0.0f; } } else { m_future.hasMoveTarget = false; vToMoveTarget.zero(); vAfterMoveTarget.zero(); distToMoveTarget = distAfterMoveTarget = 0.0f; } } // -------------------------------------------------------------------------- const float maximumSpeedForStart = 0.5f; const float minimumSpeedForWalkStop = 1.0f; const float minimumSpeedForRunStop = 3.5f; const float minimumRunningDurationForRunStop = 1.0f; // (seconds) const float minimumSpeedForJuke = 4.4f*0.6f; // 4.4 is slowest runspeed in Crysis2; 0.6 is the strafing slowdown const float minimumRunningDurationForJuke = 0.1f; // (seconds) if (newSample.pseudoSpeed > 0.0f) { // Either: // - we are in a Stop and want to start again <-- note oldPseudoSpeed cannot be used to detect this, it could be already 0 from prev. frame // - we are in a Start and want to continue starting [but possibly stop or change direction at the movetarget] // - we are stopped and want to Start [but possibly stop or change direction at the movetarget] // - we are moving and want to continue moving [but possibly stop or change direction at the movetarget] m_pseudoSpeed = newSample.pseudoSpeed; if ( (allowedTransitionFlags & (1<<eTT_Start)) && (entitySpeed2DAvg <= maximumSpeedForStart) ) { //New sample's movement direction is accurate for start transitions. m_travelAngle = Ang3::CreateRadZ( newSample.bodyDirection, newSample.moveDirection ); m_transitionType = eTT_Start; m_bPredicted = true; m_transitionDistance = distToMoveTarget; m_future.vMoveDirection = newSample.moveDirection; const Vec3 realTargetBodyDirection = bHasLockedBodyTarget ? targetBodyDirection : m_future.vMoveDirection; m_targetTravelAngle = Ang3::CreateRadZ( realTargetBodyDirection, m_future.vMoveDirection ); m_future.qOrientation = Quat::CreateRotationVDir( realTargetBodyDirection ); MovementTransitionsLog("[%x] Juke failed because we are trying to start", gEnv->pRenderer->GetFrameID()); } else // at the moment start & stop are mutually exclusive { if (!(allowedTransitionFlags & (1<<eTT_Start))) MovementTransitionsLog("[%x] Start failed because current animation state (%s) doesn't support starting", gEnv->pRenderer->GetFrameID(), const_cast<CPlayer&>(player).GetAnimationGraphState() ? const_cast<CPlayer&>(player).GetAnimationGraphState()->GetCurrentStateName() : ""); else MovementTransitionsLog("[%x] Start failed because speed is %f while maximum %f is allowed", gEnv->pRenderer->GetFrameID(), player.GetAnimatedCharacter()->GetEntitySpeedHorizontal(), maximumSpeedForStart); m_transitionType = eTT_None; // try immediate directionchange first if (allowedTransitionFlags & (1<<eTT_DirectionChange)) { if ( ((oldSample.pseudoSpeed == AISPEED_RUN) || (oldSample.pseudoSpeed == AISPEED_SPRINT)) && (runningDuration > minimumRunningDurationForJuke) && (entitySpeed2D >= minimumSpeedForJuke) ) { if (gEnv->pAISystem && !gEnv->pAISystem->GetSmartObjectManager()->CheckSmartObjectStates(player.GetEntity(), "Busy")) { // === IMMEDIATE DIRECTIONCHANGE === // --------------------------------- // Assume a directionchange after moving forward for one meter (assumedDistanceToJuke=1) // Look up a transition math for that proposed directionchange // --------------------------------- m_pseudoSpeed = oldSample.pseudoSpeed; m_transitionDistance = -1; float assumedDistanceToJuke = 1.0f; CRY_ASSERT(assumedDistanceToJuke > FLT_EPSILON); Vec3 vToProposedMoveTarget = newSample.moveDirection * distToMoveTarget; // vector from current position to current movetarget Vec3 vToProposedJukePoint = oldSample.moveDirection * assumedDistanceToJuke; Vec3 vAfterProposedJukePoint = (vToProposedMoveTarget - vToProposedJukePoint).GetNormalizedSafe(newSample.moveDirection); m_jukeAngle = Ang3::CreateRadZ( vToProposedJukePoint, vAfterProposedJukePoint ); m_transitionType = eTT_DirectionChange; m_bPredicted = false; m_future.vMoveDirection = vAfterProposedJukePoint; Vec3 realTargetBodyDirection = bHasLockedBodyTarget ? targetBodyDirection : vAfterProposedJukePoint; m_targetTravelAngle = Ang3::CreateRadZ( realTargetBodyDirection, vAfterProposedJukePoint ); MovementTransitionsLog("[%x] Considering angle %+3.2f", gEnv->pRenderer->GetFrameID(), RAD2DEG(m_jukeAngle)); const STransition* pTransition = NULL; int index = -1; STransitionMatch bestMatch; transitions.FindBestMatch(*this, &pTransition, &index, &bestMatch); if (pTransition) { // ------------------------------------------------------- // We found a transition matching our guess. Adjust juke point to match the distance of the transition we found // ------------------------------------------------------- float proposedTransitionDistance = (pTransition->minDistance + pTransition->maxDistance)*0.5f; CRY_ASSERT(proposedTransitionDistance > FLT_EPSILON); vToProposedJukePoint = oldSample.moveDirection * proposedTransitionDistance; vAfterProposedJukePoint = vToProposedMoveTarget - vToProposedJukePoint; float proposedDistAfterMoveTarget = vAfterProposedJukePoint.GetLength2D(); vAfterProposedJukePoint.NormalizeSafe(newSample.moveDirection); if (proposedDistAfterMoveTarget >= transitions.GetMinDistanceAfterDirectionChange()) { m_jukeAngle = Ang3::CreateRadZ( vToProposedJukePoint, vAfterProposedJukePoint ); m_future.vMoveDirection = vAfterProposedJukePoint; realTargetBodyDirection = bHasLockedBodyTarget ? targetBodyDirection : vAfterProposedJukePoint; m_targetTravelAngle = Ang3::CreateRadZ( realTargetBodyDirection, vAfterProposedJukePoint ); MovementTransitionsLog("[%x] Proposing angle %+3.2f", gEnv->pRenderer->GetFrameID(), RAD2DEG(m_jukeAngle)); m_transitionDistance = proposedTransitionDistance; m_future.qOrientation = Quat::CreateRotationVDir( realTargetBodyDirection ); } else { MovementTransitionsLog("[%x] Immediate Juke failed because not enough distance after the juke (distance needed = %f, max distance = %f)", gEnv->pRenderer->GetFrameID(), transitions.GetMinDistanceAfterDirectionChange(), proposedDistAfterMoveTarget); m_transitionType = eTT_None; } } else { MovementTransitionsLog("[%x] Immediate Juke failed because no animation found for this angle/stance/speed", gEnv->pRenderer->GetFrameID()); m_transitionType = eTT_None; } } else { MovementTransitionsLog("[%x] Immediate Juke failed because smart object is playing", gEnv->pRenderer->GetFrameID()); } } else { if (!((oldSample.pseudoSpeed == AISPEED_RUN) || (oldSample.pseudoSpeed == AISPEED_SPRINT))) { MovementTransitionsLog("[%x] Immediate Juke failed because current pseudospeed (%f) is not supported", gEnv->pRenderer->GetFrameID(), oldSample.pseudoSpeed); } else if (runningDuration <= minimumRunningDurationForJuke) { MovementTransitionsLog("[%x] Immediate Juke failed because running only %f seconds while more than %f is needed", gEnv->pRenderer->GetFrameID(), runningDuration.GetSeconds(), minimumRunningDurationForJuke); } else //if (entitySpeed2D < minimumSpeedForJuke) { MovementTransitionsLog("[%x] Immediate Juke failed because speed is only %f while %f is needed", gEnv->pRenderer->GetFrameID(), entitySpeed2D, minimumSpeedForJuke); } } } else { MovementTransitionsLog("[%x] Immediate Juke failed because current animation state (%s) doesn't support juking", gEnv->pRenderer->GetFrameID(), const_cast<CPlayer&>(player).GetAnimationGraphState() ? const_cast<CPlayer&>(player).GetAnimationGraphState()->GetCurrentStateName() : NULL); } if (m_transitionType == eTT_None) // directionchange wasn't found { if ((allowedTransitionFlags & (1<<eTT_Stop)) && (distAfterMoveTarget < FLT_EPSILON)) { // === PREDICTED STOP === // We want to stop in the future m_transitionType = eTT_Stop; m_bPredicted = true; m_transitionDistance = distToMoveTarget; m_future.vMoveDirection = vToMoveTarget.GetNormalizedSafe(newSample.moveDirection); m_arrivalAngle = request.HasDesiredBodyDirectionAtTarget() ? Ang3::CreateRadZ( request.GetDesiredBodyDirectionAtTarget(), m_future.vMoveDirection ) : 0.0f; m_future.qOrientation = request.HasDesiredBodyDirectionAtTarget() ? Quat::CreateRotationVDir(request.GetDesiredBodyDirectionAtTarget()) : Quat::CreateRotationVDir(m_future.vMoveDirection); MovementTransitionsLog("[%x] Predicted Juke failed because we are trying to stop", gEnv->pRenderer->GetFrameID()); } else if ((allowedTransitionFlags & (1<<eTT_DirectionChange)) && (distAfterMoveTarget >= transitions.GetMinDistanceAfterDirectionChange())) { // === PREDICTED DIRECTIONCHANGE === // We want to change direction in the future // NOTE: This logic will fail if we trigger the juke really late, because then the distToMoveTarget will be very small and the angle calculation not precise m_transitionType = eTT_DirectionChange; m_bPredicted = true; m_transitionDistance = distToMoveTarget; m_jukeAngle = Ang3::CreateRadZ( vToMoveTarget, vAfterMoveTarget ); m_future.vMoveDirection = vAfterMoveTarget.GetNormalized(); const Vec3 realTargetBodyDirection = bHasLockedBodyTarget ? targetBodyDirection : m_future.vMoveDirection; m_future.qOrientation = Quat::CreateRotationVDir( realTargetBodyDirection ); m_targetTravelAngle = Ang3::CreateRadZ( realTargetBodyDirection, m_future.vMoveDirection ); } } } } else // if (newSample.pseudoSpeed <= 0.0f) { // Either: // - we are in a Stop and want to continue stopping // - we are moving and suddenly want to stop // - we are in a Start and want to stop <-- oldPseudoSpeed logic is wrong, oldPseudoSpeed will be 0 for a while so we should use real velocity // - we are stopped already and just want to stay stopped MovementTransitionsLog("[%x] Juke failed because we are not running or trying to stop", gEnv->pRenderer->GetFrameID()); MovementTransitionsLog("[%x] Start failed because we are not requesting movement", gEnv->pRenderer->GetFrameID()); if ( (( (oldSample.pseudoSpeed == AISPEED_RUN) || (oldSample.pseudoSpeed == AISPEED_SPRINT)) && (runningDuration > minimumRunningDurationForRunStop) && (entitySpeed2D >= minimumSpeedForRunStop)) || ((oldSample.pseudoSpeed == AISPEED_WALK) && (entitySpeed2D >= minimumSpeedForWalkStop)) ) { if (allowedTransitionFlags & (1<<eTT_Stop)) { // === IMMEDIATE STOP === if( gEnv->pAISystem ) { ISmartObjectManager* pSmartObjectManager = gEnv->pAISystem->GetSmartObjectManager(); if (!pSmartObjectManager || !pSmartObjectManager->CheckSmartObjectStates(player.GetEntity(), "Busy")) { // Trigger immediate stop when currently running and suddenly wanting to stop. // // NOTE: If this happens right before a forbidden area and the safeLine is not correct // or the Stop transition distance isn't configured properly the AI will enter it.. // m_pseudoSpeed = oldSample.pseudoSpeed; m_transitionDistance = -1; m_arrivalAngle = 0.0f; m_transitionType = eTT_Stop; m_bPredicted = false; const STransition* pTransition = NULL; int index = -1; STransitionMatch bestMatch; transitions.FindBestMatch(*this, &pTransition, &index, &bestMatch); float minDistanceForStop = pTransition ? pTransition->minDistance : 0.0f; bool bIsOnSafeLine = IsOnSafeLine(safeLine, playerPos, newSample.moveDirection, minDistanceForStop); if (bIsOnSafeLine) { m_transitionDistance = minDistanceForStop; m_future.vMoveDirection = newSample.moveDirection; m_future.qOrientation = Quat::CreateRotationVDir(newSample.moveDirection); pMoveParams->desiredVelocity = player.GetEntity()->GetWorldRotation().GetInverted() * player.GetLastRequestedVelocity(); float maxSpeed = player.GetStanceMaxSpeed(m_stance); if (maxSpeed > 0.01f) pMoveParams->desiredVelocity /= maxSpeed; } else { m_transitionType = eTT_None; } } } } } } if (request.HasDesiredSpeed()) { m_future.speed = request.GetDesiredTargetSpeed(); } }
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,atan2_tpl(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } const float fNetAimLerpFactor = g_pGameCVars->pl_netAimLerpFactor; //Vector slerp produces artifacts here, using a per-component lerp instead Vec3 vCurrentRight = m_lookDir.cross(Vec3Constants<float>::fVec3_OneZ); Vec3 vCurrentProjected = -(vCurrentRight.cross(Vec3Constants<float>::fVec3_OneZ)); vCurrentRight.Normalize(); vCurrentProjected.Normalize(); Vec3 vNewRight = m_curInput.lookDirection.cross(Vec3Constants<float>::fVec3_OneZ); Vec3 vNewProjected = -(vNewRight.cross(Vec3Constants<float>::fVec3_OneZ)); vNewProjected.Normalize(); float fRotZDirDot = vNewProjected.dot(vCurrentRight); float fRotZDot = vNewProjected.dot(vCurrentProjected); float fRotZ = acos_tpl(fRotZDot); fRotZ = AngleWrap_PI(fRotZ); float fRotZFinal = -fsgnf(fRotZDirDot) * fRotZ * fNetAimLerpFactor; float fCurrentAngle = acos_tpl(Vec3Constants<float>::fVec3_OneZ.dot(m_lookDir)); float fNewAngle = acos_tpl(Vec3Constants<float>::fVec3_OneZ.dot(m_curInput.lookDirection)); float fRotXFinal = (fNewAngle - fCurrentAngle) * -fNetAimLerpFactor; //Rotate around X first, as we have already generated the right vector Vec3 vNewLookDir = m_lookDir.GetRotated(vCurrentRight, fRotXFinal); m_lookDir = vNewLookDir.GetRotated(Vec3Constants<float>::fVec3_OneZ, fRotZFinal); 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); moveRequest.SetPseudoSpeed(CalculatePseudoSpeed()); 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 0 if (m_pPlayer->m_netSetPosition) { SPredictedCharacterStates charStates; charStates.states[0].position = m_pPlayer->GetEntity()->GetPos(); charStates.states[0].orientation = m_pPlayer->GetEntity()->GetRotation(); charStates.states[0].deltatime = 0.0f; charStates.states[1].position = m_pPlayer->m_netCurrentLocation; charStates.states[1].orientation = m_pPlayer->GetEntity()->GetRotation(); charStates.states[1].deltatime = gEnv->pTimer->GetFrameTime(); charStates.states[2].position = m_pPlayer->m_netDesiredLocation; charStates.states[2].orientation = m_pPlayer->GetEntity()->GetRotation(); charStates.states[2].deltatime = m_pPlayer->m_netLerpTime; charStates.nStates = 3; moveRequest.SetPrediction(charStates); } #endif //0 #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 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(); }