void CStickyProjectile::CalculateLocationForStick( const IEntity& projectile, const Vec3& collPos, const Vec3& collNormal, QuatT& outLocation ) const { if(m_flags&eSF_OrientateToCollNormal) { const float bigz = cry_fabsf(collNormal.z)-cry_fabsf(collNormal.y); const Vec3 temp(0.f,(float)__fsel(bigz,1.f,0.f),(float)__fsel(bigz,0.f,1.f)); outLocation.q = Quat(Matrix33::CreateOrientation( temp.Cross(collNormal), -collNormal, 0)); AABB aabb; projectile.GetLocalBounds(aabb); outLocation.t = collPos + (outLocation.q.GetColumn2() * ((aabb.max.y-aabb.min.y)*0.5f)); } else { outLocation.q = projectile.GetRotation(); outLocation.t = collPos + (outLocation.q.GetColumn1() * 0.1f); } }
void CNetPlayerInput::UpdateErrorSnap(const Vec3 &entPos, const Vec3 &desiredPos, f32 netPosDist, const Vec3 &desPosOffset, const CTimeValue &curTime) { if (g_pGameCVars->pl_velocityInterpAlwaysSnap) { //--- Snap to target m_pPlayer->GetEntity()->SetPos(desiredPos); m_passedNetPos = true; m_passedPredictionPos = true; } else if (curTime > m_nextBCTime && !(m_pPlayer->m_stats.inFreefall.Value() > 0)) { //--- Breadcrumbs dropped for simulated annealing, whilst the player is blocked we reduce the maximum //--- allowed offset until the character is snapped to the last net position Vec3 prevOffset = entPos - m_breadCrumb; bool blocked = false; if (!m_passedNetPos) { float moveDist = prevOffset.Dot(desPosOffset) / netPosDist; float moveSpeed = moveDist / k_timePerBC; blocked = ((moveSpeed / m_netLerpSpeed) <= k_BCMovingRatio); } if (blocked) { m_blockedTime += k_timePerBC; } else { m_blockedTime = 0.0f; } m_breadCrumb = entPos; m_nextBCTime = curTime+k_timePerBC; Vec3 v0(desiredPos.x, desiredPos.y, 0.0f); Vec3 v1(m_predictedPosition.x, m_predictedPosition.y, 0.0f); Vec3 pt(entPos.x, entPos.y, 0.0f); Lineseg validPath(v0, v1); float t; float distSqrXY = Distance::Point_LinesegSq(pt, validPath, t); float heightDiff = m_predictedPosition.z - entPos.z; float blockedFactor = (1.0f - (m_blockedTime / k_maxBlockTime)); float maxDistXY = !m_passedNetPos ? blockedFactor * k_maxInterpolateDist : k_reachedTargetAllowedDeviation; float timeOnGround = m_pPlayer->GetActorStats()->onGround; float allowedHeightDiff = (float)__fsel(timeOnGround - k_onGroundTime, k_allowedHeightDiff, k_allowedHeightDiffInAir); if ((distSqrXY > (maxDistXY * maxDistXY)) || (cry_fabsf(heightDiff) > allowedHeightDiff)) { //--- Snap to target m_pPlayer->GetEntity()->SetPos(desiredPos); m_passedNetPos = true; const bool isfallen = m_pPlayer->m_stats.inFreefall.Value()==1; } } }
//------------------------------------------------------------------------ bool CGunTurret::IsAiming(const Vec3 &pos, float treshold) const { Vec3 tdir=(pos-GetWeaponPos()).normalized(); float dot = GetWeaponDir().Dot(tdir); float angle=RAD2DEG(cry_acosf(CLAMP(dot,-1.f,1.f))); if(cry_fabsf(angle)>treshold) return false; return true; }
void CVehicleMovementMPVTOL::ReceivedServerPathingData( const SVTOLPathPosParams& data ) { CryAutoCriticalSection lk(m_lock); //CryLog( "[VTOL] CLUPDATE: path[%d] loc[%f]", data.pathId, data.location ); float netError = 0.f; if( m_pathing.pathingData.pathId==data.pathId && m_pathing.pCachedPathPtr ) { netError = m_pathing.pCachedPathPtr->GetDistance( m_pathing.pathingData.location, data.location, m_pathing.shouldLoop ); if(cry_fabsf(netError) > g_pGameCVars->v_MPVTOLNetworkSnapThreshold) { SnapToPathLoc(data); netError = 0.0f; } } // Let it out of a wait, if the server VTOL is moving on (avoids a snap) if(netError>(g_pGameCVars->v_MPVTOLNetworkSnapThreshold*0.4f) && m_pathing.waitTime) { m_pathing.waitTime = 0.f; m_pathing.targetSpeed = m_pathing.defaultSpeed; } m_pathing.networkError = netError; }
void CVehicleMovementHelicopter::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); CryAutoCriticalSection lk(m_lock); SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; if (m_arcade.m_handling.maxSpeedForward>0.f) // Use the new handling code { //ResetActions(); m_movementAction.Clear(); m_movementAction.isAI = true; SVehiclePhysicsHelicopterProcessAIParams params; params.pPhysStatus = physStatus; params.pInputAction = &m_inputAction; params.pAiRequest = &m_aiRequest; params.dt = deltaTime; params.aiRequiredVel = m_CurrentVel; params.aiCurrentSpeed = m_CurrentSpeed; params.aiYawResponseScalar = m_yawResponseScalar; m_yawResponseScalar = 1.f; // Use helper class to process the AI input // It will return a requested velocity, and change the input m_arcade.ProcessAI(params); // Get the output velocity m_CurrentVel = params.aiRequiredVel; m_CurrentSpeed = params.aiCurrentSpeed; return; } ////////////////////// OLD DEPRECATED CODE :( ////////////////////////////////// m_movementAction.Clear(); ResetActions(); // Our current state const Vec3 worldPos = physStatus->pos; const Matrix33 worldMat( physStatus->q); const Matrix33 localMat( physStatus->q.GetInverted()); const Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat); const Ang3 localAngles = Ang3::GetAnglesXYZ(localMat); const Vec3 currentVel = physStatus->v; const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f); m_CurrentSpeed = m_CurrentVel.len(); //currentVel.len(); float currentSpeed2d = currentVel2D.len(); // +ve direction mean rotation anti-clocwise about the z axis - 0 means along y float currentDir = worldAngles.z; // to avoid singularity const Vec3 vWorldDir = worldMat.GetRow(1); const Vec3 vSideWays = worldMat.GetRow(0); const Vec3 vWorldDir2D = Vec3( vWorldDir.x, vWorldDir.y, 0.0f ).GetNormalizedSafe(); // Our inputs float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f; Limit(desiredSpeed, -m_maxSpeed, m_maxSpeed); const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir; Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f); desiredMoveDir2D = desiredMoveDir2D.GetNormalizedSafe(desiredMoveDir2D); const Vec3 desiredVel = desiredMoveDir * desiredSpeed; const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f); Vec3 desiredLookDir(desiredMoveDir); if (m_aiRequest.HasDesiredBodyDirectionAtTarget()) { desiredLookDir = m_aiRequest.GetDesiredBodyDirectionAtTarget().GetNormalizedSafe(desiredMoveDir); } else if (m_aiRequest.HasLookTarget()) { desiredLookDir = (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe(desiredMoveDir); } //const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir; const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); Vec3 prediction = m_aiRequest.HasBodyTarget() ? m_aiRequest.GetBodyTarget() : ZERO; prediction = (prediction.IsEquivalent(ZERO)) ? desiredMoveDir2D : prediction - worldPos; prediction.z = 0.0f; float speedLimit = prediction.GetLength2D(); if(speedLimit > 0.0f) { prediction *= 1.0f / speedLimit; } Vec3 tempDir = currentVel2D.IsEquivalent(ZERO) ? localMat.GetRow(1) : currentVel2D; tempDir.z = 0.0f; tempDir.NormalizeFast(); float dotProd = tempDir.dot(prediction); Limit(dotProd, FLT_EPSILON, 1.0f); float accel = m_enginePowerMax * min(2.0f, 1.0f / dotProd); // * dotProd; if (!m_aiRequest.HasDesiredBodyDirectionAtTarget()) { dotProd *= dotProd; dotProd *= dotProd; float tempf = min(max(speedLimit * speedLimit, 2.0f), m_maxSpeed * dotProd); Limit(desiredSpeed, -tempf, tempf); } else if (dotProd < 0.0125f) { Limit(desiredSpeed, -m_maxSpeed * 0.25f, m_maxSpeed * 0.25f); } float posNeg = (float)__fsel(desiredSpeed - m_CurrentSpeed, 1.0f, -5.0f); if (desiredVel2D.GetLengthSquared() > FLT_EPSILON) { m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime; } else { m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime; } if (posNeg > 0.0f && m_CurrentSpeed > desiredSpeed) { m_CurrentSpeed = desiredSpeed; } else if (posNeg < 0.0f && m_CurrentSpeed < desiredSpeed) { m_CurrentSpeed = desiredSpeed; } // ---------------------------- Rotation ---------------------------- float desiredDir = (desiredLookDir2D.GetLengthSquared() > 0.0f) ? atan2f(-desiredLookDir2D.x, desiredLookDir2D.y) : atan2f(-vWorldDir2D.x, vWorldDir2D.y); while (currentDir < desiredDir - gf_PI) currentDir += 2.0f * gf_PI; while (currentDir > desiredDir + gf_PI) currentDir -= 2.0f * gf_PI; // ---------------------------- Yaw ---------------------------- Ang3 dirDiff(0.0f, 0.0f, desiredDir - currentDir); dirDiff.RangePI(); float absDiff = fabsf(dirDiff.z); float rotSpeed = (float)__fsel(dirDiff.z, m_yawPerRoll, -m_yawPerRoll); m_actionYaw = m_actionYaw + deltaTime * (rotSpeed - m_actionYaw); float temp = fabsf(m_actionYaw); float multiplier = ((absDiff / (temp + 0.001f)) + 1.0f) * 0.5f; m_actionYaw *= (float)__fsel(absDiff - temp, 1.0f, multiplier); // ---------------------------- Yaw ------------------------------ m_CurrentVel = desiredMoveDir * m_CurrentSpeed; // ---------------------------- Pitch ---------------------------- if (m_CurrentVel.GetLengthSquared2D() > 0.1f) { CalculatePitch(worldAngles, desiredMoveDir, currentSpeed2d, desiredSpeed, deltaTime); } else { Quat rot; rot.SetRotationVDir(desiredLookDir, 0.0f); float desiredXRot = Ang3::GetAnglesXYZ(rot).x + m_steeringDamage.x; m_actionPitch = worldAngles.x + (desiredXRot - worldAngles.x) * deltaTime/* * 10.0f*/; Limit(m_actionPitch, -m_maxPitchAngle * 2.0f, m_maxPitchAngle * 2.0f); } // ---------------------------- Roll ---------------------------- float rollSpeed = GetRollSpeed(); rollSpeed *= deltaTime; rollSpeed = (float)__fsel(absDiff - rollSpeed, rollSpeed, absDiff); float roll =(float) __fsel(dirDiff.z, -rollSpeed, rollSpeed); float speedPerUnit = 1.5f; float desiredRollSpeed = absDiff * speedPerUnit * (float)__fsel(dirDiff.z, 1.0f, -1.0f); desiredRollSpeed = -m_actionYaw * 2.5f; desiredRollSpeed += m_steeringDamage.y; m_actionRoll = m_actionRoll + deltaTime * (desiredRollSpeed - m_actionRoll); Limit(m_actionRoll, -m_maxRollAngle + m_steeringDamage.y, m_maxRollAngle - m_steeringDamage.y); m_actionRoll *= m_rollDamping; // ---------------------------- Roll ---------------------------- // ---------------------------- Convert and apply ---------------------------- Ang3 angles(m_actionPitch, m_actionRoll, worldAngles.z + deltaTime * m_actionYaw); pe_params_pos paramPos; paramPos.q.SetRotationXYZ(angles); paramPos.q.Normalize(); IPhysicalEntity * pPhysicalEntity = GetPhysics(); pPhysicalEntity->SetParams(¶mPos, 1); pe_action_set_velocity vel; vel.v = m_CurrentVel + m_netPosAdjust; pPhysicalEntity->Action(&vel, 1); // ---------------------------- Convert and apply ---------------------------- m_rpmScale = max(0.2f, cry_fabsf(m_CurrentSpeed / m_maxSpeed)); }
//------------------------------------------------------------------------ void CProjectile::Ricochet(EventPhysCollision *pCollision) { IActor *pActor = g_pGame->GetIGameFramework()->GetClientActor(); if (!pActor) return; Vec3 dir=pCollision->vloc[0]; dir.NormalizeSafe(); float dot=pCollision->n.Dot(dir); if (dot>=0.0f) // backface return; float b=0,f=0; uint matPierceability=0; if (!gEnv->pPhysicalWorld->GetSurfaceParameters(pCollision->idmat[1], b, f, matPierceability)) return; matPierceability&=sf_pierceable_mask; float probability=0.25+0.25*(MAX(0,7-matPierceability)/7.0f); if ((matPierceability && matPierceability>=8) || Random()>probability) return; f32 cosine = dir.Dot(-pCollision->n); if (cosine>1.0f)cosine=1.0f; if (cosine<-1.0f) cosine=-1.0f; float angle=RAD2DEG( cry_fabsf(cry_acosf(cosine)) ); if (angle<10.0f) return; Vec3 ricochetDir = -2.0f*dot*pCollision->n+dir; ricochetDir.NormalizeSafe(); Ang3 angles=Ang3::GetAnglesXYZ(Matrix33::CreateRotationVDir(ricochetDir)); float rx=Random()-0.5f; float rz=Random()-0.5f; angles.x+=rx*DEG2RAD(10.0f); angles.z+=rz*DEG2RAD(10.0f); ricochetDir=Matrix33::CreateRotationXYZ(angles).GetColumn(1).normalized(); Lineseg line(pCollision->pt, pCollision->pt+ricochetDir*20.0f); Vec3 player = pActor->GetEntity()->GetWorldPos(); float t; float distanceSq=Distance::Point_LinesegSq(player, line, t); if (distanceSq < 7.5*7.5 && (t>=0.0f && t<=1.0f)) { if (distanceSq >= 0.25*0.25) { Sphere s; s.center = player; s.radius = 6.0f; Vec3 entry,exit; int intersect=Intersect::Lineseg_Sphere(line, s, entry,exit); if (intersect) // one entry or one entry and one exit { if (intersect==0x2) entry=pCollision->pt; RicochetSound(entry, ricochetDir); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine(entry, ColorB(255, 255, 255, 255), entry+ricochetDir, ColorB(255, 255, 255, 255), 2); } } } }
//------------------------------------------------------------------------ void CRapid::Update(float frameTime, uint32 frameId) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); PlayStopRapidFireIfNeeded(); BaseClass::Update(frameTime, frameId); if (m_speed <= 0.0f && m_acceleration < 0.0001f) { FinishDeceleration(); return; } CActor* pOwnerActor = m_pWeapon->GetOwnerActor(); const bool isOwnerClient = pOwnerActor ? pOwnerActor->IsClient() : false; const bool isOwnerPlayer = pOwnerActor ? pOwnerActor->IsPlayer() : false; m_pWeapon->RequireUpdate(eIUS_FireMode); m_speed = m_speed + m_acceleration*frameTime; if (m_speed > m_fireParams->rapidparams.max_speed) { m_speed = m_fireParams->rapidparams.max_speed; m_rapidFlags &= ~eRapidFlag_accelerating; } if ((m_speed >= m_fireParams->rapidparams.min_speed) && !(m_rapidFlags & eRapidFlag_decelerating)) { float dt = 1.0f; if (cry_fabsf(m_speed)>0.001f && cry_fabsf(m_fireParams->rapidparams.max_speed)>0.001f) { dt = m_speed * (float)__fres(m_fireParams->rapidparams.max_speed); } CRY_ASSERT(m_fireParams->fireparams.rate > 0); m_next_shot_dt = 60.0f* (float)__fres((m_fireParams->fireparams.rate*dt)); if (CanFire(false)) { if (!OutOfAmmo()) { const bool firing = (m_rapidFlags & eRapidFlag_netShooting) || Shoot(true, m_fireParams->fireparams.autoReload); Firing(firing); } else { StopFire(); } } } else if (m_firing) { StopFire(); if (OutOfAmmo() && isOwnerPlayer) { m_pWeapon->Reload(); } } if ((m_speed < m_fireParams->rapidparams.min_speed) && (m_acceleration < 0.0f) && !(m_rapidFlags & eRapidFlag_decelerating)) Accelerate(m_fireParams->rapidparams.deceleration); UpdateRotation(frameTime); UpdateFiring(pOwnerActor, isOwnerClient, isOwnerPlayer, frameTime); }
//------------------------------------------------------------------------ void CScriptControlledPhysics::OnPostStep(EventPhysPostStep *pPostStep) { pe_action_set_velocity av; bool moving=m_moving; bool rotating=m_rotating; float dt=pPostStep->dt; if(m_moving) { Vec3 current=pPostStep->pos; Vec3 target=m_moveTarget; Vec3 delta=target-current; float distance=delta.len(); Vec3 dir=delta; if(distance>0.01f) dir *= (1.0f/distance); if(distance<0.01f) { m_speed=0.0f; m_moving=false; pPostStep->pos=target; av.v=ZERO; } else { float a=m_speed/m_stopTime; float d=m_speed*m_stopTime-0.5f*a*m_stopTime*m_stopTime; if(distance<=(d+0.01f)) m_acceleration=(distance-m_speed*m_stopTime)/(m_stopTime*m_stopTime); m_speed=m_speed+m_acceleration*dt; if(m_speed>=m_maxSpeed) { m_speed=m_maxSpeed; m_acceleration=0.0f; } else if(m_speed*dt>distance) m_speed=distance/dt; else if(m_speed<0.05f) m_speed=0.05f; av.v=dir*m_speed; } } if(m_rotating) { Quat current=pPostStep->q; Quat target=m_rotationTarget; Quat rotation=target*!current; float angle=cry_acosf(CLAMP(rotation.w, -1.0f, 1.0f))*2.0f; float original=angle; if(angle>gf_PI) angle=angle-gf_PI2; else if(angle<-gf_PI) angle=angle+gf_PI2; if(cry_fabsf(angle)<0.001f) { m_rotationSpeed=0.0f; m_rotating=false; pPostStep->q=m_rotationTarget; av.w=ZERO; } else { float a=m_rotationSpeed/m_rotationStopTime; float d=m_rotationSpeed*m_stopTime-0.5f*a*m_rotationStopTime*m_rotationStopTime; if(cry_fabsf(angle)<d+0.001f) m_rotationAcceleration=(angle-m_rotationSpeed*m_rotationStopTime)/(m_rotationStopTime*m_rotationStopTime); m_rotationSpeed=m_rotationSpeed+sgn(angle)*m_rotationAcceleration*dt; if(cry_fabsf(m_rotationSpeed*dt)>cry_fabsf(angle)) m_rotationSpeed=angle/dt; else if(cry_fabsf(m_rotationSpeed)<0.001f) m_rotationSpeed=sgn(m_rotationSpeed)*0.001f; else if(cry_fabsf(m_rotationSpeed)>=m_rotationMaxSpeed) { m_rotationSpeed=sgn(m_rotationSpeed)*m_rotationMaxSpeed; m_rotationAcceleration=0.0f; } } if(cry_fabsf(angle)>=0.001f) av.w=(rotation.v/cry_sinf(original*0.5f)).normalized(); av.w*=m_rotationSpeed; } if(moving || rotating) { if(IPhysicalEntity *pPE=GetEntity()->GetPhysics()) pPE->Action(&av); } if((moving && !m_moving) || (rotating && !m_rotating)) GetEntity()->SetWorldTM(Matrix34::Create(GetEntity()->GetScale(), pPostStep->q, pPostStep->pos)); }
//------------------------------------------------------------------------ void CRapid::Update(float frameTime, uint32 frameId) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); CSingle::Update(frameTime, frameId); if (m_speed <= 0.0f && m_acceleration < 0.0001f) { FinishDeceleration(); return; } m_pWeapon->RequireUpdate(eIUS_FireMode); m_speed = m_speed + m_acceleration*frameTime; if (m_speed > m_pShared->rapidparams.max_speed) { m_speed = m_pShared->rapidparams.max_speed; m_accelerating = false; } if ((m_speed >= m_pShared->rapidparams.min_speed) && (!m_decelerating)) { float dt = 1.0f; if (cry_fabsf(m_speed)>0.001f && cry_fabsf(m_pShared->rapidparams.max_speed>0.001f)) dt=m_speed/m_pShared->rapidparams.max_speed; m_next_shot_dt = 60.0f/(m_pShared->fireparams.rate*dt); bool canShoot = CanFire(false); if (canShoot) { if (!OutOfAmmo()) { if (m_netshooting) Firing(true); else Firing(Shoot(true, false)); if (m_firing && !(m_pShared->rapidparams.camshake_rotate.IsZero() && m_pShared->rapidparams.camshake_shift.IsZero())) { CActor *act = m_pWeapon->GetOwnerActor(); if (act && act->IsClient()) { IView *pView = g_pGame->GetIGameFramework()->GetIViewSystem()->GetActiveView(); if (pView) pView->SetViewShake(Ang3(m_pShared->rapidparams.camshake_rotate), m_pShared->rapidparams.camshake_shift, m_next_shot_dt/m_pShared->rapidparams.camshake_perShot, m_next_shot_dt/m_pShared->rapidparams.camshake_perShot, 0, 1); } } } else { Firing(false); Accelerate(m_pShared->rapidparams.deceleration); if (m_pWeapon->GetOwnerActor() && m_pWeapon->GetOwnerActor()->IsPlayer()) { SmokeEffect(); m_pWeapon->Reload(); } } } } else if (m_firing) { Firing(false); if (OutOfAmmo() && m_pWeapon->GetOwnerActor() && m_pWeapon->GetOwnerActor()->IsPlayer()) { SmokeEffect(); m_pWeapon->Reload(); } } if ((m_speed < m_pShared->rapidparams.min_speed) && (m_acceleration < 0.0f) && (!m_decelerating)) Accelerate(m_pShared->rapidparams.deceleration); UpdateRotation(frameTime); UpdateSound(frameTime); }
//------------------------------------------------------------------------ void CScriptControlledPhysics::OnPostStep(EventPhysPostStep *pPostStep) { pe_action_set_velocity av; const bool moving = m_moving; const bool rotating = m_rotating; const float deltaTime = pPostStep->dt; if (m_moving) { const Vec3 current = pPostStep->pos; const Vec3 target = m_moveTarget; const Vec3 delta = target - current; const float distanceSq = delta.len2(); if (distanceSq <= sqr(0.025f) || (delta.dot(m_lastVelocity) < 0.0f)) { m_speed = 0.0f; m_moving = false; m_lastVelocity.zero(); pPostStep->pos = target; av.v = ZERO; } else { float velocity = m_speed; float acceleration = m_acceleration; Vec3 direction = delta; const float distanceToEnd = direction.NormalizeSafe(); // Accelerate velocity = std::min(velocity + acceleration * deltaTime, m_maxSpeed); // Calculate acceleration and time needed to stop const float accelerationNeededToStop = (-(velocity*velocity) / distanceToEnd) / 2; if (fabsf(accelerationNeededToStop) > 0.0f) { const float timeNeededToStop = sqrtf((distanceToEnd / 0.5f) / fabsf(accelerationNeededToStop)); if (timeNeededToStop < m_stopTime) { acceleration = accelerationNeededToStop; } } // Prevent overshooting if ((velocity * deltaTime) > distanceToEnd) { const float multiplier = distanceToEnd / fabsf(velocity * deltaTime); velocity *= multiplier; acceleration *= multiplier; } m_acceleration = acceleration; m_speed = velocity; m_lastVelocity = direction * velocity; av.v = direction * velocity; } } if (m_rotating) { Quat current=pPostStep->q; Quat target=m_rotationTarget; Quat rotation=target*!current; float angle=cry_acosf(CLAMP(rotation.w, -1.0f, 1.0f))*2.0f; float original=angle; if (angle>gf_PI) angle=angle-gf_PI2; else if (angle<-gf_PI) angle=angle+gf_PI2; if (cry_fabsf(angle)<0.01f) { m_rotationSpeed=0.0f; m_rotating=false; pPostStep->q=m_rotationTarget; av.w=ZERO; } else { float a=m_rotationSpeed/m_rotationStopTime; float d=m_rotationSpeed*m_stopTime-0.5f*a*m_rotationStopTime*m_rotationStopTime; if (cry_fabsf(angle)<d+0.001f) m_rotationAcceleration=(angle-m_rotationSpeed*m_rotationStopTime)/(m_rotationStopTime*m_rotationStopTime); m_rotationSpeed=m_rotationSpeed+sgn(angle)*m_rotationAcceleration*deltaTime; if (cry_fabsf(m_rotationSpeed*deltaTime)>cry_fabsf(angle)) m_rotationSpeed=angle/deltaTime; else if (cry_fabsf(m_rotationSpeed)<0.001f) m_rotationSpeed=sgn(m_rotationSpeed)*0.001f; else if (cry_fabsf(m_rotationSpeed)>=m_rotationMaxSpeed) { m_rotationSpeed=sgn(m_rotationSpeed)*m_rotationMaxSpeed; m_rotationAcceleration=0.0f; } } if(cry_fabsf(angle)>=0.001f) av.w=(rotation.v/cry_sinf(original*0.5f)).normalized(); av.w*=m_rotationSpeed; } if (moving || rotating) { if (IPhysicalEntity *pPE=GetEntity()->GetPhysics()) pPE->Action(&av, 1); } /* if ((moving && !m_moving) || (rotating && !m_rotating)) GetEntity()->SetWorldTM(Matrix34::Create(GetEntity()->GetScale(), pPostStep->q, pPostStep->pos)); */ }
QuatT CStrafeOffset::Compute(float frameTime) { const float STAP_MF_Front = 1.0f; const float STAP_MF_Back = 1.0f; const float STAP_MF_StrafeLeft = 1.0f; const float STAP_MF_StrafeRight = 1.0f; static const float MIN_VERT_DIR = 0.2f; static const float MAX_VERT_DIR = 1.0f; static const float MIN_HORIZ_DIR = 0.2f; static const float MAX_HORIZ_DIR = 3.0f; static const float runEaseFactor = 0.2f; const float MIN_SPEED = 0.2f; const float MAX_SPEED = 4.0f; float rotationFactor = 1.0f; float strafeFactor = 1.0f; Ang3 inputRot = m_gameParams.inputRot; float absInputRotHoriz = cry_fabsf(inputRot.z) * rotationFactor; float horizSpeed = m_gameParams.velocity.GetLength2D(); float runFactor = (horizSpeed - MIN_SPEED) / (MAX_SPEED - MIN_SPEED); const float horizRotFactor = clamp(-m_gameParams.aimDirection.z * (absInputRotHoriz - MIN_HORIZ_DIR) / (MAX_HORIZ_DIR - MIN_HORIZ_DIR), 0.0f, 1.0f); runFactor = max(runFactor, horizRotFactor); runFactor = clamp(runFactor, 0.0f, 1.0f); m_runFactor = ((runFactor * runEaseFactor) + (m_runFactor * (1.0f - runEaseFactor))); //--- Calculate movement acceleration const float invFrontAugmentation = m_staticParams.accelerationFrontAugmentation != 0.0 ? (1.0f / m_staticParams.accelerationFrontAugmentation) : 1.0f; const Vec3 inputMoveAugmented = Vec3( m_gameParams.inputMove.x * invFrontAugmentation, m_gameParams.inputMove.y * m_staticParams.accelerationFrontAugmentation, 0.0f); Interpolate(m_smoothedVelocity, inputMoveAugmented, m_staticParams.velocityLowPassFilter, frameTime); const Vec3 velocityDerivative = (frameTime > 0.0) ? ((m_smoothedVelocity - m_lastVelocity) / frameTime) : Vec3(ZERO); m_lastVelocity = m_smoothedVelocity; float interpFront = SignedPow(clamp(velocityDerivative.y * m_staticParams.velocityInterpolationMultiplier, -1, 1), m_staticParams.accelerationSmoothing); interpFront *= (float)__fsel(interpFront, STAP_MF_Front, STAP_MF_Back) * strafeFactor; Interpolate(m_interpFront, interpFront, m_staticParams.velocityLowPassFilter, frameTime); float interpSide = SignedPow(clamp(velocityDerivative.x * m_staticParams.velocityInterpolationMultiplier, -1, 1), m_staticParams.accelerationSmoothing); interpSide *= (float)__fsel(interpSide, STAP_MF_StrafeLeft, STAP_MF_StrafeRight) * strafeFactor; Interpolate(m_interpSide, interpSide, m_staticParams.velocityLowPassFilter, frameTime); // create offsets QuatT strafeOffset(IDENTITY); Vec3 posSize = m_staticParams.strafe_offset; Ang3 sideRotSize = m_staticParams.side_strafe_rot; Ang3 frontRotSize = m_staticParams.front_strafe_rot; const float cmToMeter = 1.0f / 100.0f; const float degreeToRadians = 3.14159f / 180.0f; strafeOffset.t.x -= m_interpSide * posSize.x * cmToMeter; strafeOffset.t.y -= m_interpFront * posSize.y * cmToMeter; strafeOffset.t.z -= max(std::abs(m_interpFront), std::abs(m_interpSide)) * posSize.z * cmToMeter; strafeOffset.q *= Quat(sideRotSize * m_interpSide * degreeToRadians); strafeOffset.q *= Quat(frontRotSize * m_interpFront * degreeToRadians); return strafeOffset; }
//------------------------------------------------------------------------ void CGunTurret::UpdateOrientation(float deltaTime) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); bool changed = false; bool searching = (m_targetId==0 && m_turretparams.searching); float speed = searching ? m_turretparams.search_speed : m_turretparams.turn_speed; assert(m_goalYaw >= 0.f && m_goalYaw <= gf_PI2); // update turret Matrix34 turretTM = GetEntity()->GetSlotLocalTM(eIGS_Aux0, false); Ang3 turretAngles(turretTM); if(turretAngles.z < 0.0f) turretAngles.z+=gf_PI2; if(cry_fabsf(m_goalYaw-turretAngles.z) > gf_PI) { if(m_goalYaw >= gf_PI) turretAngles.z += gf_PI2; else turretAngles.z -= gf_PI2; } if(m_turretparams.yaw_range < 360.f) { // reverse, to avoid forbidden range if(m_goalYaw > gf_PI && turretAngles.z < gf_PI) turretAngles.z += gf_PI2; else if(m_goalYaw < gf_PI && turretAngles.z > gf_PI) turretAngles.z -= gf_PI2; } if(cry_fabsf(turretAngles.z-m_goalYaw) > 0.001f) { Interp(turretAngles.z, m_goalYaw, speed, deltaTime, 0.25f*speed); if(m_turretSound == INVALID_SOUNDID && gEnv->IsClient()) m_turretSound = PlayAction(g_pItemStrings->turret); changed = true; } else if(m_turretSound != INVALID_SOUNDID) { StopSound(m_turretSound); m_turretSound = INVALID_SOUNDID; } if(changed) { turretTM.SetRotationXYZ(turretAngles,turretTM.GetTranslation()); GetEntity()->SetSlotLocalTM(eIGS_Aux0, turretTM); } // update weapon Matrix34 weaponTM = GetEntity()->GetSlotLocalTM(eIGS_ThirdPerson, false); Ang3 weaponAngles(weaponTM); weaponAngles.z = turretAngles.z; if(cry_fabsf(weaponAngles.x-m_goalPitch) > 0.001f) { Interp(weaponAngles.x, m_goalPitch, speed, deltaTime, 0.25f*speed); if(m_cannonSound == INVALID_SOUNDID && gEnv->IsClient()) m_cannonSound = PlayAction(g_pItemStrings->cannon); changed = true; } else if(m_cannonSound != INVALID_SOUNDID) { StopSound(m_cannonSound); m_cannonSound = INVALID_SOUNDID; } if(changed) { weaponTM.SetRotationXYZ(weaponAngles); Vec3 w_trans = turretTM.TransformPoint(m_radarHelperPos); //Vec3 w_trans = GetSlotHelperPos(eIGS_Aux0,m_radarHelper.c_str(),false); weaponTM.SetTranslation(w_trans); GetEntity()->SetSlotLocalTM(eIGS_ThirdPerson, weaponTM); if(GetEntity()->IsSlotValid(eIGS_Aux1)) { Vec3 b_trans = weaponTM.TransformPoint(m_barrelHelperPos); //Vec3 b_trans = GetSlotHelperPos(eIGS_ThirdPerson,m_barrelHelper.c_str(),false); weaponTM.SetTranslation(b_trans); GetEntity()->SetSlotLocalTM(eIGS_Aux1, weaponTM*m_barrelRotation); } if(gEnv->IsClient()) { for(TEffectInfoMap::const_iterator it=m_effects.begin(); it!=m_effects.end(); ++it) { Matrix34 tm(GetSlotHelperRotation(eIGS_ThirdPerson,it->second.helper.c_str(),true), GetSlotHelperPos(eIGS_ThirdPerson,it->second.helper.c_str(),true)); SetEffectWorldTM(it->first, tm); } } } UpdatePhysics(); if(g_pGameCVars->i_debug_turrets == eGTD_Basic) { DrawDebug(); //gEnv->pRenderer->DrawLabel(GetEntity()->GetWorldPos(), 1.4f, "%s yaw: %.2f, goalYaw: %.2f (%.2f), goalPitch: %.2f (%.2f/%.2f)", searching?"[search]":"", RAD2DEG(turretAngles.z), RAD2DEG(m_goalYaw), 0.5f*(m_turretparams.yaw_range), RAD2DEG(m_goalPitch), m_turretparams.min_pitch, m_turretparams.max_pitch); } }