//------------------------------------------------------------------------ void CVehicleViewSteer::UpdateView(SViewParams &viewParams, EntityId playerId) { static bool doUpdate = true; if (!doUpdate) return; if (m_position.IsValid()) { viewParams.position = m_position; } else { CRY_ASSERT_MESSAGE(0, "camera position invalid"); } Vec3 dir = (m_lookAt - m_position).GetNormalizedSafe(); if (dir.IsValid() && dir.GetLengthSquared() > 0.01f) { viewParams.rotation = Quat::CreateRotationVDir(dir); } else { CRY_ASSERT_MESSAGE(0, "camera rotation invalid"); } // set view direction on actor IActor* pActor = m_pSeat->GetPassengerActor(true); if (pActor && pActor->IsClient()) { pActor->SetViewInVehicle(viewParams.rotation); } }
void CScriptProxy::OnCollision(CEntity* pTarget, int matId, const Vec3 &pt, const Vec3 &n, const Vec3 &vel, const Vec3 &targetVel, int partId, float mass) { if (!CurrentState()->IsStateFunctionImplemented(ScriptState_OnCollision)) return; FUNCTION_PROFILER( GetISystem(), PROFILE_ENTITY ); if (!m_hitTable) m_hitTable.Create(gEnv->pScriptSystem); { Vec3 dir(0, 0, 0); CScriptSetGetChain chain(m_hitTable); chain.SetValue("normal", n); chain.SetValue("pos", pt); if (vel.GetLengthSquared() > 1e-6f) { dir = vel.GetNormalized(); chain.SetValue("dir", dir); } chain.SetValue("velocity", vel); chain.SetValue("target_velocity", targetVel); chain.SetValue("target_mass", mass); chain.SetValue("partid", partId); chain.SetValue("backface", n.Dot(dir) >= 0); chain.SetValue("materialId", matId); if (pTarget) { ScriptHandle sh; sh.n = pTarget->GetId(); if (pTarget->GetPhysics()) { chain.SetValue("target_type", (int)pTarget->GetPhysics()->GetType()); } else { chain.SetToNull("target_type"); } chain.SetValue("target_id", sh); if (pTarget->GetScriptTable()) { chain.SetValue("target", pTarget->GetScriptTable()); } } else { chain.SetToNull("target_type"); chain.SetToNull("target_id"); chain.SetToNull("target"); } } m_pScript->CallStateFunction( CurrentState(),m_pThis,ScriptState_OnCollision, m_hitTable); }
bool CBattleDust::CheckIntersection(CBattleEvent* pEventOne, Vec3& pos, float radius) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); if(!pEventOne) return false; Vec3 centreToCentre = pos - pEventOne->m_worldPos; float sumRadiiSquared = (radius * radius) + (pEventOne->m_radius * pEventOne->m_radius); float distanceSquared = centreToCentre.GetLengthSquared(); return ((distanceSquared < sumRadiiSquared) && (distanceSquared < m_distanceBetweenEvents*m_distanceBetweenEvents)); }
bool SkillKill::IsGotYourBackKill(CPlayer* pShooterPlayer, CPlayer* pTargetPlayer) { //To use the new actor manager stuff when merged back to postalpha const float maxDistSq = sqr(g_pGameCVars->g_gotYourBackKill_targetDistFromFriendly); const float fovRange = cry_cosf(DEG2RAD(g_pGameCVars->g_gotYourBackKill_FOVRange)); IActorIteratorPtr pActorIterator = g_pGame->GetIGameFramework()->GetIActorSystem()->CreateActorIterator(); Vec3 targetLocation = pTargetPlayer->GetEntity()->GetWorldPos(); SMovementState targetMovementState; pTargetPlayer->GetMovementController()->GetMovementState(targetMovementState); Vec3 targetAimDirection = targetMovementState.aimDirection; while(CActor* pActor = static_cast<CActor*>(pActorIterator->Next())) { if(pActor != pShooterPlayer && !pActor->IsDead() && pShooterPlayer->IsFriendlyEntity(pActor->GetEntityId())) { Vec3 actorLocation = pActor->GetEntity()->GetWorldPos(); Vec3 distance = actorLocation - targetLocation; if(distance.GetLengthSquared() < maxDistSq) { distance.Normalize(); if(distance.Dot(targetAimDirection) > fovRange) { SMovementState actorMovementState; pActor->GetMovementController()->GetMovementState(actorMovementState); Vec3 actorAimDirection = actorMovementState.aimDirection; if(actorAimDirection.Dot(-distance) < fovRange) { return true; } } } } } return false; }
void CVehicleMovementHelicopter::UpdateNetworkError(const Vec3& netPosition, const Quat& netRotation) { SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; if(!physStatus->pos.IsZero(0.5f)) { static const float maxDotError = cosf(0.5f*DEG2RAD(10.f)); Vec3 posError = netPosition - physStatus->pos; float dotProduct = physStatus->q | netRotation; // CryWatch("posError=%.2f", posError.GetLength()); if (posError.GetLengthSquared()>sqr(4.f) || dotProduct < maxDotError) { // Snap! m_pEntity->SetPos(netPosition); m_pEntity->SetRotation(netRotation); m_netPosAdjust.zero(); } else { // Change the error smoothly m_netPosAdjust += (posError - m_netPosAdjust)*0.5f; } } }
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 CClaymore::Update(SEntityUpdateContext &ctx, int updateSlot) { CProjectile::Update(ctx, updateSlot); bool debug = (g_pGameCVars->g_debugMines != 0); if(gEnv->bServer) { if(m_armed) { CGameRules* pGR = g_pGame->GetGameRules(); if(pGR) { for(std::list<EntityId>::iterator it = m_targetList.begin(); it != m_targetList.end(); ++it) { IEntity* pEntity = gEnv->pEntitySystem->GetEntity(*it); if(!pEntity) continue; // if this is a team game, claymores aren't set off by their own team... if(pGR->GetTeamCount() > 0 && (m_teamId != 0 && pGR->GetTeam(pEntity->GetId()) == m_teamId)) continue; // otherwise, not set off by the player who dropped them. if(pGR->GetTeamCount() == 0 && m_ownerId == pEntity->GetId()) continue; IPhysicalEntity *pPhysics = pEntity->GetPhysics(); if(pPhysics) { pe_status_dynamics physStatus; if(0 != pPhysics->GetStatus(&physStatus) && physStatus.v.GetLengthSquared() > 0.01f) { // now check angle between this claymore and approaching object // to see if it is within the angular range m_triggerAngle. // If it is, then check distance is less than m_triggerRange, // and also check line-of-sight between the two entities. IRenderAuxGeom * pRAG = gEnv->pRenderer->GetIRenderAuxGeom(); pRAG->SetRenderFlags( e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeNone ); AABB entityBBox; pEntity->GetWorldBounds(entityBBox); if(debug) { pRAG->DrawAABB( entityBBox, true, ColorF(1,0,0,0.4f), eBBD_Faceted ); } Vec3 enemyDir = entityBBox.GetCenter() - GetEntity()->GetPos(); Vec3 checkDir = enemyDir; checkDir.z = 0; float distanceSq = enemyDir.GetLengthSquared(); // for players a simple distance check is fine, but for vehicles use a better intersection check // so any corner of the vehicle going inside the zone sets off the claymore. static float playerRadius = 2.5f; bool inside = false; if(entityBBox.GetRadius() < playerRadius) { inside = (distanceSq < (m_triggerRadius * m_triggerRadius)); } else { static ray_hit hit; if(gEnv->pPhysicalWorld->CollideEntityWithBeam(pEntity->GetPhysics(), GetEntity()->GetWorldPos(), enemyDir, m_triggerRadius, &hit)) { inside = true; enemyDir = hit.pt - GetEntity()->GetWorldPos(); } } if(inside) { enemyDir.NormalizeSafe(); checkDir.NormalizeSafe(); float dotProd = checkDir.Dot(m_triggerDirection); if(debug) { pRAG->DrawLine(GetEntity()->GetPos(), ColorF(1,0,0,1), GetEntity()->GetPos() + Matrix33::CreateRotationZ(m_triggerAngle/2.0f)*m_triggerDirection*m_triggerRadius, ColorF(1,0,0,1), 5.0f); pRAG->DrawLine(GetEntity()->GetPos(), ColorF(1,0,0,1), GetEntity()->GetPos() + Matrix33::CreateRotationZ(-m_triggerAngle/2.0f)*m_triggerDirection*m_triggerRadius, ColorF(1,0,0,1), 5.0f); ColorF clr; clr.a = 0.3f; clr.b = 0.4f; clr.g = 0.1f; clr.r = 1.0f; pRAG->DrawLine(GetEntity()->GetPos(), clr, GetEntity()->GetPos() + (enemyDir * m_triggerRadius), clr, 5.0f); } if(dotProd > cry_cosf(m_triggerAngle/2.0f)) { static const int objTypes = ent_all&(~ent_terrain); static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; ray_hit hit; int col = gEnv->pPhysicalWorld->RayWorldIntersection(GetEntity()->GetPos(), (enemyDir * m_triggerRadius * 1.5f), objTypes, flags, &hit, 1, GetEntity()->GetPhysics()); bool bang = false; if (!col) bang = true; else if (entityBBox.IsContainPoint(hit.pt)) bang = true; else if (hit.pt.GetSquaredDistance(GetEntity()->GetWorldPos()) >= distanceSq) bang = true; if (bang) { // pass in the explosion normal, which is -m_triggerDirection Explode(true, false, Vec3(0,0,0), -m_triggerDirection); if(debug) { ColorF clr; clr.a = 0.3f; clr.g = 0.1f; clr.r = 1.0f; clr.b = 1.0f; pRAG->DrawLine(GetEntity()->GetPos(), clr, GetEntity()->GetPos() + (enemyDir * m_triggerRadius), clr, 5.0f); } } } } } } } } } else { m_timeToArm -= gEnv->pTimer->GetFrameTime(); if(m_timeToArm <= 0.0f) { m_armed = true; IEntityTriggerProxy *pTriggerProxy = (IEntityTriggerProxy*)(GetEntity()->GetProxy(ENTITY_PROXY_TRIGGER)); if (!pTriggerProxy) { GetEntity()->CreateProxy(ENTITY_PROXY_TRIGGER); pTriggerProxy = (IEntityTriggerProxy*)GetEntity()->GetProxy(ENTITY_PROXY_TRIGGER); } if(pTriggerProxy) { // create a trigger volume a couple of metres bigger than we need, to ensure we catch vehicles. // Checks above will still make sure the entity is within the radius before detonating though. float radius = m_triggerRadius + 2.0f; AABB boundingBox = AABB(Vec3(-radius,-radius,-radius), Vec3(radius,radius,radius)); pTriggerProxy->SetTriggerBounds(boundingBox); } } } } if(debug && m_armed) { IRenderAuxGeom * pRAG = gEnv->pRenderer->GetIRenderAuxGeom(); ColorF clr; clr.a = 0.3f; clr.b = 0.4f; clr.g = 0.1f; clr.r = 1.0f; pRAG->SetRenderFlags( e_Mode3D | e_AlphaBlended | e_DrawInFrontOff | e_FillModeSolid | e_CullModeNone ); pRAG->DrawCylinder(GetEntity()->GetPos(), Vec3(0, 0, 1), m_triggerRadius, m_triggerRadius * 2.0f, clr); Vec3 size(m_triggerRadius + 2.0f, m_triggerRadius + 2.0f, m_triggerRadius + 2.0f); AABB box(GetEntity()->GetPos() - size, GetEntity()->GetPos() + size); pRAG->DrawAABB(box, false, ColorF(0.1f, 0.1f, 0.1f, 0.1f), eBBD_Faceted); pRAG->DrawLine(GetEntity()->GetPos(), clr, GetEntity()->GetPos() + m_triggerDirection, clr, 5.0f); } }
void CNetPlayerInput::PreUpdate() { IPhysicalEntity * pPhysEnt = m_pPlayer->GetEntity()->GetPhysics(); if (!pPhysEnt) return; CMovementRequest moveRequest; SMovementState moveState; m_pPlayer->GetMovementController()->GetMovementState(moveState); Quat worldRot = m_pPlayer->GetBaseQuat(); // m_pPlayer->GetEntity()->GetWorldRotation(); Vec3 deltaMovement = worldRot.GetInverted().GetNormalized() * m_curInput.deltaMovement; // absolutely ensure length is correct deltaMovement = deltaMovement.GetNormalizedSafe(ZERO) * m_curInput.deltaMovement.GetLength(); moveRequest.AddDeltaMovement( deltaMovement ); if( IsDemoPlayback() ) { Vec3 localVDir(m_pPlayer->GetViewQuatFinal().GetInverted() * m_curInput.lookDirection); Ang3 deltaAngles(asin(localVDir.z),0,cry_atan2f(-localVDir.x,localVDir.y)); moveRequest.AddDeltaRotation(deltaAngles*gEnv->pTimer->GetFrameTime()); } //else { Vec3 distantTarget = moveState.eyePosition + 1000.0f * m_curInput.lookDirection; Vec3 lookTarget = distantTarget; if (gEnv->bClient && m_pPlayer->GetGameObject()->IsProbablyVisible()) { // post-process aim direction ray_hit hit; static const int obj_types = ent_all; // ent_terrain|ent_static|ent_rigid|ent_sleeping_rigid|ent_living; static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any; bool rayHitAny = 0 != gEnv->pPhysicalWorld->RayWorldIntersection( moveState.eyePosition, 150.0f * m_curInput.lookDirection, obj_types, flags, &hit, 1, pPhysEnt ); if (rayHitAny) { lookTarget = hit.pt; } static float proneDist = 1.0f; static float crouchDist = 0.6f; static float standDist = 0.3f; float dist = standDist; if(m_pPlayer->GetStance() == STANCE_CROUCH) dist = crouchDist; else if(m_pPlayer->GetStance() == STANCE_PRONE) dist = proneDist; if((lookTarget - moveState.eyePosition).GetLength2D() < dist) { Vec3 eyeToTarget2d = lookTarget - moveState.eyePosition; eyeToTarget2d.z = 0.0f; eyeToTarget2d.NormalizeSafe(); eyeToTarget2d *= dist; ray_hit newhit; bool rayHitAny = 0 != gEnv->pPhysicalWorld->RayWorldIntersection( moveState.eyePosition + eyeToTarget2d, 3 * Vec3(0,0,-1), obj_types, flags, &newhit, 1, pPhysEnt ); if (rayHitAny) { lookTarget = newhit.pt; } } // SNH: new approach. Make sure the aimTarget is at least 1.5m away, // if not, pick a point 1m down the vector instead. Vec3 dir = lookTarget - moveState.eyePosition; static float minDist = 1.5f; if(dir.GetLengthSquared() < minDist) { lookTarget = moveState.eyePosition + dir.GetNormalizedSafe(); } // draw eye pos for comparison //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(moveState.eyePosition, 0.04f, ColorF(0.3f,0.2f,0.7f,1.0f)); } moveRequest.SetLookTarget( lookTarget ); moveRequest.SetAimTarget( lookTarget ); if (m_curInput.deltaMovement.GetLengthSquared() > sqr(0.2f)) // 0.2f is almost stopped moveRequest.SetBodyTarget( distantTarget ); else moveRequest.ClearBodyTarget(); } moveRequest.SetAllowStrafing(true); float pseudoSpeed = 0.0f; if (m_curInput.deltaMovement.len2() > 0.0f) { pseudoSpeed = m_pPlayer->CalculatePseudoSpeed(m_curInput.sprint); } moveRequest.SetPseudoSpeed(pseudoSpeed); float lean=0.0f; if (m_curInput.leanl) lean-=1.0f; if (m_curInput.leanr) lean+=1.0f; if (fabsf(lean)>0.01f) moveRequest.SetLean(lean); else moveRequest.ClearLean(); m_pPlayer->GetMovementController()->RequestMovement(moveRequest); if (m_curInput.sprint) m_pPlayer->m_actions |= ACTION_SPRINT; else m_pPlayer->m_actions &= ~ACTION_SPRINT; if (m_curInput.leanl) m_pPlayer->m_actions |= ACTION_LEANLEFT; else m_pPlayer->m_actions &= ~ACTION_LEANLEFT; if (m_curInput.leanr) m_pPlayer->m_actions |= ACTION_LEANRIGHT; else m_pPlayer->m_actions &= ~ACTION_LEANRIGHT; // debug.. if (g_pGameCVars->g_debugNetPlayerInput & 2) { IPersistantDebug * pPD = gEnv->pGame->GetIGameFramework()->GetIPersistantDebug(); pPD->Begin( string("update_player_input_") + m_pPlayer->GetEntity()->GetName(), true ); Vec3 wp = m_pPlayer->GetEntity()->GetWorldPos(); wp.z += 2.0f; pPD->AddSphere( moveRequest.GetLookTarget(), 0.5f, ColorF(1,0,1,0.3f), 1.0f ); // pPD->AddSphere( moveRequest.GetMoveTarget(), 0.5f, ColorF(1,1,0,0.3f), 1.0f ); pPD->AddDirection( m_pPlayer->GetEntity()->GetWorldPos() + Vec3(0,0,2), 1, m_curInput.deltaMovement, ColorF(1,0,0,0.3f), 1.0f ); } //m_curInput.deltaMovement.zero(); }
void CNetLerper::Update(float dt, const Vec3& entityPos, SPrediction& predictionOut, const Vec3& velGround, bool bInAirOrJumping) { if(!m_enabled) { predictionOut.predictedPos = entityPos; predictionOut.lerpVel.zero(); predictionOut.shouldSnap = false; return; } CRY_ASSERT(m_settings); dt = max(dt, 0.001f); IEntity* pGroundEntity = gEnv->pEntitySystem->GetEntity(m_standingOn); m_desired.worldPos = m_desired.pos; if (pGroundEntity) { if (IPhysicalEntity* pGroundPhys = pGroundEntity->GetPhysics()) { pe_status_pos psp; pGroundPhys->GetStatus(&psp); m_desired.worldPos = psp.q * m_desired.pos + psp.pos; } } // Prediction is done a "long" time ahead const float predictTime = min(m_clock + m_settings->lookAhead, m_settings->maxLookAhead); const Vec3 predictedPos = m_desired.worldPos + (m_desired.vel * predictTime); const Vec3 predOffset = predictedPos - entityPos; const float predDist = predOffset.GetLength(); // Errors: m_lerpedError = entityPos - predictedPos; // Error between desired pos (nb: not predicted pos) const Vec3 errorToDesiredPos = entityPos - m_desired.worldPos; const int snapError = GetLerpError(errorToDesiredPos, m_lerpedError); m_clock += dt; const float lerpDist = predDist + (dt*velGround).GetLength(); if (lerpDist<m_settings->minLerpDistance && m_desired.vel.GetLengthSquared() < sqr(m_settings->minLerpSpeed) && !bInAirOrJumping) // Stop lerping { // This block should be entered as few times as possible while on a moving platform. predictionOut.predictedPos = predictedPos; predictionOut.lerpVel.zero(); predictionOut.shouldSnap = false; m_lerpedPos = m_desired.worldPos; m_lerpedError.zero(); if (m_snapType== eSnap_None) { predictionOut.shouldSnap = true; m_snapType = eSnap_Minor; LogSnapError(); } } else if (snapError & k_desiredError) // k_lerpError is ignored because it works improperly during collisions with living entities { predictionOut.predictedPos = m_desired.worldPos; predictionOut.lerpVel.zero(); predictionOut.shouldSnap = true; m_lerpedPos = m_desired.worldPos; m_lerpedError.zero(); if(errorToDesiredPos.GetLengthSquared() > sqr(m_settings->snapDistMarkedMajor)) { m_snapType = eSnap_Major; } else { m_snapType = eSnap_Normal; } LogSnapError(); } else { // Calculate simple lerp velocity Vec3 lerpVel = predOffset * (float)__fres(m_settings->lookAhead); // Clamp it const float maxPredictionDistance = m_settings->maxInterSpeed * m_settings->lookAhead; if (predDist > maxPredictionDistance) lerpVel *= maxPredictionDistance * (float)__fres(predDist); // Output predictionOut.predictedPos = predictedPos; predictionOut.lerpVel = lerpVel; predictionOut.shouldSnap = false; m_snapType = eSnap_None; } // Keep this in local space m_lerpedPos += dt * (predictionOut.lerpVel + velGround); m_lerpedPos += (m_desired.worldPos - m_lerpedPos) * 0.05f; // Keep on top of any drift }
//------------------------------------------------------------------------ void CGameRulesMPDamageHandling::SvOnCollision(const IEntity *pVictimEntity, const CGameRules::SCollisionHitInfo& collisionHitInfo) { FUNCTION_PROFILER(gEnv->pSystem, PROFILE_GAME); CRY_ASSERT(gEnv->bMultiplayer); #if !defined(_RELEASE) if (g_pGameCVars->g_DisableCollisionDamage) return; #endif IGameFramework* gameFramwork = g_pGame->GetIGameFramework(); EntityId victimID = pVictimEntity->GetId(); EntityId offenderID = collisionHitInfo.targetId; const IEntity* pOffenderEntity = gEnv->pEntitySystem->GetEntity(offenderID); float currentTime = gEnv->pTimer->GetCurrTime(); CActor* victimActor = static_cast<CActor*>(gameFramwork->GetIActorSystem()->GetActor(victimID)); IVehicle* offenderVehicle = gameFramwork->GetIVehicleSystem()->GetVehicle(offenderID); IVehicle* victimVehicle = gameFramwork->GetIVehicleSystem()->GetVehicle(victimID); IActor* offenderActor = gameFramwork->GetIActorSystem()->GetActor(offenderID); if(pOffenderEntity && !offenderVehicle && !offenderActor) { if( IEntity* pParent = pOffenderEntity->GetParent() ) { offenderVehicle = gameFramwork->GetIVehicleSystem()->GetVehicle(pParent->GetId()); } } // Vehicles being flipped do no damage, for now if (offenderVehicle != NULL && offenderVehicle->GetStatus().beingFlipped) return; // Players can't damage vehicles if (victimVehicle && offenderActor) return; // Filter frequent collisions if (pOffenderEntity) { FRAME_PROFILER("Filter out recent collisions", gEnv->pSystem, PROFILE_GAME); EntityCollisionRecords::const_iterator collisionRecordIter = m_entityCollisionRecords.find(victimID); if (collisionRecordIter != m_entityCollisionRecords.end()) { const EntityCollisionRecord& record = collisionRecordIter->second; if (record.entityID == offenderID && record.time + EntityCollisionIgnoreTimeBetweenCollisions > currentTime) { return; } } } float offenderMass = collisionHitInfo.target_mass; enum { CollisionWithEntity, CollisionWithStaticWorld } collisionType = (pOffenderEntity || offenderMass > 0.0f) ? CollisionWithEntity : CollisionWithStaticWorld; const Vec3& victimVelocity = collisionHitInfo.velocity; const Vec3& offenderVelocity = collisionHitInfo.target_velocity; float relativeSpeedSq = 0.0f; float minSpeedToCareAboutCollisionSq = 0.0f; float contactMass = 0.0f; bool offenderIsBig = offenderMass > 1000.f; switch (collisionType) { case CollisionWithEntity: { Vec3 relativeVelocity = victimVelocity - offenderVelocity; relativeSpeedSq = relativeVelocity.GetLengthSquared(); minSpeedToCareAboutCollisionSq = sqr(10.0f); if (victimActor && offenderIsBig) { minSpeedToCareAboutCollisionSq = sqr(1.0f); } if (victimActor && offenderVehicle) { //Players won't be hurt by vehicles with a negative kill player speed if(offenderVehicle->GetDamageParams().aiKillPlayerSpeed < 0.f) { return; } minSpeedToCareAboutCollisionSq = sqr(2.0f); } const float offenderSpeedSq = offenderVelocity.GetLengthSquared(); if (offenderSpeedSq == 0.0f) // -- if collision target it not moving { minSpeedToCareAboutCollisionSq *= sqr(2.0f); } ////////////////////////////////////////////////////////////////////////// contactMass = offenderMass; break; } case CollisionWithStaticWorld: { // Actors don't take damage from running into walls! if (victimActor) { return; } relativeSpeedSq = victimVelocity.GetLengthSquared(); minSpeedToCareAboutCollisionSq = sqr(7.5f); contactMass = collisionHitInfo.mass; break; } } const bool contactMassIsTooLowToCare = contactMass < 0.01f; if (contactMassIsTooLowToCare) return; ////////////////////////////////////////////////////////////////////////// // Calculate the collision damage if (relativeSpeedSq >= minSpeedToCareAboutCollisionSq) { bool useDefaultCalculation = true; float fEnergy = 0.f; float damage = 0.f; EntityId kickerId = 0; // Calculate damage if (offenderVehicle && victimActor) { useDefaultCalculation = false; damage = ProcessActorVehicleCollision(victimActor, victimID, offenderVehicle, offenderID, damage, collisionHitInfo, kickerId); } else if (offenderIsBig && victimActor) // i.e. a kickable car { // Try to find the kicker CTimeValue time = gEnv->pTimer->GetAsyncTime(); IActorSystem* pActorSystem = gEnv->pGame->GetIGameFramework()->GetIActorSystem(); IActorIteratorPtr pActorIterator = pActorSystem->CreateActorIterator(); IActor* pActor = pActorIterator->Next(); float lowestTime = 5.f; while (pActor != NULL) { CPlayer* pPlayer = static_cast<CPlayer*>(pActor); EntityId kicked = pPlayer->GetLargeObjectInteraction().GetLastObjectId(); if (kicked==offenderID) { float timeSinceKick = (time - pPlayer->GetLargeObjectInteraction().GetLastObjectTime()).GetSeconds(); if (timeSinceKick < lowestTime) { // We found the kicker and the kicked kickerId = pActor->GetEntityId(); lowestTime = timeSinceKick; } } pActor = pActorIterator->Next(); } damage = ProcessActorKickedVehicle(victimActor, victimID, kickerId, offenderID, damage, collisionHitInfo); useDefaultCalculation = false; } if (useDefaultCalculation) { fEnergy = GetCollisionEnergy(pVictimEntity, collisionHitInfo); if (victimVehicle || offenderIsBig) { damage = 0.0005f * fEnergy; } else { damage = 0.0025f * fEnergy; } // Apply damage multipliers damage *= GetCollisionDamageMult(pVictimEntity, pOffenderEntity, collisionHitInfo); if (victimActor) { const bool victimIsPlayer = victimActor->IsPlayer(); if (victimIsPlayer) { damage = AdjustPlayerCollisionDamage(pVictimEntity, pOffenderEntity, collisionHitInfo, damage); } } } if (damage >= DAMAGE_THRESHOLD_COLLISIONS) { HitInfo hit; hit.damage = damage; hit.pos = collisionHitInfo.pos; if (collisionHitInfo.target_velocity.GetLengthSquared() > 1e-6) hit.dir = collisionHitInfo.target_velocity.GetNormalized(); hit.radius = 0.0f; hit.partId = collisionHitInfo.partId; hit.targetId = victimID; hit.weaponId = offenderID; hit.shooterId = kickerId != 0 ? kickerId : offenderID; hit.material = 0; hit.type = CGameRules::EHitType::Collision; hit.explosion = false; CGameRules *pGameRules = g_pGame->GetGameRules(); if (pGameRules->GetTeamCount() > 1) { int shooterTeamId = pGameRules->GetTeam(hit.shooterId); int targetTeamId = pGameRules->GetTeam(hit.targetId); if (shooterTeamId && (shooterTeamId == targetTeamId)) { damage = GetFriendlyFireDamage(damage, hit, victimActor); } } if (damage >= DAMAGE_THRESHOLD_COLLISIONS) { IScriptTable* pVictimScript = pVictimEntity ? pVictimEntity->GetScriptTable() : NULL; IScriptTable* pOffenderScript = pOffenderEntity ? pOffenderEntity->GetScriptTable() : NULL; if (!pOffenderEntity && pVictimEntity) { pOffenderEntity = pVictimEntity; offenderID = victimID; } m_entityCollisionRecords[victimID] = EntityCollisionRecord(offenderID, currentTime); if(victimVehicle) { victimVehicle->OnHit(hit); } else if (pVictimScript) { FRAME_PROFILER("Call to OnHit", gEnv->pSystem, PROFILE_GAME); if (!IsDead(victimActor, pVictimScript)) { if (IActor* offenderDriver = offenderVehicle ? offenderVehicle->GetDriver() : NULL) hit.shooterId = offenderDriver->GetEntityId(); DelegateServerHit(pVictimScript, hit, victimActor); } } } } } }
void CMountedGunController::Update(EntityId mountedGunID, float frameTime) { CRY_ASSERT_MESSAGE(m_pControlledPlayer, "Controlled player not initialized"); CItem* pMountedGun = static_cast<CItem*>(gEnv->pGame->GetIGameFramework()->GetIItemSystem()->GetItem(mountedGunID)); bool canUpdateMountedGun = (pMountedGun != NULL) && (pMountedGun->GetStats().mounted); if (canUpdateMountedGun) { IMovementController * pMovementController = m_pControlledPlayer->GetMovementController(); assert(pMovementController); SMovementState info; pMovementController->GetMovementState(info); IEntity* pMountedGunEntity = pMountedGun->GetEntity(); const Matrix34& lastMountedGunWorldTM = pMountedGunEntity->GetWorldTM(); Vec3 desiredAimDirection = info.aimDirection.GetNormalized(); // AI can switch directions too fast, prevent snapping if(!m_pControlledPlayer->IsPlayer()) { const Vec3 currentDir = lastMountedGunWorldTM.GetColumn1(); const float dot = clamp(currentDir.Dot(desiredAimDirection), -1.0f, 1.0f); const float reqAngle = cry_acosf(dot); const float maxRotSpeed = 2.0f; const float maxAngle = frameTime * maxRotSpeed; if(fabs(reqAngle) > maxAngle) { const Vec3 axis = currentDir.Cross(desiredAimDirection); if(axis.GetLengthSquared() > 0.001f) // current dir and new dir are enough different { desiredAimDirection = currentDir.GetRotated(axis.GetNormalized(),sgn(reqAngle)*maxAngle); } } } bool isUserClient = m_pControlledPlayer->IsClient(); IEntity* pMountedGunParentEntity = pMountedGunEntity->GetParent(); IVehicle *pVehicle = NULL; if(pMountedGunParentEntity && m_pControlledPlayer) pVehicle = m_pControlledPlayer->GetLinkedVehicle(); CRecordingSystem* pRecordingSystem = g_pGame->GetRecordingSystem(); //For client update always, for others only when there is notable change if (!pVehicle && (isUserClient || (!desiredAimDirection.IsEquivalent(lastMountedGunWorldTM.GetColumn1(), 0.003f)))) { Quat rotation = Quat::CreateRotationVDir(desiredAimDirection, 0.0f); pMountedGunEntity->SetRotation(rotation); if (isUserClient && pRecordingSystem) { // Only record the gun position if you're using the gun. pRecordingSystem->OnMountedGunRotate(pMountedGunEntity, rotation); } } const Vec3 vInitialAimDirection = GetMountDirection(pMountedGun, pMountedGunParentEntity); assert( vInitialAimDirection.IsUnit() ); //Adjust gunner position and animations UpdateGunnerLocation(pMountedGun, pMountedGunParentEntity, vInitialAimDirection); const float aimrad = Ang3::CreateRadZ(Vec2(vInitialAimDirection),Vec2(-desiredAimDirection)); const float pitchLimit = sin_tpl(DEG2RAD(30.0f)); const float animHeight = fabs_tpl(clamp(desiredAimDirection.z * (float)__fres(pitchLimit), -1.0f, 1.0f)); const float aimUp = (float)__fsel(-desiredAimDirection.z, 0.0f, animHeight); const float aimDown = (float)__fsel(desiredAimDirection.z, 0.0f, animHeight); if (pRecordingSystem) { pRecordingSystem->OnMountedGunUpdate(m_pControlledPlayer, aimrad, aimUp, aimDown); } if(!m_pControlledPlayer->IsThirdPerson()) { UpdateFirstPersonAnimations(pMountedGun, desiredAimDirection); } if(m_pMovementAction) { const float aimUpParam = aimUp; const float aimDownParam = aimDown; const float aimMovementParam = CalculateAnimationTime(aimrad); m_pMovementAction->SetParam(MountedGunCRCs.aimUpParam, aimUpParam); m_pMovementAction->SetParam(MountedGunCRCs.aimDownParam, aimDownParam); m_pMovementAction->SetParam(MountedGunCRCs.aimMovementParam, aimMovementParam); } UpdateIKMounted(pMountedGun); } }
//------------------------------------------------------------------------ void CItem::UpdateMounted(float frameTime) { IRenderAuxGeom* pAuxGeom = gEnv->pRenderer->GetIRenderAuxGeom(); if (!m_ownerId || !m_stats.mounted) return; CActor *pActor = GetOwnerActor(); if (!pActor) return; CheckViewChange(); if (true) { if (IsClient()) { ICharacterInstance *pCharacter = GetEntity()->GetCharacter(eIGS_FirstPerson); if (pCharacter && !m_idleAnimation[eIGS_FirstPerson].empty() && pCharacter->GetISkeletonAnim()->GetNumAnimsInFIFO(0)<1) PlayAction(m_idleAnimation[eIGS_FirstPerson], 0, true); } // need to explicitly update characters at this point // cause the entity system update occered earlier, with the last position for (int i=0; i<eIGS_Last; i++) { if (GetEntity()->GetSlotFlags(i)&ENTITY_SLOT_RENDER) { ICharacterInstance *pCharacter = GetEntity()->GetCharacter(i); if (pCharacter) { Matrix34 mloc = GetEntity()->GetSlotLocalTM(i,false); Matrix34 m34 = GetEntity()->GetWorldTM()*mloc; QuatT renderLocation = QuatT(m34); pCharacter->GetISkeletonPose()->SetForceSkeletonUpdate(9); pCharacter->SkeletonPreProcess(renderLocation, renderLocation, GetISystem()->GetViewCamera(),0x55 ); pCharacter->SetPostProcessParameter(renderLocation, renderLocation, 0, 0.0f, 0x55 ); } } } // f32 fColor[4] = {1,1,0,1}; // f32 g_YLine=60.0f; // gEnv->pRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false, "Mounted Gun Code" ); //adjust the orientation of the gun based on the aim-direction SMovementState info; IMovementController* pMC = pActor->GetMovementController(); pMC->GetMovementState(info); Vec3 dir = info.aimDirection.GetNormalized(); Matrix34 tm = Matrix33::CreateRotationVDir(dir); Vec3 vGunXAxis=tm.GetColumn0(); if (pActor->GetLinkedVehicle()==0) { if (pMC) { if(!pActor->IsPlayer()) { // prevent snapping direction Vec3 currentDir = GetEntity()->GetWorldRotation().GetColumn1(); float dot = currentDir.Dot(dir); dot = CLAMP(dot,-1,1); float reqAngle = cry_acosf(dot); const float maxRotSpeed = 2.0f; float maxAngle = frameTime * maxRotSpeed; if(fabs(reqAngle) > maxAngle) { Vec3 axis = currentDir.Cross(dir); if(axis.GetLengthSquared()>0.001f) // current dir and new dir are enough different dir = currentDir.GetRotated(axis.GetNormalized(),sgn(reqAngle)*maxAngle); } } //adjust the orientation of the gun based on the aim-direction tm = Matrix33::CreateRotationVDir(dir); Vec3 vWPos=GetEntity()->GetWorldPos(); tm.SetTranslation(vWPos); GetEntity()->SetWorldTM(tm); //set the new orientation of the mounted gun vGunXAxis=tm.GetColumn0(); Vec3 vInitialAimDirection = m_stats.mount_dir; Matrix33 vInitialPlayerOrientation = Matrix33::CreateRotationVDir(vInitialAimDirection); assert( vInitialAimDirection.IsUnit() ); Vec3 newp; if (pActor->IsThirdPerson()) { //third person f32 dist = m_mountparams.body_distance*1.3f; Vec3 oldp = pActor->GetEntity()->GetWorldPos(); newp = GetEntity()->GetWorldPos()-vInitialAimDirection*dist; //mounted gun newp.z = oldp.z; } else { //first person f32 fMoveBack = (1.0f+(dir.z*dir.z*dir.z*dir.z*4.0f))*0.75f; f32 dist = m_mountparams.eye_distance*fMoveBack; Vec3 oldp = pActor->GetEntity()->GetWorldPos(); newp = GetEntity()->GetWorldPos()-dir*dist; //mounted gun //newp.z -= 0.75f; newp.z = oldp.z; } Matrix34 actortm(pActor->GetEntity()->GetWorldTM()); //if (pActor->IsThirdPerson()) actortm=vInitialPlayerOrientation; actortm.SetTranslation(newp); pActor->GetEntity()->SetWorldTM(actortm, ENTITY_XFORM_USER); pActor->GetAnimationGraphState()->SetInput("Action","gunnerMounted"); //f32 g_YLine=80.0f; //gEnv->pRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false, "Mounted Gun Active for FP and AI" ); if (ICharacterInstance *pCharacter = pActor->GetEntity()->GetCharacter(0)) { ISkeletonAnim *pSkeletonAnim = pCharacter->GetISkeletonAnim(); assert(pSkeletonAnim); uint32 numAnimsLayer = pSkeletonAnim->GetNumAnimsInFIFO(0); for(uint32 i=0; i<numAnimsLayer; i++) { CAnimation &animation = pSkeletonAnim->GetAnimFromFIFO(0, i); if (animation.m_AnimParams.m_nFlags & CA_MANUAL_UPDATE) { f32 aimrad = Ang3::CreateRadZ(Vec2(vInitialAimDirection),Vec2(dir)); animation.m_fAnimTime = clamp_tpl(aimrad/gf_PI,-1.0f,+1.0f)*0.5f+0.5f; //if (pActor->IsThirdPerson()==0) //animation.m_fAnimTime=0.6f; //Ivo & Benito: high advanced future code. don't ask what it is //Benito - Not needed any more ;) //f32 g_YLine=100.0f; //gEnv->pRenderer->Draw2dLabel( 1,g_YLine, 1.3f, fColor, false, "AnimTime: %f MyAimAngle: %f deg:% distance:%f", animation.m_fAnimTime, aimrad, RAD2DEG(aimrad),m_mountparams.body_distance ); } } } m_stats.mount_last_aimdir = dir; } } if (ICharacterInstance* pCharInstance = pActor->GetEntity()->GetCharacter(0)) { if (ISkeletonAnim* pSkeletonAnim = pCharInstance->GetISkeletonAnim()) { OldBlendSpace ap; if (GetAimBlending(ap)) { pSkeletonAnim->SetBlendSpaceOverride(eMotionParamID_TurnSpeed, 0.5f + 0.5f * ap.m_turn, true); } } } UpdateIKMounted(pActor, vGunXAxis*0.1f); RequireUpdate(eIUS_General); } }
void CPlayerView::ViewSpectatorTarget(SViewParams &viewParams) { CActor* pTarget = (CActor*)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.stats_spectatorTarget); if(!pTarget) return; IVehicle* pVehicle = pTarget->GetLinkedVehicle(); static float defaultOffset = 0.3f; static float viewHeight = 1.8f; Matrix34 worldTM = pTarget->GetEntity()->GetWorldTM(); Vec3 worldPos = worldTM.GetTranslation(); if(!pVehicle) { const SStanceInfo* stanceInfo = pTarget->GetStanceInfo(pTarget->GetStance()); if(stanceInfo) { Interpolate(viewHeight, stanceInfo->viewOffset.z, 5.0f, viewParams.frameTime); worldPos.z += viewHeight + defaultOffset; } else { worldPos.z += 1.8f; } } else { // use vehicle pos/ori worldTM = pVehicle->GetEntity()->GetWorldTM(); worldPos = pVehicle->GetEntity()->GetWorldPos(); worldPos.z += 1.5f; } Ang3 worldAngles = Ang3::GetAnglesXYZ(Matrix33(worldTM)); float distance = 3; // if freelook allowed, get orientation and distance from player entity if(g_pGameCVars->g_spectate_FixedOrientation == 0) { CPlayer* pThisPlayer = static_cast<CPlayer*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.entityId)); if(!pThisPlayer) return; Matrix34 ownOrientation = pThisPlayer->GetEntity()->GetWorldTM(); worldAngles += Ang3::GetAnglesXYZ(Matrix33(ownOrientation)); distance = pThisPlayer->GetSpectatorZoom(); } if(pVehicle) { distance *= 4.0f; // air vehicles need bigger distance if(pVehicle->GetMovement() && pVehicle->GetMovement()->GetMovementType() == IVehicleMovement::eVMT_Air) distance *= 2.0f; } Vec3 goal; goal.x = distance * cos(worldAngles.z + gf_PI*1.5f) + worldPos.x; goal.y = distance * sin(worldAngles.z - gf_PI/2.0f) + worldPos.y; AABB targetBounds; pTarget->GetEntity()->GetLocalBounds(targetBounds); goal.z = targetBounds.max.z; float offset = defaultOffset; if(pVehicle) { if(pVehicle->GetMovement() && pVehicle->GetMovement()->GetMovementType() == IVehicleMovement::eVMT_Air) offset = 3.0f; else offset = 1.0f; } goal.z += pTarget->GetEntity()->GetWorldPos().z + offset; // store / interpolate the offset, not the world pos (reduces percieved jitter in vehicles) static Vec3 viewOffset(goal-worldPos); static Vec3 camPos(goal); static Vec3 entPos(worldPos); static EntityId lastSpectatorTarget(m_in.stats_spectatorTarget); // do a ray cast to check for camera intersection static ray_hit hit; IPhysicalEntity* pSkipEntities[10]; int nSkip = 0; if(pVehicle) { // vehicle drivers don't seem to have current items, so need to add the vehicle itself here nSkip = pVehicle->GetSkipEntities(pSkipEntities, 10); } else { IItem* pItem = pTarget->GetCurrentItem(); if (pItem) { CWeapon* pWeapon = (CWeapon*)pItem->GetIWeapon(); if (pWeapon) nSkip = CSingle::GetSkipEntities(pWeapon, pSkipEntities, 10); } } static float minDist = 0.4f; // how close we're allowed to get to the target static float wallSafeDistance = 0.3f; // how far to keep camera from walls Vec3 dir = goal - worldPos; primitives::sphere sphere; sphere.center = worldPos; sphere.r = wallSafeDistance; geom_contact *pContact = 0; float hitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, dir, 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, nSkip); // even when we have contact, keep the camera the same height above the target float minHeightDiff = dir.z; if(hitDist > 0 && pContact) { goal = worldPos + (hitDist * dir.GetNormalizedSafe()); if(goal.z - worldPos.z < minHeightDiff) { // can't move the camera far enough away from the player in this direction. Try moving it directly up a bit int numHits = 0; sphere.center = goal; // (move back just slightly to avoid colliding with the wall we've already found...) sphere.center -= dir.GetNormalizedSafe() * 0.05f; float newHitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, Vec3(0,0,minHeightDiff), 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, nSkip); float raiseDist = minHeightDiff - (goal.z - worldPos.z) - wallSafeDistance; if(newHitDist != 0) { raiseDist = MIN(minHeightDiff, newHitDist); } raiseDist = MAX(0.0f, raiseDist); goal.z += raiseDist; worldPos.z += raiseDist*0.8f; } } int thisFrameId = gEnv->pRenderer->GetFrameID(); static int frameNo(thisFrameId); if(thisFrameId - frameNo > 5) { // reset positions viewOffset = goal - worldPos; entPos = worldPos; camPos = goal; } if(lastSpectatorTarget != m_in.stats_spectatorTarget) { viewOffset = goal - worldPos; entPos = worldPos; camPos = goal; lastSpectatorTarget = m_in.stats_spectatorTarget; } frameNo = thisFrameId; static float interpSpeed = 5.0f; static float interpSpeed2 = 5.0f; static float interpSpeed3 = 8.0f; if(pVehicle) { Interpolate(viewOffset, goal-worldPos, interpSpeed, viewParams.frameTime); entPos = worldPos; viewParams.position = worldPos + viewOffset; camPos = viewParams.position; } else { Vec3 camPosChange = goal - camPos; Vec3 entPosChange = worldPos - entPos; if(camPosChange.GetLengthSquared() > 100.0f) camPos = goal; if(entPosChange.GetLengthSquared() > 100.0f) entPos = worldPos; Interpolate(camPos, goal, interpSpeed2, viewParams.frameTime); Interpolate(entPos, worldPos, interpSpeed3, viewParams.frameTime); viewParams.position = camPos; } Matrix33 rotation = Matrix33::CreateRotationVDir((entPos - viewParams.position).GetNormalizedSafe()); viewParams.rotation = GetQuatFromMat33(rotation); m_io.bUsePivot = true; m_io.stats_bobCycle = 0.0; }
void CPlayerView::ViewSpectatorTarget(SViewParams &viewParams) { CActor *pTarget = (CActor *)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_in.stats_spectatorTarget); if(!pTarget) { return; } Matrix34 worldTM = pTarget->GetEntity()->GetWorldTM(); Vec3 worldPos = worldTM.GetTranslation(); worldPos.z += 1.5f; Ang3 worldAngles = Ang3::GetAnglesXYZ(Matrix33(worldTM)); float rot = worldAngles.z;// + m_rot; float distance = 3;//(m_defaultDistance != 0) ? m_defaultDistance : m_distance; if(IVehicle *pVehicle = pTarget->GetLinkedVehicle()) { AABB vehicleBox; pVehicle->GetEntity()->GetLocalBounds(vehicleBox); distance = 2.0f * vehicleBox.GetRadius(); } Vec3 goal; float zoom = 1.0f; goal.x = distance * zoom * cosf(rot + gf_PI * 1.5f) + worldPos.x; goal.y = distance * zoom * sinf(rot - gf_PI / 2.0f) + worldPos.y; AABB targetBounds; pTarget->GetEntity()->GetLocalBounds(targetBounds); goal.z = targetBounds.max.z; static float defaultOffset = 0.75f; float offset = defaultOffset; if(pTarget->GetLinkedVehicle()) { offset = 2.0f; } goal.z += pTarget->GetEntity()->GetWorldPos().z + offset; // store / interpolate the offset, not the world pos (reduces percieved jitter in vehicles) static Vec3 viewOffset(goal - worldPos); static Vec3 position(goal); static Vec3 entPos(worldPos); static EntityId lastSpectatorTarget(m_in.stats_spectatorTarget); // do a ray cast to check for camera intersection static ray_hit hit; IPhysicalEntity *pSkipEntities[10]; int nSkip = 0; IItem *pItem = pTarget->GetCurrentItem(); if (pItem) { CWeapon *pWeapon = (CWeapon *)pItem->GetIWeapon(); if (pWeapon) { nSkip = CSingle::GetSkipEntities(pWeapon, pSkipEntities, 10); } } else if(IVehicle *pVehicle = pTarget->GetLinkedVehicle()) { // vehicle drivers don't seem to have current items, so need to add the vehicle itself here nSkip = pVehicle->GetSkipEntities(pSkipEntities, 10); } const float wallSafeDistance = 0.2f; // how far to keep camera from walls Vec3 dir = goal - worldPos; primitives::sphere sphere; sphere.center = worldPos; sphere.r = wallSafeDistance; geom_contact *pContact = 0; float hitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, dir, ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, geom_colltype_player, 0, 0, 0, pSkipEntities, nSkip); // even when we have contact, keep the camera the same height above the target float minHeightDiff = dir.z; if(hitDist > 0 && pContact) { goal = worldPos + (hitDist * dir.GetNormalizedSafe()); if(goal.z - worldPos.z < minHeightDiff) { // can't move the camera far enough away from the player in this direction. Try moving it directly up a bit sphere.center = goal; // (move back just slightly to avoid colliding with the wall we've already found...) sphere.center -= dir.GetNormalizedSafe() * 0.05f; float newHitDist = gEnv->pPhysicalWorld->PrimitiveWorldIntersection(sphere.type, &sphere, Vec3(0, 0, minHeightDiff), ent_static | ent_terrain | ent_rigid | ent_sleeping_rigid, &pContact, 0, geom_colltype_player, 0, 0, 0, pSkipEntities, nSkip); float raiseDist = minHeightDiff - (goal.z - worldPos.z) - wallSafeDistance; if(newHitDist != 0) { raiseDist = MIN(minHeightDiff, newHitDist); } raiseDist = MAX(0.0f, raiseDist); goal.z += raiseDist; worldPos.z += raiseDist * 0.8f; } } int thisFrameId = gEnv->pRenderer->GetFrameID(); static int frameNo(thisFrameId); if(thisFrameId - frameNo > 5) { // reset positions viewOffset = goal - worldPos; entPos = worldPos; position = goal; } if(lastSpectatorTarget != m_in.stats_spectatorTarget) { viewOffset = goal - worldPos; entPos = worldPos; position = goal; lastSpectatorTarget = m_in.stats_spectatorTarget; } frameNo = thisFrameId; if(pTarget->GetLinkedVehicle()) { Interpolate(viewOffset, goal - worldPos, 5.0f, viewParams.frameTime); entPos = worldPos; viewParams.position = worldPos + viewOffset; position = viewParams.position; } else { Vec3 camPosChange = goal - position; Vec3 entPosChange = worldPos - entPos; if(camPosChange.GetLengthSquared() > 100.0f) { position = goal; } if(entPosChange.GetLengthSquared() > 100.0f) { entPos = worldPos; } Interpolate(position, goal, 5.0f, viewParams.frameTime); Interpolate(entPos, worldPos, 5.0f, viewParams.frameTime); viewParams.position = position; } Matrix33 rotation = Matrix33::CreateRotationVDir((entPos - viewParams.position).GetNormalizedSafe()); viewParams.rotation = Quat(rotation); m_io.bUsePivot = true; m_io.stats_bobCycle = 0.0; }
bool CMPTutorial::CheckNearbyEntities(const CPlayer *pPlayer) { FUNCTION_PROFILER(GetISystem(), PROFILE_GAME); // checks for: // eTE_NeutralFactory // eTE_CaptureFactory // eTE_EnterHostileFactory // eTE_EnterPrototypeFactory // eTE_ApproachEnemyBase // eTE_ApproachEnemyHQ // eTE_DestroyEnemyHQ // eTE_CaptureAlienSite // If none of these need checking, don't bother. if(! ( m_events[eTE_NeutralFactory].m_status == eMS_Checking || m_events[eTE_CaptureFactory].m_status == eMS_Checking || m_events[eTE_EnterHostileFactory].m_status == eMS_Checking || m_events[eTE_EnterPrototypeFactory].m_status == eMS_Checking || m_events[eTE_ApproachEnemyBase].m_status == eMS_Checking || m_events[eTE_ApproachEnemyHq].m_status == eMS_Checking || m_events[eTE_CaptureAlienSite].m_status == eMS_Checking || m_events[eTE_AllAliensNoPrototype].m_status == eMS_Checking || m_events[eTE_AlienNoPrototype].m_status == eMS_Checking )) { return false; } bool showPrompt = false; if(!pPlayer) return showPrompt; Vec3 playerPos = pPlayer->GetEntity()->GetWorldPos(); int playerTeam = g_pGame->GetGameRules()->GetTeam(pPlayer->GetEntityId()); // rewritten to avoid iterating through the entity list: cached lists of HQ / energy point / spawn groups bool allCrashSites = true; // does the player's team own all crash sites bool PTFactory = false; // does the player's team own the PT factory bool nearCrashSite = false; // is the player near a crash site for(std::list<EntityId>::iterator it = m_alienEnergyPointList.begin(); it != m_alienEnergyPointList.end(); ++it) { EntityId eid = *it; // check team if(playerTeam != g_pGame->GetGameRules()->GetTeam(eid)) allCrashSites = false; IEntity* pEnt = gEnv->pEntitySystem->GetEntity(eid); if(pEnt) { Vec3 vec = pEnt->GetWorldPos() - playerPos; float distanceSq = vec.GetLengthSquared(); if(distanceSq < 500.0f && g_pGame->GetGameRules()->GetTeam(pEnt->GetId()) == playerTeam) { showPrompt = TriggerEvent(eTE_CaptureAlienSite); nearCrashSite = true; } } } if(m_events[eTE_AllAliensNoPrototype].m_status == eMS_Checking || m_events[eTE_AlienNoPrototype].m_status == eMS_Checking) { // if player's team doesn't own the PT factory, they get an additional message... for(std::list<EntityId>::iterator factIt = m_factoryList.begin(); factIt != m_factoryList.end(); ++factIt) { EntityId factoryId = *factIt; if(g_pGame->GetHUD()) { if(g_pGame->GetHUD()->GetPowerStruggleHUD()->IsFactoryType(factoryId, CHUDPowerStruggle::E_PROTOTYPES)) { if(g_pGame->GetGameRules()->GetTeam(factoryId) == playerTeam) { PTFactory = true; } } } } if(!PTFactory) { if(allCrashSites) { // player's team owns all aliens but not the factory TriggerEvent(eTE_AllAliensNoPrototype); } else if(nearCrashSite) { // player has captured an alien but not yet the prototype factory. TriggerEvent(eTE_AlienNoPrototype); } } } if(!showPrompt && m_events[eTE_ApproachEnemyBase].m_status == eMS_Checking) { std::list<EntityId>::iterator it = m_baseList.begin(); for(; it != m_baseList.end(); ++it) { IEntity* pEnt = gEnv->pEntitySystem->GetEntity(*it); if(pEnt) { Vec3 vec = pEnt->GetWorldPos() - playerPos; float distanceSq = vec.GetLengthSquared(); int team = g_pGame->GetGameRules()->GetTeam(pEnt->GetId()); if(team != playerTeam) { if(distanceSq < 10000.0f) showPrompt = TriggerEvent(eTE_ApproachEnemyBase); } } } } if(!showPrompt && m_events[eTE_SpawnBunker].m_status == eMS_Checking) { std::list<EntityId>::iterator it = m_spawnGroupList.begin(); for(; it != m_spawnGroupList.end(); ++it) { IEntity* pEnt = gEnv->pEntitySystem->GetEntity(*it); if(pEnt) { Vec3 vec = pEnt->GetWorldPos() - playerPos; float distanceSq = vec.GetLengthSquared(); if(distanceSq <= 80.0f) { if(g_pGame->GetGameRules()->GetTeam(pEnt->GetId()) == 0) showPrompt = TriggerEvent(eTE_SpawnBunker); } } } } if(!showPrompt) { std::list<EntityId>::iterator it = m_factoryList.begin(); for(; it != m_factoryList.end(); ++it) { IEntity* pEnt = gEnv->pEntitySystem->GetEntity(*it); if(pEnt) { Vec3 vec = pEnt->GetWorldPos() - playerPos; float distanceSq = vec.GetLengthSquared(); if(distanceSq < 500.0f) { // prompt depends on team and factory type bool inPrototypeFactory = g_pGame->GetHUD()->GetPowerStruggleHUD()->IsFactoryType(pEnt->GetId(), CHUDPowerStruggle::E_PROTOTYPES); int team = g_pGame->GetGameRules()->GetTeam(pEnt->GetId()); if(team == 0) { showPrompt = TriggerEvent(eTE_NeutralFactory); } else if(team != playerTeam) { showPrompt = TriggerEvent(eTE_EnterHostileFactory); } else // team == playerTeam { showPrompt = TriggerEvent(eTE_CaptureFactory); if(inPrototypeFactory) { showPrompt |= TriggerEvent(eTE_EnterPrototypeFactory); } } } } } } return showPrompt; }
//------------------------------------------------------------------------ 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 CIntersectionAssistanceUnit::IsPositionWithinAcceptedLimits(const Vec3& vTestPos, const Vec3& vOrigin, const float fTolerance) const { const Vec3 vDiff = vTestPos - vOrigin; return (vDiff.GetLengthSquared() < (fTolerance * fTolerance)); }
//--------------------------------------------------------------------------- IEntity* CFireModePlugin_AutoAim::CalculateBestProjectileAutoAimTarget(const Vec3& attackerPos, const Vec3& attackerDir, const bool bCurrentlyZoomed, const EntityId ownerId) const { #if ALLOW_PROJECTILEHELPER_DEBUGGING static const ColorB red(127,0,0); static const ColorB green(0,127,0); static const ColorB brightGreen(0,255,0); static const float s_sphereDebugRad = 0.15f; #endif IEntity* pBestTarget = NULL; float fBestScore = 0.0f; const TAutoaimTargets& players = g_pGame->GetAutoAimManager().GetAutoAimTargets(); // Cache commonly required constants for scoring const ConeParams& aimConeSettings = GetAimConeSettings(bCurrentlyZoomed); const float minAutoAimDistSqrd = cry_sqr(aimConeSettings.m_minDistance); const float maxAutoAimDistSqrd = cry_sqr(aimConeSettings.m_maxDistance); const float coneSizeRads = aimConeSettings.m_outerConeRads; IEntitySystem* pEntitySystem = gEnv->pEntitySystem; CPlayerVisTable* pVisTable = g_pGame->GetPlayerVisTable(); const float distanceConstant = __fres(max(aimConeSettings.m_maxDistance, FLT_EPSILON)); const float coneAngleConstant = __fres(max(coneSizeRads*0.5f, FLT_EPSILON)); // For each potential target we do a dist + cone check TAutoaimTargets::const_iterator endIter = players.end(); for(TAutoaimTargets::const_iterator iter = players.begin(); iter != endIter; ++iter) { // If entity exists and we are allowed to target them EntityId targetEntityId = iter->entityId; IEntity* pEntity = pEntitySystem->GetEntity(targetEntityId); if(pEntity && AllowedToTargetPlayer(ownerId,targetEntityId)) { // If further than allowed dist, discard Vec3 targetTestPos; // Test against primary Auto aim position const SAutoaimTarget* pAutoAimInfo = g_pGame->GetAutoAimManager().GetTargetInfo(targetEntityId); if(pAutoAimInfo) { targetTestPos = pAutoAimInfo->primaryAimPosition; } else { // Then ABBB centre as backup IEntityPhysicalProxy* pPhysProxy = static_cast<IEntityPhysicalProxy*>(pEntity->GetProxy(ENTITY_PROXY_PHYSICS)); if(pPhysProxy) { AABB aabb; pPhysProxy->GetWorldBounds(aabb); targetTestPos = aabb.GetCenter(); } else { targetTestPos = pEntity->GetWorldPos(); } } Vec3 toTarget = targetTestPos - attackerPos; float distSqrd = toTarget.GetLengthSquared(); if( distSqrd >= minAutoAimDistSqrd && distSqrd <= maxAutoAimDistSqrd ) { // If not within cone.. discard float theta = 0.0f; if(TargetPositionWithinFrontalCone(attackerPos,targetTestPos, attackerDir,coneSizeRads, theta)) { // If cant see them .. next if(!pVisTable->CanLocalPlayerSee(targetEntityId, 5)) { #if ALLOW_PROJECTILEHELPER_DEBUGGING m_lastTargetRejectionReason.append("VISION BLOCKED"); #endif // #if ALLOW_PROJECTILEHELPER_DEBUGGING continue; } // For each candidate, generate their Auto Aim score. // 1) [0.0f,1.0f] score comprised of DISTANCE based score (closer is better) float targetDistScore = 1.0f - ( sqrtf(distSqrd) * distanceConstant ); // Lets try squaring this to make candidates with only small gaps between them reflect distance scoring better and reduce the importance of distance at super long ranges targetDistScore *= targetDistScore; // 2) + [0.0f,1.0f] cone based score (central is better) const float targetConeScore = 1.0f - ( theta * coneAngleConstant ); // Factor in designer controlled multipliers const float finalScore = (targetDistScore * g_pGameCVars->pl_pickAndThrow.chargedThrowAutoAimDistanceHeuristicWeighting) + // TODO - move these weightings into params (targetConeScore * g_pGameCVars->pl_pickAndThrow.chargedThrowAutoAimAngleHeuristicWeighting); if(finalScore > fBestScore) { fBestScore = finalScore; pBestTarget = pEntity; } // Debug rendering! #if ALLOW_PROJECTILEHELPER_DEBUGGING if(g_pGameCVars->pl_debug_projectileAimHelper) { CryWatch("Entity [%s - %d] DistScore [%.2f] , ConeScore[%.2f], totalScore [%.3f]", pEntity->GetName(), pEntity->GetId(), targetDistScore, targetConeScore, finalScore); // Draw a green sphere to indicate valid gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(targetTestPos, s_sphereDebugRad,green); } #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING } #if ALLOW_PROJECTILEHELPER_DEBUGGING else { m_lastTargetRejectionReason.Format("OUTSIDE CONE [%.3f]",RAD2DEG(theta)); if(g_pGameCVars->pl_debug_projectileAimHelper) { // Draw a red sphere to indicate not valid gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(targetTestPos, s_sphereDebugRad, red); } } #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING } #if ALLOW_PROJECTILEHELPER_DEBUGGING else { if(distSqrd >= minAutoAimDistSqrd) { m_lastTargetRejectionReason.Format("TOO CLOSE [%.3f]", cry_sqrtf_fast(distSqrd)); } else { m_lastTargetRejectionReason.Format("TOO FAR [%.3f]",cry_sqrtf_fast(distSqrd)); } } #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING } } // Draw a Really bright sphere on BEST target #if ALLOW_PROJECTILEHELPER_DEBUGGING if(pBestTarget && g_pGameCVars->pl_debug_projectileAimHelper) { // If further than allowed dist, discard Vec3 targetTestPos = pBestTarget->GetPos(); // We use aabb centre to reduce error IEntityPhysicalProxy* pPhysProxy = static_cast<IEntityPhysicalProxy*>(pBestTarget->GetProxy(ENTITY_PROXY_PHYSICS)); if(pPhysProxy) { AABB aabb; pPhysProxy->GetWorldBounds(aabb); targetTestPos = aabb.GetCenter(); } // Draw a bright green sphere to indicate target chosen gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(targetTestPos, s_sphereDebugRad*1.05f, brightGreen); } #endif //#if ALLOW_PROJECTILEHELPER_DEBUGGING return pBestTarget; }