void CMFXForceFeedbackEffect::Execute(SMFXRunTimeEffectParams& params) { FUNCTION_PROFILER(gEnv->pSystem, PROFILE_ACTION); if (params.playflags & MFX_PLAY_FORCEFEEDBACK) { float distanceToPlayerSqr = FLT_MAX; IActor *pClientActor = gEnv->pGame->GetIGameFramework()->GetClientActor(); if (pClientActor) { distanceToPlayerSqr = (pClientActor->GetEntity()->GetWorldPos() - params.pos).GetLengthSquared(); } const float testDistanceSqr = clamp_tpl(distanceToPlayerSqr, m_forceFeedbackParams.intensityFallOffMinDistanceSqr, m_forceFeedbackParams.intensityFallOffMaxDistanceSqr); const float minMaxDiffSqr = m_forceFeedbackParams.intensityFallOffMaxDistanceSqr - m_forceFeedbackParams.intensityFallOffMinDistanceSqr; float effectIntensity = (float)__fsel(-minMaxDiffSqr, 0.0f, 1.0f - (testDistanceSqr - m_forceFeedbackParams.intensityFallOffMinDistanceSqr) / (minMaxDiffSqr + FLT_EPSILON)); effectIntensity *= effectIntensity; if (effectIntensity > 0.01f) { IForceFeedbackSystem* pForceFeedback = CCryAction::GetCryAction()->GetIForceFeedbackSystem(); assert(pForceFeedback); ForceFeedbackFxId fxId = pForceFeedback->GetEffectIdByName(m_forceFeedbackParams.forceFeedbackEventName.c_str()); pForceFeedback->PlayForceFeedbackEffect(fxId, SForceFeedbackRuntimeParams(effectIntensity, 0.0f)); } } }
//--------------------------------------------------------------- void CPlayerRotation::ProcessNormalRoll( float frameTime ) { //apply lean/roll float rollAngleGoal(0); const Vec3 velocity = m_player.GetActorPhysics().velocity; const float speed2( velocity.len2()); if ((speed2 > 0.01f) && m_player.m_stats.inAir) { const float maxSpeed = m_player.GetStanceMaxSpeed(STANCE_STAND); const float maxSpeedInverse = (float)__fsel(-maxSpeed, 1.0f, __fres(maxSpeed + FLT_EPSILON)); const Vec3 velVec = velocity * maxSpeedInverse; const float dotSide(m_viewQuat.GetColumn0() * velVec); rollAngleGoal -= DEG2RAD(dotSide * 1.5f);; } const float tempLean = m_leanAmount; const float leanAmountMultiplier = 3.0f; const float leanAmount = clamp_tpl(tempLean * leanAmountMultiplier, -1.0f, 1.0f); rollAngleGoal += DEG2RAD(leanAmount * m_player.m_params.leanAngle); Interpolate(m_viewRoll,rollAngleGoal,9.9f,frameTime); m_deltaAngles += m_angularImpulseDelta; }
// "ratio" is the amplitude of the shaking void CView::ProcessShakeNormal_CalcRatio( SShake *pShake, float frameTime, float endSustain ) { const float FADEOUT_TIME_WHEN_INTERRUPTED = 0.5f; if (pShake->interrupted) pShake->ratio = max(0.f, pShake->ratio - ( frameTime / FADEOUT_TIME_WHEN_INTERRUPTED )); // fadeout after interrupted else if (pShake->timeDone>=endSustain && pShake->fadeOutDuration>0) { float timeFading = pShake->timeDone - endSustain; pShake->ratio = clamp_tpl( 1.f - timeFading / pShake->fadeOutDuration, 0.f, 1.f ); // fadeOut } else if (pShake->timeDone>=pShake->fadeInDuration) { pShake->ratio = 1.f; // sustain } else { pShake->ratio = min( 1.f, pShake->timeDone / pShake->fadeInDuration ); // fadeIn } if (pShake->permanent && pShake->timeDone>=pShake->fadeInDuration && !pShake->interrupted) pShake->ratio = 1.f; // permanent standing }
float GetQuatAbsAngle(const Quat& q) { //float fwd = q.GetColumn1().y; float fwd = q.GetFwdY(); fwd = clamp_tpl(fwd, -1.0f, 1.0f); return acos_tpl(fwd); }
float ApplyAntiOscilationFilter(float value, float filtersize) { float filterfraction = clamp_tpl(abs(value) / filtersize, 0.0f, 1.0f); float filter = (0.5f - 0.5f * cos_tpl(filterfraction * gf_PI)); value *= filter; return value; }
//------------------------------------------------------------------------ void CWeapon::OnDroppedByPlayer(IInventory* pPlayerInventory) { CRY_ASSERT(pPlayerInventory); TFireModeVector::const_iterator firemodesEndIt = m_firemodes.end(); for (TFireModeVector::const_iterator firemodeCit = m_firemodes.begin(); firemodeCit != firemodesEndIt ; ++firemodeCit) { const CFireMode* pFiremode = *firemodeCit; if (pFiremode) { IEntityClass* pFiremodeAmmo = pFiremode->GetAmmoType(); if (pFiremodeAmmo) { // Exchange also ammo pool from inventory to bonus ammo map, for next user who picks it up int ammoCount = pPlayerInventory->GetAmmoCount(pFiremodeAmmo); if (ammoCount > 0) { if(gEnv->bMultiplayer) { int currentClipAmount = GetAmmoCount(pFiremodeAmmo); int clipSize = pFiremode->GetClipSize(); int numForClip = clamp_tpl(clipSize - currentClipAmount, 0, ammoCount); SetAmmoCount(pFiremodeAmmo, currentClipAmount + numForClip); ammoCount -= numForClip; } SetInventoryAmmoCount(pFiremodeAmmo, 0); SWeaponAmmoUtils::SetAmmo(m_bonusammo, pFiremodeAmmo, ammoCount); } } } } }
void EntityEffects::CHeatController::InitWithEntity( IEntity* pEntity, const float baseHeat ) { CRY_ASSERT(m_ownerEntity == NULL); CRY_ASSERT(pEntity); m_ownerEntity = pEntity; m_baseHeat = clamp_tpl(baseHeat, 0.0f, 1.0f); }
// (jh) here it moves void CPlayerInput::ApplyMovement(Vec3 delta) { //m_deltaMovement += delta; m_deltaMovement.x = clamp_tpl(m_deltaMovement.x+delta.x,-1.0f,1.0f); m_deltaMovement.y = clamp_tpl(m_deltaMovement.y+delta.y,-1.0f,1.0f); m_deltaMovement.z = 0; // (jh) debug: this should draw but it dissapers... // IRenderer* renderer = gEnv->pRenderer; // renderer->Set2DMode(true, renderer->GetWidth(), renderer->GetHeight()); //static float color[] = {1,1,1,1}; //renderer->Draw2dLabel(100,50,1.5,color,false,"m_deltaMovement:%f,%f (requested:%f,%f", m_deltaMovement.x, m_deltaMovement.y,delta.x,delta.y); //ColorF col(1.0,1.0,1.0,1.0); //renderer->Draw2dLabel(100,50,2,col,false,"m_deltaMovement:%f,%f (requested:%f,%f", m_deltaMovement.x, m_deltaMovement.y,delta.x,delta.y); // renderer->Set2DMode(false, 0, 0); }
void CPlayerStateSwim_WaterTestProxy::UpdateSubmergedFraction(const float referenceHeight, const float playerHeight, const float waterLevel) { const float referenceHeightFinal = max(referenceHeight, 1.3f); const float submergedTotal = playerHeight - waterLevel; const float submergedFraction = (float)__fsel(submergedTotal, 0.0f, clamp_tpl(-submergedTotal * __fres(referenceHeightFinal), 0.0f, 1.0f)); SetSubmergedFraction(submergedFraction); }
float EntityEffects::CHeatController::UpdateCoolDown(const float frameTime) { const float cooldownRate = 0.075f; m_baseHeat = clamp_tpl(m_baseHeat - (frameTime * cooldownRate), 0.0f, m_baseHeat); m_coolDownHeat = (float)fsel(-(m_baseHeat - m_coolDownHeat), -1.0f, m_coolDownHeat); return m_baseHeat; }
float EntityEffects::CHeatController::UpdateHeat( const float frameTime ) { m_heatPulse.runningTime += frameTime; const float pulseFraction = clamp_tpl(m_heatPulse.runningTime * (float)fres(m_heatPulse.baseTime), 0.0f, 1.0f); const bool pulseActive = (pulseFraction < 1.0f); float pulseHeat = 0.0f; if (pulseActive) { pulseHeat = (m_heatPulse.heat * (1.0f - pulseFraction)); } else { m_heatPulse.Reset(); } return clamp_tpl(m_baseHeat + pulseHeat, 0.0f, 1.0f); }
//------------------------------------------------------------------------ bool CWeapon::CAnimationFiringLocator::GetProbableHit(EntityId weaponId, const IFireMode* pFireMode, Vec3& hit) { CRY_ASSERT(m_pOwnerWeapon); // [*DavidR | 14/Oct/2010] Note: Basically a Copy & Paste of CSingle::GetProbableHit but without getting info // from the movement controller static Vec3 pos(ZERO), dir(FORWARD_DIRECTION); CActor *pActor = m_pOwnerWeapon->GetOwnerActor(); IEntity *pWeaponEntity = m_pOwnerWeapon->GetEntity(); static PhysSkipList skipList; skipList.clear(); CSingle::GetSkipEntities(m_pOwnerWeapon, skipList); float rayLength = 250.0f; IEntityClass* pAmmoClass = pFireMode->GetAmmoType(); const SAmmoParams *pAmmoParams = pAmmoClass ? g_pGame->GetWeaponSystem()->GetAmmoParams(pAmmoClass) : NULL; if (pAmmoParams) { //Benito - It could happen that the lifetime/speed are zero, so ensure at least some minimum distance check rayLength = clamp_tpl(min(pAmmoParams->speed * pAmmoParams->lifetime, rayLength), 5.0f, rayLength); } // Change this so it calls this firing locator's GetFiringPos if it gets implemented (no need atm) pos = pFireMode->GetFiringPos(Vec3Constants<float>::fVec3_Zero); IF_UNLIKELY(!GetFiringDir(weaponId, pFireMode, dir, Vec3Constants<float>::fVec3_Zero, Vec3Constants<float>::fVec3_Zero)) dir = pFireMode->GetFiringDir(Vec3Constants<float>::fVec3_Zero, pos); dir *= rayLength; static ray_hit rayHit; // use the ammo's pierceability uint32 flags=(geom_colltype_ray|geom_colltype13)<<rwi_colltype_bit|rwi_colltype_any|rwi_force_pierceable_noncoll|rwi_ignore_solid_back_faces; uint8 pierceability = 8; if (pAmmoParams && pAmmoParams->pParticleParams && !is_unused(pAmmoParams->pParticleParams->iPierceability)) { pierceability=pAmmoParams->pParticleParams->iPierceability; } flags |= pierceability; if (gEnv->pPhysicalWorld->RayWorldIntersection(pos, dir, ent_all, flags, &rayHit, 1, !skipList.empty() ? &skipList[0] : NULL, skipList.size())) { hit = rayHit.pt; } else { hit = pos + dir; } return true; }
void SearchSpot::DebugDraw(float searchTimeOut) { ColorB spotColor; switch (m_status) { case NotSearchedYet: spotColor = ColorB(0, 0, 255); break; case BeingSearchedRightAboutNow: spotColor = ColorB(255, 255, 0); break; case Searched: spotColor = ColorB(0, 255, 0); break; case Unreachable: spotColor = ColorB(255, 0, 0); break; case SearchedTimingOut: if(searchTimeOut) { uint8 green = (uint8)(255 * clamp_tpl( (m_searchTimeoutLeft / (searchTimeOut / 2.0f)), 0.0f, 1.0f)); uint8 blue = (uint8)(255 * clamp_tpl(((searchTimeOut - m_searchTimeoutLeft) / (searchTimeOut / 2.0f)), 0.0f, 1.0f)); spotColor = ColorB(0, green, blue); } break; } IRenderAuxGeom* pDebugRenderer = gEnv->pRenderer->GetIRenderAuxGeom(); pDebugRenderer->DrawSphere(m_pos, 0.3f, spotColor); if (m_assigneeID) { Agent agent(m_assigneeID); if (agent) pDebugRenderer->DrawLine(agent.GetPos(), ColorB(255, 255, 0), m_pos, ColorB(255, 255, 0), 2.0f); } }
CForceFeedBackSystem::SFFOutput CForceFeedBackSystem::SActiveEffect::Update( float frameTime ) { SFFOutput effectFF; bool canPlay = (runtimeParams.delay <= 0.0f); if (canPlay) { bool isLoopingEffect = (effectTime <= 0.0f); const float effectTimeInv = !isLoopingEffect ? (float)__fres(effectTime) : 1.0f; const float sampleTime = runningTime * effectTimeInv; const float sampleTimeAAtFreq = sampleTime * frequencyA; const float sampleTimeAAtFreqNorm = clamp_tpl(sampleTimeAAtFreq - floor_tpl(sampleTimeAAtFreq), 0.0f, 1.0f); const float sampleTimeBAtFreq = sampleTime * frequencyB; const float sampleTimeBAtFreqNorm = clamp_tpl(sampleTimeBAtFreq - floor_tpl(sampleTimeBAtFreq), 0.0f, 1.0f); effectFF.forceFeedbackA = m_patternA.SamplePattern(sampleTimeAAtFreqNorm) * m_envelopeA.SampleEnvelope(sampleTime) * runtimeParams.intensity; effectFF.forceFeedbackB = m_patternB.SamplePattern(sampleTimeBAtFreqNorm) * m_envelopeB.SampleEnvelope(sampleTime) * runtimeParams.intensity; runningTime += frameTime; //Re-start the loop if (isLoopingEffect) { runningTime = (float)__fsel(1.0f - runningTime, runningTime, 0.0f); } } else { runtimeParams.delay = clamp_tpl(runtimeParams.delay - frameTime, 0.0f, runtimeParams.delay); } return effectFF; }
Ang3 CCinematicInput::UpdateAdditiveCameraInputWithMouse( const SUpdateContext& updateCtx, const Ang3& rawMouseInput ) { #if CINEMATIC_INPUT_PC_MOUSE Ang3 rawMouseInputModified = rawMouseInput * updateCtx.m_frameTime * updateCtx.m_frameTime; rawMouseInputModified.z = -rawMouseInputModified.z; rawMouseInputModified.x *= (g_pGameCVars->cl_invertMouse == 0) ? 1.0f : -1.0f; m_mouseAccumulatedInput += rawMouseInputModified; m_mouseAccumulatedInput.x = clamp_tpl(m_mouseAccumulatedInput.x, -1.0f, 1.0f); m_mouseAccumulatedInput.z = clamp_tpl(m_mouseAccumulatedInput.z, -1.0f, 1.0f); m_mouseAccumulatedInput.y = 0.0f; //Yaw angle (Z axis) m_mouseAccumulatedAngles.z = -(float)fsel(m_mouseAccumulatedInput.z, m_mouseAccumulatedInput.z * updateCtx.m_lookRightLimit, m_mouseAccumulatedInput.z * updateCtx.m_lookLeftLimit); //Pitch angle (X axis) m_mouseAccumulatedAngles.x = (float)fsel(m_mouseAccumulatedInput.x, m_mouseAccumulatedInput.x * updateCtx.m_lookUpLimit, m_mouseAccumulatedInput.x * updateCtx.m_lookDownLimit); // Recenter after a certain amount of time without input if (updateCtx.m_recenter) { const float rawInputLen = fabs(rawMouseInputModified.x) + fabs(rawMouseInputModified.z); const float newRecenterTimeOut = (float)fsel(-rawInputLen, m_mouseRecenterTimeOut - updateCtx.m_frameTime, CINEMATIC_INPUT_MOUSE_RECENTER_TIMEOUT); if (newRecenterTimeOut < 0.0f) { Interpolate(m_mouseAccumulatedInput, Ang3(0.0f, 0.0f, 0.0f), 1.5f, updateCtx.m_frameTime); } m_mouseRecenterTimeOut = max(newRecenterTimeOut, 0.0f); } return m_mouseAccumulatedAngles; #else return Ang3(0.0f, 0.0f, 0.0f); #endif }
float SearchGroup::CalculateScore(SearchSpot& searchSpot, EntityId entityID, SearchSpotQuery* query, Vec3& targetCurrentPos) const { assert(query); Agent agent(entityID); if (agent.IsValid()) { const Vec3 spotPosition = searchSpot.GetPos(); const Vec3 agentPosition = agent.GetPos(); const float agentToSpotDistance = agentPosition.GetDistance(spotPosition); if (agentToSpotDistance < query->minDistanceFromAgent) { return -100.0f; } float closenessToAgentScore = 0.0f; closenessToAgentScore = 1.0f - clamp_tpl(agentToSpotDistance, 1.0f, 50.0f) / 50.0f; const float closenessToTargetScore = 1.0f - clamp_tpl(spotPosition.GetDistance(m_targetPos), 1.0f, 50.0f) / 50.0f; float closenessToTargetCurrentPosScore = 0.0f; if (!targetCurrentPos.IsZeroFast()) { closenessToTargetCurrentPosScore = 1.0f - clamp_tpl(spotPosition.GetDistance(targetCurrentPos), 1.0f, 50.0f) / 50.0f; } return closenessToAgentScore * query->closenessToAgentWeight + closenessToTargetScore * query->closenessToTargetWeight + closenessToTargetCurrentPosScore * query->closenessToTargetCurrentPosWeight; } else { return -100.0f; } }
void CFlashUIMCVisibleBaseNode::ProcessEvent( EFlowEvent event,SActivationInfo* pActInfo ) { if (event == eFE_Initialize) { UpdateObjectDesc( GetPortString( pActInfo, GetInputPort(eI_UIMovieClip)), pActInfo, m_isTemplate ); } else if (event == eFE_Activate) { if (IsPortActive( pActInfo, GetInputPort(eI_UIMovieClip))) { UpdateObjectDesc( GetPortString( pActInfo, GetInputPort(eI_UIMovieClip)), pActInfo, m_isTemplate ); } if (IsTemplate() && !UpdateTmplDesc( GetPortString( pActInfo, GetInputPort(eI_TemplateInstanceName)), pActInfo )) return; if (GetElement()) { const int instanceId = GetPortInt( pActInfo, GetInputPort(eI_InstanceID)); if (IsPortActive ( pActInfo, GetInputPort(eI_Set))) { const bool bVis = GetPortBool( pActInfo, GetInputPort(eI_Visible)); const float alpha = clamp_tpl( GetPortFloat( pActInfo, GetInputPort(eI_Alpha)), 0.0f, 1.f ); SPerInstanceCall2< bool, float > caller; caller.Execute( GetElement(), instanceId, functor(*this, &CFlashUIMCVisibleBaseNode::SetValues), bVis, alpha ); ActivateOutput( pActInfo, eO_OnSet, true ); ActivateOutput( pActInfo, eO_Visible, bVis ); ActivateOutput( pActInfo, eO_Alpha, alpha ); } else if (IsPortActive( pActInfo, GetInputPort(eI_Get))) { bool bVis = false; float alpha = 0.f; SPerInstanceCall2< bool &, float & > caller; if (!caller.Execute( GetElement(), instanceId, functor(*this, &CFlashUIMCVisibleBaseNode::GetValues), bVis, alpha, false )) { UIACTION_WARNING( "FG: UIElement \"%s\" called get Array for multiple instances! (passed instanceId %i), referenced at node \"%s\"", GetElement()->GetName(),instanceId, pActInfo->pGraph->GetNodeTypeName( pActInfo->myID )); } ActivateOutput( pActInfo, eO_Visible, bVis ); ActivateOutput( pActInfo, eO_Alpha, alpha ); } } } }
void CFirstPersonCameraComponent::Update() { auto pPlayer = CPlayerComponent::GetLocalPlayer(); auto pPlayerInput = pPlayer->GetPlayerInput(); // Default on failure is to return a cleanly constructed default matrix. Matrix34 newCameraMatrix = Matrix34::Create(Vec3(1.0f), IDENTITY, ZERO); if (pPlayerInput) { // Resolve the entity. if (auto pEntity = gEnv->pEntitySystem->GetEntity(m_targetEntityID)) { // It's possible there is no actor to query for eye position, in that case, return a safe default // value for an average height person. Vec3 localEyePosition { AverageEyePosition }; // If we are attached to an entity that is an actor we can use their eye position. auto pActor = CActorComponent::GetActor(m_targetEntityID); if (pActor) localEyePosition = pActor->GetLocalEyePos(); // Apply the player input rotation for this frame, and limit the pitch / yaw movement according to the set max and min values. if (pPlayer->GetinteractionState().IsCameraMovementAllowed()) { m_viewPitch -= pPlayerInput->GetMousePitchDelta() - pPlayerInput->GetXiPitchDelta(); m_viewPitch = clamp_tpl(m_viewPitch, DEG2RAD(g_cvars.m_firstPersonCameraPitchMin), DEG2RAD(g_cvars.m_firstPersonCameraPitchMax)); } // Pose is based on entity position and the eye position. // We will use the rotation of the entity as a base, and apply pitch based on our own reckoning. const Vec3 position = pEntity->GetPos() + localEyePosition; const Quat rotation = pEntity->GetRotation() * Quat(Ang3(m_viewPitch, 0.0f, 0.0f)); newCameraMatrix = Matrix34::Create(Vec3(1.0f), rotation, position + rotation * m_pCameraManager->GetViewOffset()); #if defined(_DEBUG) if (g_cvars.m_firstPersonCameraDebug) { gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(position, 0.04f, ColorB(0, 0, 255, 255)); } #endif } } // Store the new matrix for later. m_cameraMatrix = newCameraMatrix; }
void CPlayerStateSwim_WaterTestProxy::Update(const CPlayer& player, const float frameTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); if( gEnv->IsEditor() && !gEnv->IsEditorGameMode() ) { m_lastInternalState = m_internalState; m_internalState = eProxyInternalState_OutOfWater; m_shouldSwim = false; } float newSwimmingTimer = 0.0f; switch(m_internalState) { case eProxyInternalState_OutOfWater: { if (m_lastInternalState != eProxyInternalState_OutOfWater) { Reset(true); } UpdateOutOfWater(player, frameTime); newSwimmingTimer = m_swimmingTimer - frameTime; } break; case eProxyInternalState_PartiallySubmerged: { UpdateInWater(player, frameTime); newSwimmingTimer = m_swimmingTimer - frameTime; } break; case eProxyInternalState_Swimming: { UpdateInWater(player, frameTime); newSwimmingTimer = m_swimmingTimer + frameTime; } break; } m_swimmingTimer = clamp_tpl(newSwimmingTimer, -1000.0f, 1000.0f); }
void CPlayerRotation::ProcessFinalViewEffects( float minAngle, float maxAngle ) { if (!m_player.IsClient()) { m_viewQuatFinal = m_viewQuat; } else { Ang3 viewAngleOffset = m_frameViewAnglesOffset; float currentViewPitch = GetLocalPitch(); float newPitch = clamp_tpl(currentViewPitch + viewAngleOffset.x, minAngle, maxAngle); viewAngleOffset.x = newPitch - currentViewPitch; m_viewQuatFinal = m_viewQuat * Quat::CreateRotationXYZ(viewAngleOffset); } }
const Vec3 CPlayerStateJump::CalculateInAirJumpExtraVelocity( const CPlayer& player, const Vec3& desiredVelocity ) const { const SPlayerStats& stats = player.m_stats; const float speedUpFactor = 0.175f; Vec3 jumpExtraVelocity(0.0f, 0.0f, 0.0f); const SActorPhysics& actorPhysics = player.GetActorPhysics(); if (actorPhysics.velocity.z > 0.0f) { //Note: Desired velocity is flat (not 'z' component), so jumpHeight should not be altered jumpExtraVelocity = desiredVelocity * speedUpFactor; } else { //Note: this makes the jump feel less 'floaty', by accelerating the player slightly down // and compensates the extra traveled distance when going up const float g = actorPhysics.gravity.len(); if (g > 0.0f) { const float jumpHeightScale = 1.0f; const float jumpHeight = player.m_params.jumpHeight * jumpHeightScale; const float estimatedLandTime = sqrt_tpl(2.0f*jumpHeight*(1.0f/g)) * (1.0f - speedUpFactor); assert(estimatedLandTime > 0.0f); if (estimatedLandTime > 0.0f) { const float requiredGravity = (2.0f*jumpHeight)/(estimatedLandTime * estimatedLandTime); const float initialAccelerationScale = clamp_tpl((-actorPhysics.velocity.z * 0.6f), 0.0f, 1.0f); jumpExtraVelocity = (requiredGravity - g) * actorPhysics.gravity.GetNormalized() * initialAccelerationScale; } } } return jumpExtraVelocity; }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementTank::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER( gEnv->pSystem, PROFILE_GAME ); m_netActionSync.UpdateObject(this); CryAutoCriticalSection lk(m_lock); CVehicleMovementBase::ProcessMovement(deltaTime); if (!(m_actorId && m_isEnginePowered)) { IPhysicalEntity* pPhysics = GetPhysics(); if (m_latFriction != 1.3f) SetLatFriction(1.3f); if (m_axleFriction != m_axleFrictionMax) UpdateAxleFriction(0.f, false, deltaTime); m_action.bHandBrake = 1; m_action.pedal = 0; m_action.steer = 0; pPhysics->Action(&m_action, 1); return; } IPhysicalEntity* pPhysics = GetPhysics(); MARK_UNUSED m_action.clutch; Matrix34 worldTM( m_PhysPos.q ); worldTM.AddTranslation( m_PhysPos.pos ); const Matrix34 invWTM = worldTM.GetInvertedFast(); Vec3 localVel = invWTM.TransformVector(m_PhysDyn.v); Vec3 localW = invWTM.TransformVector(m_PhysDyn.w); float speed = m_PhysDyn.v.len(); float speedRatio = min(1.f, speed/m_maxSpeed); float actionPedal = abs(m_movementAction.power) > 0.001f ? m_movementAction.power : 0.f; // tank specific: // avoid steering input around 0.5 (ask Anton) float actionSteer = m_movementAction.rotateYaw; float absSteer = abs(actionSteer); float steerSpeed = (absSteer < 0.01f && abs(m_currSteer) > 0.01f) ? m_steerSpeedRelax : m_steerSpeed; if (steerSpeed == 0.f) { m_currSteer = (float)sgn(actionSteer); } else { if (m_movementAction.isAI) { m_currSteer = actionSteer; } else { m_currSteer += min(abs(actionSteer-m_currSteer), deltaTime*steerSpeed) * sgn(actionSteer-m_currSteer); } } Limit(m_currSteer, -m_steerLimit, m_steerLimit); if (abs(m_currSteer) > 0.0001f) { // if steering, apply full throttle to have enough turn power actionPedal = (float)sgn(actionPedal); if (actionPedal == 0.f) { // allow steering-on-teh-spot only above maxReverseSpeed (to avoid sudden reverse of controls) const float maxReverseSpeed = -1.5f; actionPedal = max(0.f, min(1.f, 1.f-(localVel.y/maxReverseSpeed))); // todo float steerLim = 0.8f; Limit(m_currSteer, -steerLim*m_steerLimit, steerLim*m_steerLimit); } } if (!pPhysics->GetStatus(&m_vehicleStatus)) return; int currGear = m_vehicleStatus.iCurGear - 1; // indexing for convenience: -1,0,1,2,.. UpdateAxleFriction(m_movementAction.power, true, deltaTime); UpdateSuspension(deltaTime); float absPedal = abs(actionPedal); // pedal ramping if (m_pedalSpeed == 0.f) m_currPedal = actionPedal; else { m_currPedal += deltaTime * m_pedalSpeed * sgn(actionPedal - m_currPedal); m_currPedal = clamp_tpl(m_currPedal, -absPedal, absPedal); } // only apply pedal after threshold is exceeded if (currGear == 0 && fabs_tpl(m_currPedal) < m_pedalThreshold) m_action.pedal = 0; else m_action.pedal = m_currPedal; // change pedal amount based on damages float damageMul = 0.0f; { if (m_movementAction.isAI) { damageMul = 1.0f - 0.30f * m_damage; m_action.pedal *= damageMul; } else { // request from Sten: damage shouldn't affect reversing so much. float effectiveDamage = m_damage; if(m_action.pedal < -0.1f) effectiveDamage = 0.4f * m_damage; m_action.pedal *= GetWheelCondition(); damageMul = 1.0f - 0.7f*effectiveDamage; m_action.pedal *= damageMul; } } // reverse steering value for backward driving float effSteer = m_currSteer * sgn(actionPedal); // update lateral friction float latSlipMinGoal = 0.f; float latFricMinGoal = m_latFricMin; if (abs(effSteer) > 0.01f && !m_movementAction.brake) { latSlipMinGoal = m_latSlipMin; // use steering friction, but not when countersteering if (sgn(effSteer) != sgn(localW.z)) latFricMinGoal = m_latFricMinSteer; } Interpolate(m_currentSlipMin, latSlipMinGoal, 3.f, deltaTime); if (latFricMinGoal < m_currentFricMin) m_currentFricMin = latFricMinGoal; else Interpolate(m_currentFricMin, latFricMinGoal, 3.f, deltaTime); float fractionSpeed = min(1.f, max(0.f, m_avgLateralSlip-m_currentSlipMin) / (m_latSlipMax-m_currentSlipMin)); float latFric = fractionSpeed * (m_latFricMax-m_currentFricMin) + m_currentFricMin; if ( m_movementAction.brake && m_movementAction.isAI ) { // it is natural for ai, apply differnt friction value while handbreaking latFric = m_latFricMax; } if (latFric != m_latFriction) { SetLatFriction(latFric); } const static float maxSteer = gf_PI/4.f; // fix maxsteer, shouldn't change m_action.steer = m_currSteer * maxSteer; if (m_steeringImpulseMin > 0.f && m_wheelContactsLeft != 0 && m_wheelContactsRight != 0) { const float maxW = 0.3f*gf_PI; float steer = abs(m_currSteer)>0.001f ? m_currSteer : 0.f; float desired = steer * maxW; float curr = -localW.z; float err = desired - curr; // err>0 means correction to right Limit(err, -maxW, maxW); if (abs(err) > 0.01f) { float amount = m_steeringImpulseMin + speedRatio*(m_steeringImpulseMax-m_steeringImpulseMin); // bigger correction for relaxing if (desired == 0.f || (desired*curr>0 && abs(desired)<abs(curr))) amount = m_steeringImpulseRelaxMin + speedRatio*(m_steeringImpulseRelaxMax-m_steeringImpulseRelaxMin); float corr = -err * amount * m_PhysDyn.mass * deltaTime; pe_action_impulse imp; imp.iApplyTime = 0; imp.angImpulse = worldTM.GetColumn2() * corr; pPhysics->Action(&imp, THREAD_SAFE); } } m_action.bHandBrake = (m_movementAction.brake) ? 1 : 0; if (currGear > 0 && m_vehicleStatus.iCurGear < m_currentGear) { // when shifted down, disengage clutch immediately to avoid power/speed dropdown m_action.clutch = 1.f; } pPhysics->Action(&m_action, 1); if (Boosting()) ApplyBoost(speed, 1.2f*m_maxSpeed*GetWheelCondition()*damageMul, m_boostStrength, deltaTime); if (m_wheelContacts <= 1 && speed > 5.f) { ApplyAirDamp(DEG2RAD(20.f), DEG2RAD(10.f), deltaTime, THREAD_SAFE); UpdateGravity(-9.81f * 1.4f); } if (m_netActionSync.PublishActions( CNetworkMovementStdWheeled(this) )) CHANGED_NETWORK_STATE(m_pVehicle, eEA_GameClientDynamic ); }
//------------------------------------------------------------------------ bool CVehicleViewSteer::Init(IVehicleSeat* pSeat, const CVehicleParams &table) { if (!CVehicleViewBase::Init(pSeat, table)) return false; m_pAimPart = pSeat->GetAimPart(); CVehicleParams params = table.findChild(m_name); if (!params) return false; CVehicleParams posParams = params.findChild("Pos"); CVehicleParams rotationParams = params.findChild("Rotation"); CVehicleParams motionParams = params.findChild("Motion"); CVehicleParams backwardsParams = params.findChild("Backwards"); CVehicleParams radiusParams = params.findChild("Radius"); if (posParams) { posParams.getAttr("offset", m_localSpaceCameraOffset); posParams.getAttr("aim", m_lookAt0); posParams.getAttr("pivotOffset", m_pivotOffset); } if (rotationParams) { rotationParams.getAttr("rotationMax", m_maxRotation); if (rotationParams.haveAttr("rotationMax2")) { rotationParams.getAttr("rotationMax2", m_maxRotation2); } else { m_maxRotation2 = m_maxRotation / 3.0f; } m_maxRotation = DEG2RAD(m_maxRotation); m_maxRotation2 = DEG2RAD(m_maxRotation2); rotationParams.getAttr("stickSensitivity", m_stickSensitivity); rotationParams.getAttr("stickSensitivity2", m_stickSensitivity2); rotationParams.getAttr("inheritedElev", m_inheritedElev); getFlag(rotationParams, "canRotate", m_flags, eVCam_canRotate); m_inheritedElev = clamp_tpl(m_inheritedElev, 0.f, 1.f); } if (motionParams) { motionParams.getAttr("returnSpeed", m_angReturnSpeed1); motionParams.getAttr("returnSpeed2", m_angReturnSpeed2); motionParams.getAttr("angFollow", m_angSpeedCorrection0); } if (backwardsParams) { getFlag(backwardsParams, "clamp", m_backwardsFlags, eVCam_rotationClamp); getFlag(backwardsParams, "returnSpring", m_backwardsFlags, eVCam_rotationSpring); } if (radiusParams) { radiusParams.getAttr("min", m_radiusMin); radiusParams.getAttr("max", m_radiusMax); radiusParams.getAttr("relaxRate", m_radiusRelaxRate); radiusParams.getAttr("dampRate", m_radiusDampRate); radiusParams.getAttr("velInfluence", m_radiusVelInfluence); } Reset(); return true; }
//------------------------------------------------------------------------ void CVehicleViewSteer::Update(float dt) { IEntity* pEntity = m_pVehicle->GetEntity(); assert(pEntity); IVehicleMovement* pVehicleMovement = m_pVehicle->GetMovement(); if (pVehicleMovement == NULL) return; IPhysicalEntity* pPhysEntity = pEntity->GetPhysics(); if (!pPhysEntity) return; pe_status_dynamics dynStatus; pPhysEntity->GetStatus(&dynStatus); SMovementState movementState; pVehicleMovement->GetMovementState(movementState); const float pedal = pVehicleMovement->GetEnginePedal(); const float maxSpeed = movementState.maxSpeed; const Matrix34 &pose = m_pAimPart ? m_pAimPart->GetWorldTM() : pEntity->GetWorldTM(); const Vec3 entityPos = pose.GetColumn3(); const Vec3 xAxis = pose.GetColumn0(); const Vec3 yAxis = pose.GetColumn1(); const Vec3 zAxis = pose.GetColumn2(); const float forwardSpeed = dynStatus.v.dot(yAxis); const float speedNorm = clamp_tpl(forwardSpeed / maxSpeed, 0.0f, 1.0f); const Vec3 maxRotation = m_maxRotation + speedNorm * (m_maxRotation2 - m_maxRotation); CalcLookAt(pose); if (m_lookAt.IsValid()) { if (!m_lastOffset.IsValid()) { m_position = pose * m_localSpaceCameraOffset; m_lastOffset = m_position - m_lookAt; m_lastOffsetBeforeElev = m_lastOffset; } Vec3 offset = m_lastOffsetBeforeElev; if (pedal < 0.1f && forwardSpeed < 1.0f) { // Going Backwards m_flags &= ~(eVCam_goingForwards | m_forwardFlags); m_flags |= m_backwardsFlags; } if (offset.dot(yAxis) < 0.8f && forwardSpeed > 1.f) { // Going Forwards m_flags &= ~m_backwardsFlags; m_flags |= eVCam_goingForwards | m_forwardFlags; } float sensitivity = (1.f - speedNorm) * m_stickSensitivity.z + speedNorm * m_stickSensitivity2.z; float rotate = -m_rotatingAction.z * sensitivity; rotate = rotate * dt; if (zAxis.z > 0.1f) { // Safe to update curYaw Vec3 projectedX = xAxis; projectedX.z = 0.f; Vec3 projectedY = yAxis; projectedY.z = 0.f; const float newYaw = atan2_tpl(offset.dot(projectedX), -(offset.dot(projectedY))); const float maxChange = DEG2RAD(270.f) * dt; const float delta = clamp_tpl(newYaw - m_curYaw, -maxChange, +maxChange); m_curYaw += delta; } // Rotation Action { if (m_flags & eVCam_rotationClamp) { float newYaw = clamp_tpl(m_curYaw + rotate, -maxRotation.z, +maxRotation.z); rotate = newYaw - m_curYaw; rotate = clamp_tpl(newYaw - m_curYaw, -fabsf(rotate), +fabsf(rotate)); m_rotation.z += rotate; } else { m_rotation.z = 0.f; } if (speedNorm > 0.1f) { float reduce = dt * 1.f; m_rotation.z = m_rotation.z - reduce * m_rotation.z / (fabsf(m_rotation.z) + reduce); } } // Ang Spring { float angSpeedCorrection = dt * dt * m_angSpeedCorrection / (dt * m_angSpeedCorrection + 1.f) * dynStatus.w.z; if ((m_flags & eVCam_rotationSpring) == 0) { m_angReturnSpeed = 0.f; angSpeedCorrection = 0.f; } float difference = m_rotation.z - m_curYaw; float relax = difference * (m_angReturnSpeed * dt) / ((m_angReturnSpeed * dt) + 1.f); const float delta = +relax + angSpeedCorrection + rotate; m_curYaw += delta; Matrix33 rot = Matrix33::CreateRotationZ(delta); offset = rot * offset; // Lerp the spring speed float angSpeedTarget = m_angReturnSpeed1 + speedNorm * (m_angReturnSpeed2 - m_angReturnSpeed1); m_angReturnSpeed += (angSpeedTarget - m_angReturnSpeed) * (dt / (dt + 0.3f)); m_angSpeedCorrection += (m_angSpeedCorrection0 - m_angSpeedCorrection) * (dt / (dt + 0.3f)); } if (!offset.IsValid()) offset = m_lastOffset; // Velocity influence Vec3 displacement = -((2.f - speedNorm) * dt) * dynStatus.v;// - yAxis*(0.0f*speedNorm*(yAxis.dot(dynStatus.v)))); float dot = offset.dot(displacement); if (dot < 0.f) { displacement = displacement + offset * -0.1f * (offset.dot(displacement) / offset.GetLengthSquared()); } offset = offset + displacement; const float radius0 = fabsf(m_localSpaceCameraOffset.y); const float minRadius = radius0 * m_radiusMin; const float maxRadius = radius0 * m_radiusMax; float radiusXY = sqrtf(sqr(offset.x) + sqr(offset.y)); Vec3 offsetXY = offset; offsetXY.z = 0.f; Vec3 accelerationV = (dynStatus.v - m_lastVehVel); float acceleration = offsetXY.dot(accelerationV) / radiusXY; m_lastVehVel = dynStatus.v; m_radiusVel -= acceleration; m_radius += m_radiusVel * dt - dt * m_radiusVelInfluence * offsetXY.dot(dynStatus.v) / radiusXY; m_radiusVel *= expf(-dt * m_radiusDampRate); m_radius += (radius0 - m_radius) * (dt * m_radiusRelaxRate) / (dt * m_radiusRelaxRate + 1.f); m_radius = clamp_tpl(m_radius, minRadius, maxRadius); offset = offset * (m_radius / radiusXY); // Vertical motion float targetOffsetHeight = m_localSpaceCameraOffset.z * (m_radius / radius0); float oldOffsetHeight = offset.z; offset.z += (targetOffsetHeight - offset.z) * (dt / (dt + 0.3f)); Limit(offset.z, targetOffsetHeight - 2.f, targetOffsetHeight + 2.f); float verticalChange = offset.z - oldOffsetHeight; m_lastOffsetBeforeElev = offset; // Add up and down camera tilt { offset.z -= verticalChange; m_rotation.x += dt * m_stickSensitivity.x * m_rotatingAction.x; m_rotation.x = clamp_tpl(m_rotation.x, -maxRotation.x, +maxRotation.x); float elevAngleVehicle = m_inheritedElev * yAxis.z; // yAxis.z == approx elevation angle float elevationAngle = m_rotation.x - elevAngleVehicle; float sinElev, cosElev; sincos_tpl(elevationAngle, &sinElev, &cosElev); float horizLen = sqrtf(offset.GetLengthSquared2D()); float horizLenNew = horizLen * cosElev - sinElev * offset.z; if (horizLen > 1e-4f) { horizLenNew /= horizLen; offset.x *= horizLenNew; offset.y *= horizLenNew; offset.z = offset.z * cosElev + sinElev * horizLen; } offset.z += verticalChange; } if (!offset.IsValid()) offset = m_lastOffset; m_position = m_lookAt + offset; // Perform world intersection test. { // Initialise sphere and direction. primitives::sphere sphere; sphere.center = m_lookAt; sphere.r = g_SteerCameraRadius; Vec3 direction = m_position - m_lookAt; // Calculate camera bounds. AABB localBounds; m_pVehicle->GetEntity()->GetLocalBounds(localBounds); const float cameraBoundsScale = 0.75f; localBounds.min *= cameraBoundsScale; localBounds.max *= cameraBoundsScale; OBB cameraBounds; Matrix34 worldTM = m_pVehicle->GetEntity()->GetWorldTM(); cameraBounds.SetOBBfromAABB(Matrix33(worldTM), localBounds); // Try to find point on edge of camera bounds to begin swept sphere intersection test. Vec3 rayBoxIntersect; if (Intersect::Ray_OBB(Ray(m_position, -direction), worldTM.GetTranslation(), cameraBounds, rayBoxIntersect) > 0) { Vec3 temp = m_position - rayBoxIntersect; if (direction.Dot(temp) > 0.0f) { sphere.center = rayBoxIntersect; direction = temp; } } // Perform swept sphere intersection test against world. geom_contact* pContact = NULL; IPhysicalEntity* pSkipEntities[10]; float distance = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, direction, ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, (geom_colltype_player << rwi_colltype_bit) | rwi_stop_at_pierceable, 0, 0, 0, pSkipEntities, m_pVehicle->GetSkipEntities(pSkipEntities, 10)); if (distance > 0.0f) { // Sweep intersects world so calculate new offset. offset = (sphere.center + (direction.GetNormalizedSafe() * distance)) - m_lookAt; } } Interpolate(m_lastOffset, offset, 10.f, dt); m_position = m_lookAt + m_lastOffset; } else { CRY_ASSERT_MESSAGE(0, "camera will fail because lookat position is invalid"); } m_rotatingAction.zero(); }
//------------------------------------------------------------------------ bool CFireModePlugin_Overheat::Update(float frameTime, uint32 frameId) { CWeapon* pWeapon = m_pOwnerFiremode->GetWeapon(); CRY_ASSERT(pWeapon); CActor *pActor = pWeapon->GetOwnerActor(); bool isOwnerAIControlled = pActor ? !pActor->IsPlayer() : false; if(isOwnerAIControlled) return false; float oldheat = m_heat; if (m_overheat > 0.0f) { m_overheat -= frameTime; if (m_overheat <= 0.0f) { m_overheat = 0.0f; FragmentID fragment = pWeapon->GetFragmentID(m_pParams->cooldown.c_str()); pWeapon->PlayAction(fragment); } } else { float add=0.0f; float sub=0.0f; if (m_firedThisFrame) { add = m_pParams->attack; if(pActor && pActor->GetLinkedVehicle()) { const static float k_VehicleCombatMode_ScaleOverheat = 0.5f; add = m_pParams->attack * k_VehicleCombatMode_ScaleOverheat; } } else if (m_pOwnerFiremode->GetNextShotTime()<=0.0001f && !m_pOwnerFiremode->IsFiring()) { sub=frameTime / m_pParams->decay; } m_heat = clamp_tpl(m_heat + (add-sub), 0.0f, 1.0f); if (m_heat >= 0.999f && oldheat<0.999f) { m_overheat = m_pParams->duration; m_isCoolingDown = true; m_pOwnerFiremode->StopFire(); FragmentID fragment = pWeapon->GetFragmentID(m_pParams->overheating.c_str()); pWeapon->PlayAction(fragment); int slot = pWeapon->GetStats().fp ? eIGS_FirstPerson : eIGS_ThirdPerson; if (!m_pParams->effect[slot].empty()) { if (m_heatEffectId) { pWeapon->DetachEffect(m_heatEffectId); m_heatEffectId = 0; } m_heatEffectId = pWeapon->AttachEffect(slot, false, m_pParams->effect[slot].c_str(), m_pParams->helper[slot].c_str()); } } else if(m_heat <= m_pParams->refire_heat) { m_isCoolingDown = false; } } m_firedThisFrame = false; return (m_heat > 0.0001f); }
//------------------------------------------------------------------------ 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); }
void CXInputDevice::SetDeadZone(float fThreshold) { m_fDeadZone = clamp_tpl(fThreshold, 0.001f, 1.0f) * INPUT_DEADZONE_MULTIPLIER; }
void CBoidBird::Think( float dt,SBoidContext &bc ) { m_accel.zero(); float factorAlignment = bc.factorAlignment; float factorCohesion = bc.factorCohesion; float factorSeparation = bc.factorSeparation; float factorAvoidLand = bc.factorAvoidLand; float factorAttractToOrigin = bc.factorAttractToOrigin; float factorKeepHeight = bc.factorKeepHeight; if(m_status == Bird::LANDING) { //factorAlignment /= 3.f; factorCohesion *=10.f; factorSeparation = 0; factorAvoidLand = 0; factorAttractToOrigin *=10; factorKeepHeight = 0; } if (m_spawnFromPt) { // Set the acceleration of the boid float fHalfDesired = m_desiredHeigh * .5f; if (m_pos.z < fHalfDesired) { m_accel.z = 3.f; } else { m_accel.z = .5f; // Set z-acceleration float fRange = 1.f - (m_pos.z-fHalfDesired)/fHalfDesired; // 1..0 range if (m_heading.z > 0.2f) m_accel.z = .5f + fRange; // 2..1 m_accel.x += m_heading.x * .1f; m_accel.y += m_heading.y * .1f; } if (m_pos.z > m_desiredHeigh) SetSpawnFromPt(false); // Limits birds to above water and land. if (m_pos.z < bc.terrainZ-0.2f) { m_pos.z = bc.terrainZ-0.2f; } if (m_pos.z < bc.waterLevel-0.2f) { m_pos.z = bc.waterLevel-0.2f; } return; } float height = m_pos.z - bc.flockPos.z; // Free will. // Continue accelerating in same dir until target speed reached. // Try to maintain average speed of (maxspeed+minspeed)/2 float targetSpeed = (bc.MaxSpeed + bc.MinSpeed)/2; m_accel -= m_heading*(m_speed-targetSpeed)*0.5f; // Desired height. float dh = m_desiredHeigh - m_pos.z; float dhexp = -(dh*dh)/(3*3); dhexp = clamp_tpl(dhexp,-70.0f,70.0f); // Max values for expf // Gaussian weight. float fKeepHeight = factorKeepHeight - m_fNoKeepHeight; m_fNoKeepHeight = max(0.f, m_fNoKeepHeight - .01f*dt); m_accel.z = exp_tpl(dhexp) * fKeepHeight; if (factorAlignment != 0) { //CalcCohesion(); Vec3 alignmentAccel; Vec3 cohesionAccel; Vec3 separationAccel; CalcFlockBehavior(bc,alignmentAccel,cohesionAccel,separationAccel); //! Adjust for allignment, //m_accel += alignmentAccel.Normalized()*ALIGNMENT_FACTOR; m_accel += alignmentAccel*factorAlignment; m_accel += cohesionAccel*factorCohesion; m_accel += separationAccel*factorSeparation; } // Avoid land. if (height < bc.MinHeight && m_status != Bird::LANDING) { float v = (1.0f - height/bc.MinHeight); m_accel += Vec3(0,0,v*v)*bc.factorAvoidLand; } else if (height > bc.MaxHeight) { // Avoid max height. float v = (height - bc.MaxHeight)*0.1f; m_accel += Vec3(0,0,-v); } else if(m_status != Bird::TAKEOFF) { // Always try to accelerate in direction opposite to current in Z axis. m_accel.z = -(m_heading.z*m_heading.z*m_heading.z * 100.0f); } // Attract to origin point. float fAttractToOrigin = factorAttractToOrigin - m_fNoCenterAttract; m_fNoCenterAttract = max(0.f, m_fNoCenterAttract - .01f*dt); if (bc.followPlayer) { m_accel += (bc.playerPos - m_pos) * fAttractToOrigin; } else { if ((rand()&31) == 1) { m_birdOriginPos = Vec3( bc.flockPos.x+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.y+Boid::Frand()*bc.fSpawnRadius,bc.flockPos.z+Boid::Frand()*bc.fSpawnRadius ); if (m_birdOriginPos.z - bc.terrainZ < bc.MinHeight) { m_birdOriginPos.z = bc.terrainZ + bc.MinHeight; } } m_accel += (m_birdOriginPos - m_pos) * fAttractToOrigin; } // Attract to bc.attractionPoint if (m_pos.GetSquaredDistance2D(bc.attractionPoint) < 5.f) { SetAttracted(false); CBirdsFlock *pFlock = (CBirdsFlock *)m_flock; if (!pFlock->GetAttractOutput()) { // Activate the AttractTo flownode output pFlock->SetAttractOutput(true); // Activate the flow node output IEntity *pFlockEntity = pFlock->GetEntity(); if (pFlockEntity) { IScriptTable *scriptObject = pFlockEntity->GetScriptTable(); if (scriptObject) Script::CallMethod(scriptObject, "OnAttractPointReached"); } } } if (m_attractedToPt) { if(m_status == Bird::ON_GROUND) TakeOff(bc); else SetStatus(Bird::FLYING); m_accel += (bc.attractionPoint - m_pos) * m_fAttractionFactor; if (m_fAttractionFactor < 300.f * factorAttractToOrigin) m_fAttractionFactor += 3.f*dt; } // Avoid collision with Terrain and Static objects. float fCollisionAvoidanceWeight = 1.0f; m_alignHorizontally = 0; if(m_status == Bird::TAKEOFF) { if(m_accel.z < 0) m_accel.z = -m_accel.z; m_accel.z *= bc.factorTakeOff; } if (bc.avoidObstacles) { // Avoid obstacles & terrain. float fCollDistance = m_collisionInfo.CheckDistance() ; if(m_collisionInfo.IsColliding()) { float w = (1.0f - m_collisionInfo.Distance()/fCollDistance); m_accel += m_collisionInfo.Normal() * w*w * bc.factorAvoidLand * fCollisionAvoidanceWeight; } } // Limits birds to above water and land. if (m_pos.z < bc.terrainZ-0.2f) { m_pos.z = bc.terrainZ-0.2f; } if (m_pos.z < bc.waterLevel-0.2f) { m_pos.z = bc.waterLevel-0.2f; } }
void CPlayerStateGround::OnPrePhysicsUpdate( CPlayer& player, const SActorFrameMovementParams &movement, float frameTime, const bool isHeavyWeapon, const bool isPlayer ) { const Matrix34A baseMtx = Matrix34A(player.GetBaseQuat()); Matrix34A baseMtxZ(baseMtx * Matrix33::CreateScale(Vec3Constants<float>::fVec3_OneZ)); baseMtxZ.SetTranslation(Vec3Constants<float>::fVec3_Zero); const CAutoAimManager& autoAimManager = g_pGame->GetAutoAimManager(); const EntityId closeCombatTargetId = autoAimManager.GetCloseCombatSnapTarget(); const IActor* pCloseCombatTarget = isPlayer && closeCombatTargetId && player.IsClient() ? g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(closeCombatTargetId) : NULL; if (pCloseCombatTarget) { ProcessAlignToTarget(autoAimManager, player, pCloseCombatTarget); } else { // This is to restore inertia if the ProcessAlignToTarget set it previously. if( m_inertiaIsZero ) { CPlayerStateUtil::RestorePlayerPhysics( player ); m_inertiaIsZero = false; } //process movement const bool isRemote = isPlayer && !player.IsClient(); Vec3 move(ZERO); CPlayerStateUtil::CalculateGroundOrJumpMovement( player, movement, isHeavyWeapon, move ); player.GetMoveRequest().type = eCMT_Normal; //apply movement Vec3 desiredVel(ZERO); Vec3 entityPos = player.GetEntity()->GetWorldPos(); Vec3 entityRight(player.GetBaseQuat().GetColumn0()); hwvec3 xmDesiredVel = HWV3Zero(); hwmtx33 xmBaseMtxZ; HWMtx33LoadAligned(xmBaseMtxZ, baseMtxZ); hwmtx33 xmBaseMtxZOpt = HWMtx33GetOptimized(xmBaseMtxZ); hwvec3 xmMove = HWVLoadVecUnaligned(&move); simdf fGroundNormalZ; #ifdef STATE_DEBUG bool debugJumping = (g_pGameCVars->pl_debug_jumping != 0); #endif const SPlayerStats& stats = *player.GetActorStats(); { xmDesiredVel = xmMove; Vec3 groundNormal = player.GetActorPhysics().groundNormal; if(!gEnv->bMultiplayer) { if (player.IsAIControlled()) fGroundNormalZ = SIMDFLoadFloat(square(groundNormal.z)); else fGroundNormalZ = SIMDFLoadFloat(groundNormal.z); } else { //If the hill steepness is greater than our minimum threshold if(groundNormal.z > 1.f - cosf(g_pGameCVars->pl_movement.mp_slope_speed_multiplier_minHill)) { //Check if we are trying to move up or downhill groundNormal.z = 0.f; groundNormal.Normalize(); Vec3 moveDir = move; moveDir.z = 0.f; moveDir.Normalize(); float normalDotMove = groundNormal.Dot(moveDir); //Apply speed multiplier based on moving up/down hill and hill steepness float multiplier = normalDotMove < 0.f ? g_pGameCVars->pl_movement.mp_slope_speed_multiplier_uphill : g_pGameCVars->pl_movement.mp_slope_speed_multiplier_downhill; fGroundNormalZ = SIMDFLoadFloat(1.f - (1.f - player.GetActorPhysics().groundNormal.z) * multiplier); } else { fGroundNormalZ = SIMDFLoadFloat(1.0f); } } const float depthHi = g_pGameCVars->cl_shallowWaterDepthHi; const float depthLo = g_pGameCVars->cl_shallowWaterDepthLo; const float relativeBottomDepth = player.m_playerStateSwim_WaterTestProxy.GetRelativeBottomDepth(); if( relativeBottomDepth > depthLo ) { // Shallow water speed slowdown float shallowWaterMultiplier = 1.0f; shallowWaterMultiplier = isPlayer ? g_pGameCVars->cl_shallowWaterSpeedMulPlayer : g_pGameCVars->cl_shallowWaterSpeedMulAI; shallowWaterMultiplier = max(shallowWaterMultiplier, 0.1f); assert(shallowWaterMultiplier <= 1.0f); float shallowWaterDepthSpan = (depthHi - depthLo); shallowWaterDepthSpan = max(0.1f, shallowWaterDepthSpan); float slowdownFraction = (relativeBottomDepth - depthLo) / shallowWaterDepthSpan; slowdownFraction = clamp_tpl(slowdownFraction, 0.0f, 1.0f); shallowWaterMultiplier = LERP(1.0f, shallowWaterMultiplier, slowdownFraction); //avoid branch if m_stats.relativeBottomDepth <= 0.0f; shallowWaterMultiplier = (float)__fsel(-relativeBottomDepth, 1.0f, shallowWaterMultiplier); simdf vfShallowWaterMultiplier = SIMDFLoadFloat(shallowWaterMultiplier); xmDesiredVel = HWVMultiplySIMDF(xmDesiredVel, vfShallowWaterMultiplier); } } // Slow down on sloped terrain, simply proportional to the slope. xmDesiredVel = HWVMultiplySIMDF(xmDesiredVel, fGroundNormalZ); //be sure desired velocity is flat to the ground hwvec3 vDesiredVelVert = HWMtx33RotateVecOpt(xmBaseMtxZOpt, xmDesiredVel); xmDesiredVel = HWVSub(xmDesiredVel, vDesiredVelVert); HWVSaveVecUnaligned(&desiredVel, xmDesiredVel); if (isPlayer) { Vec3 modifiedSlopeNormal = player.GetActorPhysics().groundNormal; float h = Vec2(modifiedSlopeNormal.x, modifiedSlopeNormal.y).GetLength(); // TODO: OPT: sqrt(x*x+y*y) float v = modifiedSlopeNormal.z; float slopeAngleCur = RAD2DEG(atan2_tpl(h, v)); const float divisorH = (float)__fsel(-h, 1.0f, h); const float divisorV = (float)__fsel(-v, 1.0f, v); const float invV = __fres(divisorV); const float invH = __fres(divisorH); const float slopeAngleHor = 10.0f; const float slopeAngleVer = 50.0f; float slopeAngleFraction = clamp_tpl((slopeAngleCur - slopeAngleHor) * __fres(slopeAngleVer - slopeAngleHor), 0.0f, 1.0f); slopeAngleFraction = slopeAngleFraction * slopeAngleFraction * slopeAngleFraction; float slopeAngleMod = LERP(0.0f, 90.0f, slopeAngleFraction); float s, c; sincos_tpl(DEG2RAD(slopeAngleMod), &s, &c); const float hMultiplier = (float)__fsel(-h, 1.0f, s * invH); const float vMultiplier = (float)__fsel(-v, 1.0f, c * invV); modifiedSlopeNormal.x *= hMultiplier; modifiedSlopeNormal.y *= hMultiplier; modifiedSlopeNormal.z *= vMultiplier; //Normalize the slope normal if possible const float fSlopeNormalLength = modifiedSlopeNormal.len(); const float fSlopeNormalLengthSafe = (float)__fsel(fSlopeNormalLength - 0.000001f, fSlopeNormalLength, 1.0f); modifiedSlopeNormal = modifiedSlopeNormal * __fres(fSlopeNormalLengthSafe); float alignment = min(modifiedSlopeNormal * desiredVel, 0.0f); // Also affect air control (but not as much), to prevent jumping up against steep slopes. alignment *= (float)__fsel(-fabsf(stats.onGround), LERP(0.7f, 1.0f, 1.0f - clamp_tpl(modifiedSlopeNormal.z * 100.0f, 0.0f, 1.0f)), 1.0f); modifiedSlopeNormal.z = modifiedSlopeNormal.z; desiredVel -= modifiedSlopeNormal * alignment; #ifdef STATE_DEBUG if (debugJumping) { player.DebugGraph_AddValue("GroundSlope", slopeAngleCur); player.DebugGraph_AddValue("GroundSlopeMod", slopeAngleMod); } #endif } Vec3 newVelocity = desiredVel; const float fNewSpeed = newVelocity.len(); const float fVelocityMultiplier = (float)__fsel(fNewSpeed - 22.0f, __fres(fNewSpeed+FLT_EPSILON) * 22.0f, 1.0f); // TODO: Maybe we should tell physics about this new velocity ? Or maybe SPlayerStats::velocity ? (stephenn). player.GetMoveRequest().velocity = newVelocity * (stats.flashBangStunMult * fVelocityMultiplier); #ifdef STATE_DEBUG if(g_pGameCVars->pl_debug_movement > 0) { const char* filter = g_pGameCVars->pl_debug_filter->GetString(); const char* name = player.GetEntity()->GetName(); if ((strcmp(filter, "0") == 0) || (strcmp(filter, name) == 0)) { float white[] = {1.0f,1.0f,1.0f,1.0f}; gEnv->pRenderer->Draw2dLabel(20, 450, 2.0f, white, false, "Speed: %.3f m/s", player.GetMoveRequest().velocity.len()); if(g_pGameCVars->pl_debug_movement > 1) { gEnv->pRenderer->Draw2dLabel(35, 470, 1.8f, white, false, "Stance Speed: %.3f m/s - (%sSprinting)", player.GetStanceMaxSpeed(player.GetStance()), player.IsSprinting() ? "" : "Not "); } } } #endif } if( isPlayer ) { CheckForVaultTrigger(player, frameTime); } }
bool CDialogActorContext::DoLocalPlayerChecks(const float dt) { // don't check this every frame, but only every .2 secs m_checkPlayerTimeOut-=dt; if (m_checkPlayerTimeOut <= 0.0f) { do // a dummy loop to use break { float awareDistance; float awareDistanceSq; float awareAngle; m_pSession->GetPlayerAwarenessValues(awareDistance, awareAngle); awareDistanceSq=awareDistance*awareDistance; m_checkPlayerTimeOut = PLAYER_CHECKTIME; const float spotAngleCos = cos_tpl(DEG2RAD(awareAngle)); const CDialogSession::TActorContextMap& contextMap = m_pSession->GetAllContexts(); if (contextMap.size() == 1 && contextMap.begin()->first == m_actorID) { m_bIsAware = true; break; } // early out, when we don't have to do any checks if (awareDistance <= 0.0f && awareAngle <= 0.0f) { m_bIsAware = true; break; } IEntity* pThisEntity = m_pSession->GetActorEntity(m_actorID); if (!pThisEntity) { assert (false); m_bIsAware = true; break; } IMovementController* pMC = (m_pIActor != NULL) ? m_pIActor->GetMovementController() : NULL; if (!pMC) { assert (false); m_bIsAware = true; break; } SMovementState moveState; pMC->GetMovementState(moveState); Vec3 viewPos = moveState.eyePosition; Vec3 viewDir = moveState.eyeDirection; viewDir.z = 0.0f; viewDir.NormalizeSafe(); // check the player's position // check the player's view direction AABB groupBounds; groupBounds.Reset(); CDialogSession::TActorContextMap::const_iterator iter = contextMap.begin(); CDialogScript::SActorSet lookingAt = 0; while (iter != contextMap.end()) { if (iter->first != m_actorID) { IEntity* pActorEntity = m_pSession->GetActorEntity(iter->first); if (pActorEntity) { Vec3 vEntityPos = pActorEntity->GetWorldPos(); AABB worldBounds; pActorEntity->GetWorldBounds(worldBounds); groupBounds.Add(worldBounds); // calc if we look at it somehow Vec3 vEntityDir = vEntityPos - viewPos; vEntityDir.z = 0.0f; vEntityDir.NormalizeSafe(); if (viewDir.IsUnit() && vEntityDir.IsUnit()) { const float dot = clamp_tpl(viewDir.Dot(vEntityDir),-1.0f,+1.0f); // clamping should not be needed if (spotAngleCos <= dot) lookingAt.SetActor(iter->first); DiaLOG::Log(DiaLOG::eDebugC, "Angle to actor %d is %f deg", iter->first, RAD2DEG(acos_tpl(dot))); } } } ++iter; } const float distanceSq = pThisEntity->GetWorldPos().GetSquaredDistance(groupBounds.GetCenter()); CCamera& camera=gEnv->pSystem->GetViewCamera(); const bool bIsInAABB = camera.IsAABBVisible_F(groupBounds); const bool bIsInRange = distanceSq <= awareDistanceSq; const bool bIsLooking = contextMap.empty() || lookingAt.NumActors() > 0; m_bIsAwareLooking = awareAngle <= 0.0f || (bIsInAABB || bIsLooking); m_bIsAwareInRange = awareDistance <= 0.0f || bIsInRange; m_bIsAware = m_bIsAwareLooking && m_bIsAwareInRange; DiaLOG::Log(DiaLOG::eDebugB, "[DIALOG] LPC: %s awDist=%f awAng=%f AABBVis=%d IsLooking=%d InRange=%d [Distance=%f LookingActors=%d] Final=%saware", m_pSession->GetDebugName(), awareDistance, awareAngle, bIsInAABB, bIsLooking, bIsInRange, sqrt_tpl(distanceSq), lookingAt.NumActors(), m_bIsAware ? "" : "not "); } while (false); } if (m_bIsAware) { m_playerAwareTimeOut = m_pSession->GetPlayerAwarenessGraceTime(); } else { m_playerAwareTimeOut-= dt; if (m_playerAwareTimeOut <= 0) { return false; } } return true; }