//------------------------------------------------------------------------ void CVehicleSeatActionRotateTurret::UpdatePartRotation(EVehicleTurretRotationType eType, float frameTime) { CRY_ASSERT( eType < eVTRT_NumRotationTypes ); const float threshold = 0.01f; if (frameTime > 0.08f) frameTime = 0.08f; CVehiclePartBase* pPart = m_rotations[eType].m_pPart; IVehiclePart* pParent = pPart->GetParent(); IActor* pActor = m_pSeat->GetPassengerActor(); float rot_dir = fsgnf(m_rotations[eType].m_action); float max_rotation = fabsf(m_rotations[eType].m_action); float rot_speed = DEG2RAD(fabsf(m_rotations[eType].m_speed)) * GetDamageSpeedMul(pPart); float delta = rot_dir * rot_speed * frameTime; delta += m_rotations[eType].m_aimAssist; delta = fmod(delta, gf_PI2); if (delta > gf_PI) delta -= gf_PI2; if (delta < -gf_PI) delta += gf_PI2; Limit( delta, -max_rotation, max_rotation); Ang3 deltaAngles(ZERO); if (eType == eVTRT_Pitch) deltaAngles.x = delta; else if (eType == eVTRT_Yaw) deltaAngles.z = delta; else CRY_ASSERT(false && "Unknown turret rotation"); Matrix34 tm = pPart->GetLocalBaseTM(); Ang3 angles = Ang3::GetAnglesXYZ(tm) + deltaAngles; float lerp = 0.f; if (eType == eVTRT_Pitch) { Vec3 yAxis = m_rotations[eVTRT_Yaw].m_pPart->GetLocalBaseTM().GetColumn1(); yAxis.z = 0.f; yAxis.normalize(); lerp = 0.5f - 0.5f * yAxis.y; Limit(lerp, 0.0f, 1.0f); } // clamp to limits if (m_rotations[eType].m_minLimitF != 0.0f || m_rotations[eType].m_maxLimit != 0.0f) { // Different clamp angles facing forwards/backwards float minLimit = m_rotations[eType].m_minLimitF + (m_rotations[eType].m_minLimitB - m_rotations[eType].m_minLimitF) * lerp; float angle = (eType == eVTRT_Pitch) ? angles.x : angles.z; if (angle > m_rotations[eType].m_maxLimit || angle < minLimit) { angle = clamp_tpl(angle, minLimit, m_rotations[eType].m_maxLimit); m_rotations[eType].m_currentValue = 0.f; if (eType == eVTRT_Pitch) angles.x = angle; else angles.z = angle; } } m_rotations[eType].m_orientation.Set(Quat::CreateRotationXYZ(angles)); m_rotations[eType].m_orientation.Update(frameTime); m_rotations[eType].m_action = 0.0f; m_rotations[eType].m_aimAssist = 0.0f; Matrix34 newTM(m_rotations[eType].m_orientation.Get().GetNormalized()); newTM.SetTranslation(tm.GetTranslation()); pPart->SetLocalBaseTM(newTM); // store world-space rotation const Matrix34 &worldTM = pPart->GetWorldTM(); m_rotations[eType].m_prevWorldQuat = Quat(worldTM); CRY_ASSERT(m_rotations[eType].m_prevWorldQuat.IsValid()); // now update the turret sound based on the calculated rotation speed UpdateRotationSound(eType, delta, frameTime); }
//------------------------------------------------------------------------------------ // Adjust the aim dir before we pass it to the torsoAim pose modifier, this allows us // to have the weapon deviate from the camera in certain circumstances // Should only be called once per frame as it time-steps internal vars //------------------------------------------------------------------------------------ void CLocalPlayerComponent::AdjustTorsoAimDir(float fFrameTime, Vec3 &aimDir) { const f32 HALF_PI = gf_PI * 0.5f; float newElevLimit = HALF_PI; const f32 MIN_FLATTEN_LEVEL = -0.3f; const f32 MAX_FLATTEN_LEVEL = -0.1f; const f32 TARGET_FLATTEN_ELEV = -0.2f; const f32 LIMIT_CHANGE_RATE = HALF_PI; if (g_pGameCVars->pl_swimAlignArmsToSurface && m_rPlayer.IsSwimming() && (m_rPlayer.m_playerStateSwim_WaterTestProxy.GetRelativeWaterLevel() > MIN_FLATTEN_LEVEL)) { newElevLimit = (m_rPlayer.m_playerStateSwim_WaterTestProxy.GetRelativeWaterLevel() - MIN_FLATTEN_LEVEL) / (MAX_FLATTEN_LEVEL - MIN_FLATTEN_LEVEL); newElevLimit = LERP(gf_PI * 0.5f, TARGET_FLATTEN_ELEV, clamp_tpl(newElevLimit, 0.0f, 1.0f)); } float limitDelta = LIMIT_CHANGE_RATE * fFrameTime; float limitDiff = newElevLimit - m_stapElevLimit; float smoothedLimit = (float) fsel(fabs_tpl(limitDiff) - limitDelta, m_stapElevLimit + (fsgnf(limitDiff) * limitDelta), newElevLimit); m_stapElevLimit = smoothedLimit; if (smoothedLimit < HALF_PI) { //--- Need to limit, convert to yaw & elev, limit & then convert back float yaw, elev; float xy = aimDir.GetLengthSquared2D(); if (xy > 0.001f) { yaw = atan2_tpl(aimDir.y,aimDir.x); elev = asin_tpl(clamp_tpl(aimDir.z, -1.f, +1.f)); } else { yaw = 0.f; elev = (float)fsel(aimDir.z, +1.f, -1.f) * (gf_PI*0.5f); } elev = min(elev, smoothedLimit); float sinYaw, cosYaw; float sinElev, cosElev; sincos_tpl(yaw, &sinYaw, &cosYaw); sincos_tpl(elev, &sinElev, &cosElev); aimDir.x = cosYaw * cosElev; aimDir.y = sinYaw * cosElev; aimDir.z = sinElev; } }
bool CPlayerStateSwim::OnPrePhysicsUpdate( CPlayer& player, const SActorFrameMovementParams& movement, float frameTime ) { const CPlayerStateSwim_WaterTestProxy& waterProxy = player.m_playerStateSwim_WaterTestProxy; CPlayerStateUtil::PhySetFly( player ); const SPlayerStats& stats = player.m_stats; #ifdef STATE_DEBUG const bool debug = (g_pGameCVars->cl_debugSwimming != 0); #endif const Vec3 entityPos = player.GetEntity()->GetWorldPos(); const Quat baseQuat = player.GetBaseQuat(); const Vec3 vRight(baseQuat.GetColumn0()); Vec3 velocity = player.GetActorPhysics().velocity; // Underwater timer, sounds update and surface wave speed. if (waterProxy.IsHeadUnderWater()) { m_headUnderWaterTimer += frameTime; if (m_headUnderWaterTimer <= -0.0f && !m_onSurface ) { player.PlaySound(CPlayer::ESound_DiveIn, true, "speed", velocity.len()); m_headUnderWaterTimer = 0.0f; } player.PlaySound(CPlayer::ESound_Underwater, true); } else { m_headUnderWaterTimer -= frameTime; if (m_headUnderWaterTimer >= 0.0f && (waterProxy.IsHeadComingOutOfWater() || m_onSurface)) { player.PlaySound(CPlayer::ESound_DiveOut, true, "speed", velocity.len()); m_headUnderWaterTimer = 0.0f; } player.PlaySound(CPlayer::ESound_Underwater, false); } m_headUnderWaterTimer = clamp_tpl( m_headUnderWaterTimer, -0.2f, 0.2f ); // Apply water flow velocity to the player Vec3 gravity; pe_params_buoyancy buoyancy[s_maxWaterVolumesToConsider]; if (int count = gEnv->pPhysicalWorld->CheckAreas(entityPos, gravity, &buoyancy[0], s_maxWaterVolumesToConsider)) { for(int i = 0; i < count && i < s_maxWaterVolumesToConsider; ++i) { // 0 is water if( buoyancy[i].iMedium == 0 ) { velocity += (buoyancy[i].waterFlow * frameTime); } } } // Calculate desired acceleration (user input) Vec3 desiredWorldVelocity(ZERO); Vec3 acceleration(ZERO); { Vec3 desiredLocalNormalizedVelocity(ZERO); Vec3 desiredLocalVelocity(ZERO); const Quat viewQuat = player.GetViewQuat(); const float backwardMultiplier = (float)__fsel(movement.desiredVelocity.y, 1.0f, g_pGameCVars->pl_swimBackSpeedMul); desiredLocalNormalizedVelocity.x = movement.desiredVelocity.x * g_pGameCVars->pl_swimSideSpeedMul; desiredLocalNormalizedVelocity.y = movement.desiredVelocity.y * backwardMultiplier; float sprintMultiplier = 1.0f; if ((player.IsSprinting()) && !player.IsCinematicFlagActive(SPlayerStats::eCinematicFlag_RestrictMovement)) { sprintMultiplier = GetSwimParams().m_swimSprintSpeedMul; // Higher speed multiplier when sprinting while looking up const float upFraction = clamp_tpl(viewQuat.GetFwdZ(), 0.0f, 1.0f); sprintMultiplier *= LERP(1.0f, GetSwimParams().m_swimUpSprintSpeedMul, upFraction); } const float baseSpeed = player.GetStanceMaxSpeed(STANCE_SWIM); desiredLocalVelocity.x = desiredLocalNormalizedVelocity.x * sprintMultiplier * baseSpeed; desiredLocalVelocity.y = desiredLocalNormalizedVelocity.y * sprintMultiplier * baseSpeed; desiredLocalVelocity.z = desiredLocalNormalizedVelocity.z * g_pGameCVars->pl_swimVertSpeedMul * baseSpeed; // The desired movement is applied in view-space, not in entity-space, since entity does not necessarily pitch while swimming. desiredWorldVelocity += viewQuat.GetColumn0() * desiredLocalVelocity.x; desiredWorldVelocity += viewQuat.GetColumn1() * desiredLocalVelocity.y; // though, apply up/down in world space. desiredWorldVelocity.z += desiredLocalVelocity.z; #ifdef STATE_DEBUG if (debug) { gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.8f), 1.5f, "BaseSpeed %1.3f", baseSpeed); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,1.0f), 1.5f, "SprintMul %1.2f", sprintMultiplier); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.6f), 1.5f, "MoveN[%1.3f, %1.3f, %1.3f]", desiredLocalNormalizedVelocity.x, desiredLocalNormalizedVelocity.y, desiredLocalNormalizedVelocity.z); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.5f), 1.5f, "VeloL[%1.3f, %1.3f, %1.3f]", desiredLocalVelocity.x, desiredLocalVelocity.y, desiredLocalVelocity.z); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.4f), 1.5f, "VeloW[%1.3f, %1.3f, %1.3f]", desiredWorldVelocity.x, desiredWorldVelocity.y, desiredWorldVelocity.z); } #endif //Remove a bit of control when entering the water const float userControlFraction = (float)__fsel(0.3f - waterProxy.GetSwimmingTimer(), 0.2f, 1.0f); acceleration += desiredWorldVelocity * userControlFraction; } // Apply acceleration (frame-rate independent) const float accelerateDelayInv = 3.333f; velocity += acceleration * (frameTime * accelerateDelayInv); #ifdef STATE_DEBUG if( debug ) { gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.2f), 1.5f, " Axx[%1.3f, %1.3f, %1.3f]", acceleration.x, acceleration.y, acceleration.z); } #endif //-------------------- const float relativeWaterLevel = waterProxy.GetRelativeWaterLevel() + 0.1f; const float surfaceDistanceFraction = clamp_tpl(fabsf(relativeWaterLevel), 0.0f, 1.0f); float surfaceProximityInfluence = 1.0f - surfaceDistanceFraction; const float verticalVelocityFraction = clamp_tpl((fabsf(desiredWorldVelocity.z) - 0.3f) * 2.5f, 0.0f, 1.0f); surfaceProximityInfluence = surfaceProximityInfluence * (1.0f - verticalVelocityFraction); // Apply velocity dampening (frame-rate independent) Vec3 damping(ZERO); const float zSpeedPreDamping = velocity.z; { damping.x = fabsf(velocity.x); damping.y = fabsf(velocity.y); // Vertical damping is special, to allow jumping out of water with higher speed, // and also not sink too deep when falling down ito the water after jump or such. float zDamp = 1.0f + (6.0f * clamp_tpl((-velocity.z - 1.0f) * 0.333f, 0.0f, 1.0f)); zDamp *= 1.0f - surfaceProximityInfluence; damping.z = fabsf(velocity.z) * zDamp; const float stopDelayInv = 3.333f; damping *= (frameTime * stopDelayInv); velocity.x = (float)__fsel((fabsf(velocity.x) - damping.x), (velocity.x - fsgnf(velocity.x) * damping.x), 0.0f); velocity.y = (float)__fsel((fabsf(velocity.y) - damping.y), (velocity.y - fsgnf(velocity.y) * damping.y), 0.0f); velocity.z = (float)__fsel((fabsf(velocity.z) - damping.z), (velocity.z - fsgnf(velocity.z) * damping.z), 0.0f); //Make sure you can not swim above the surface if ((relativeWaterLevel >= 0.0f) && (velocity.z > 0.0f)) { velocity.z = 0.0f; } } // Decide if we're on the surface and therefore need to be kept there.. if( relativeWaterLevel > -0.2f && relativeWaterLevel < 1.0f && fabs_tpl( zSpeedPreDamping ) < 0.5f ) { if( !waterProxy.IsHeadUnderWater() ) { m_onSurface = true; } } else { // we only leave the surface if the player moves, otherwise we try and keep the // player on the surface, even if they currently arent m_onSurface = false; } // Calculate and apply surface movement to the player. float speedDelta = 0.0f; if( m_onSurface ) { const float newWaterLevel = waterProxy.GetWaterLevel(); const float waterLevelDelta = clamp_tpl(newWaterLevel - m_lastWaterLevel, -1.0f, 1.0f ); const float newCheckedTime = waterProxy.GetWaterLevelTimeUpdated(); const float timeDelta = newCheckedTime - m_lastWaterLevelTime; if( timeDelta > FLT_EPSILON ) { speedDelta = waterLevelDelta/timeDelta; velocity.z += speedDelta; } m_lastWaterLevel = newWaterLevel; m_lastWaterLevelTime = newCheckedTime; } // Set request type and velocity player.GetMoveRequest().type = eCMT_Fly; player.GetMoveRequest().velocity = velocity; #ifdef STATE_DEBUG // DEBUG VELOCITY if (debug) { gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.0f), 1.5f, "Velo[%1.3f, %1.3f, %1.3f]", velocity.x, velocity.y, velocity.z); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.4f), 1.5f, "Damp[%1.3f, %1.3f, %1.3f]", damping.x, damping.y, damping.z); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f - Vec3(0,0,0.6f), 1.5f, "FrameTime %1.4f", frameTime); gEnv->pRenderer->DrawLabel(entityPos - vRight * 1.5f + Vec3(0,0,0.3f), 1.5f, "DeltaSpeed[%1.3f]", speedDelta ); //if (bNewSwimJumping) //gEnv->pRenderer->DrawLabel(entityPos - vRight * 0.15f + Vec3(0,0,0.6f), 2.0f, "JUMP"); } #endif return true; }
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(); }