void CAICorpseManager::DebugDraw() { if(g_pGameCVars->g_aiCorpses_DebugDraw == 0) return; IRenderAuxGeom* pRenderAux = gEnv->pRenderer->GetIRenderAuxGeom(); gEnv->pRenderer->Draw2dLabel( 50.0f, 50.0f, 1.5f, Col_White, false, "Corpse count %" PRISIZE_T " - Max %d", m_corpsesArray.size(), m_maxCorpses ); for(size_t i = 0; i < m_corpsesArray.size(); ++i) { CorpseInfo& corpse = m_corpsesArray[i]; CAICorpse* pCorpse = corpse.GetCorpse(); if(pCorpse != NULL) { AABB corpseBbox; pCorpse->GetEntity()->GetWorldBounds(corpseBbox); const Vec3 refPosition = corpseBbox.IsEmpty() ? pCorpse->GetEntity()->GetWorldPos() : corpseBbox.GetCenter(); gEnv->pRenderer->DrawLabel( refPosition, 1.5f, "%s\nPriority %d\n%s\n%s", pCorpse->GetEntity()->GetName(), pCorpse->GetPriority(), corpse.flags.AreAnyFlagsActive( CorpseInfo::eFlag_FarAway ) ? "Far away, remove when not visible" : "Not far away", corpse.flags.AreAllFlagsActive( CorpseInfo::eFlag_PhysicsDisabled) ? "Physics disabled" : "Physics enabled" ); pRenderAux->DrawCone( refPosition + Vec3(0.0f, 0.0f, 1.5f), Vec3(0.0f, 0.0f, -1.0f), 0.3f, 0.8f, Col_Red ); } } }
//------------------------------------------------------------------------ int CScriptBind_Game::RegisterWithAutoAimManager(IFunctionHandler *pH, ScriptHandle entityId, float innerRadiusFactor, float outerRadiusFactor, float snapRadiusFactor) { IEntity* pEntity = gEnv->pEntitySystem->GetEntity((EntityId)entityId.n); if (pEntity) { AABB entityBbox; pEntity->GetWorldBounds(entityBbox); const float entityRadius = (entityBbox.IsEmpty() == false) ? entityBbox.GetRadius() : 1.0f; SAutoaimTargetRegisterParams registerParams; registerParams.fallbackOffset = 0.0f; registerParams.innerRadius = entityRadius * innerRadiusFactor; registerParams.outerRadius = entityRadius * outerRadiusFactor; registerParams.snapRadius = entityRadius * snapRadiusFactor; registerParams.snapRadiusTagged = entityRadius; registerParams.primaryBoneId = -1; registerParams.physicsBoneId = -1; registerParams.secondaryBoneId = -1; g_pGame->GetAutoAimManager().RegisterAutoaimTargetObject((EntityId)entityId.n, registerParams); } return pH->EndFunction(); }
void CAutoAimManager::UpdateTargetInfo(SAutoaimTarget& aaTarget, float fFrameTime) { IEntity * pTargetEntity = gEnv->pEntitySystem->GetEntity(aaTarget.entityId); if(pTargetEntity) { CActorPtr pTargetActor = aaTarget.pActorWeak.lock(); if (pTargetActor) { Vec3 characterPos; Quat characterRot; //Need this because of decouple catch-up movement if (IAnimatedCharacter* pAnimatedCharacter = pTargetActor->GetAnimatedCharacter()) { const QuatT& animationLocation = pAnimatedCharacter->GetAnimLocation(); characterPos = animationLocation.t; characterRot = animationLocation.q; } else { const Matrix34& targetWorldTM = pTargetEntity->GetWorldTM(); //Fallback to entity position characterPos = targetWorldTM.GetTranslation(); characterRot = Quat(targetWorldTM); } Vec3 primaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); Vec3 secondaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); if (aaTarget.primaryBoneId >= 0) { if (pTargetActor->HasBoneID(aaTarget.primaryBoneId)) { primaryOffset = pTargetActor->GetBoneTransform(aaTarget.primaryBoneId).t; } else { GameWarning("CAutoAimManager: Character %s missing primary boneID: %s", pTargetEntity->GetName(), s_BONE_ID_NAME[aaTarget.primaryBoneId]); aaTarget.primaryBoneId = -1; } } if (aaTarget.secondaryBoneId >= 0) { if (pTargetActor->HasBoneID(aaTarget.secondaryBoneId)) { secondaryOffset = pTargetActor->GetBoneTransform(aaTarget.secondaryBoneId).t; } else { GameWarning("CAutoAimManager: Character %s missing secondary boneID: %s", pTargetEntity->GetName(), s_BONE_ID_NAME[aaTarget.secondaryBoneId]); aaTarget.secondaryBoneId = -1; } } aaTarget.primaryAimPosition = characterPos + (characterRot * primaryOffset); aaTarget.secondaryAimPosition = characterPos + (characterRot * secondaryOffset); //Update hostility (changes during gameplay) if (!gEnv->bMultiplayer) { uint8 targetFaction = (aaTarget.aiFaction != IFactionMap::InvalidFactionID) ? aaTarget.aiFaction : GetTargetFaction(*pTargetEntity); if (gEnv->pAISystem->GetFactionMap().GetReaction(GetLocalPlayerFaction(), aaTarget.aiFaction) == IFactionMap::Hostile) { aaTarget.SetFlag(eAATF_AIHostile); } else { aaTarget.RemoveFlag(eAATF_AIHostile); } aaTarget.aiFaction = targetFaction; } } else if(aaTarget.hasSkeleton) { //Not an actor but has a skeleton (and so can use bone offsets) ISkeletonPose* pSkeletonPose = pTargetEntity->GetCharacter(0)->GetISkeletonPose(); const Matrix34& characterMat = pTargetEntity->GetWorldTM(); const Vec3 characterPos = characterMat.GetTranslation(); const Quat characterRot(characterMat); Vec3 primaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); Vec3 secondaryOffset(0.0f, 0.0f, aaTarget.fallbackOffset); if (aaTarget.primaryBoneId >= 0) { primaryOffset = pSkeletonPose->GetAbsJointByID(aaTarget.primaryBoneId).t; } if (aaTarget.secondaryBoneId >= 0) { secondaryOffset = pSkeletonPose->GetAbsJointByID(aaTarget.secondaryBoneId).t; } aaTarget.primaryAimPosition = characterPos + (characterRot * primaryOffset); aaTarget.secondaryAimPosition = characterPos + (characterRot * secondaryOffset); } else { //Must be an object const Matrix34& entityWorldTM = pTargetEntity->GetWorldTM(); Vec3 primaryPosition = entityWorldTM.GetTranslation(); Vec3 secondaryPosition = entityWorldTM.TransformPoint(Vec3(0.0f, 0.0f, 0.5f)); AABB entityLocalBBox; pTargetEntity->GetLocalBounds(entityLocalBBox); if (!entityLocalBBox.IsEmpty()) { const Vec3 offset (0.0f, 0.0f, entityLocalBBox.GetRadius() * 0.2f); const Vec3 objectCenter = entityLocalBBox.GetCenter(); primaryPosition = entityWorldTM.TransformPoint((objectCenter - offset)); secondaryPosition = entityWorldTM.TransformPoint((objectCenter + offset)); } aaTarget.primaryAimPosition = primaryPosition; aaTarget.secondaryAimPosition = secondaryPosition; } //The physics drags the render proxy and entity behind it. If we auto aim at the render position, // we will handicap the console players by failing to let them aim ahead of the target. if(IPhysicalEntity * pPhysicalEntity = pTargetEntity->GetPhysics()) { pe_status_dynamics dyn; if(pPhysicalEntity->GetStatus(&dyn)) { Vec3 lookAhead = (dyn.v * fFrameTime); aaTarget.primaryAimPosition = aaTarget.primaryAimPosition + lookAhead; aaTarget.secondaryAimPosition = aaTarget.secondaryAimPosition + lookAhead; } } } }
//------------------------------------------------------------------------ bool CTracer::Update(float frameTime, const Vec3 &camera, const float fovScale) { frameTime = (float)__fsel(-m_age, 0.002f, frameTime); const float tracerAge = (float)__fsel(-m_age, 0.002f, m_age+frameTime); m_age = tracerAge; if (tracerAge >= m_lifeTime) return false; Vec3 currentLimitDestination; if (gEnv->bMultiplayer) { if(m_tracerFlags & kTracerFlag_updateDestFromBullet) { IEntity* pBulletEntity = gEnv->pEntitySystem->GetEntity(m_boundToBulletId); if(pBulletEntity) { m_dest = pBulletEntity->GetPos(); } } currentLimitDestination = m_dest; } else { IEntity* pBulletEntity = gEnv->pEntitySystem->GetEntity(m_boundToBulletId); currentLimitDestination = pBulletEntity ? pBulletEntity->GetPos() : m_dest; } const Vec3 maxTravelledDistance = m_dest - m_startingPos; const float maxTravelledDistanceSqr = maxTravelledDistance.len2(); float dist = sqrt_tpl(maxTravelledDistanceSqr); if (dist <= 0.001f) return false; const Vec3 dir = maxTravelledDistance * (float)__fres(dist); Vec3 pos = m_pos; float lengthScale = 1.f; Vec3 newPos = m_pos; if (!(m_tracerFlags & kTracerFlag_dontTranslate)) { const float sqrRadius = GetGameConstCVar(g_tracers_slowDownAtCameraDistance) * GetGameConstCVar(g_tracers_slowDownAtCameraDistance); const float cameraDistance = (m_pos-camera).len2(); const float speed = m_speed * (float)__fsel(sqrRadius - cameraDistance, 0.35f + (cameraDistance/(sqrRadius*2)), 1.0f); //Slow down tracer when near the player newPos += dir * min(speed*frameTime, dist); pos = newPos; if(m_slideFrac > 0.f) { pos += (((2.f * cry_frand()) - 0.5f) * m_slideFrac * speed * frameTime * dir); } } // Now update visuals... if (IEntity *pEntity = gEnv->pEntitySystem->GetEntity(m_entityId)) { AABB tracerBbox; pEntity->GetWorldBounds(tracerBbox); float tracerHalfLength = !tracerBbox.IsEmpty() ? tracerBbox.GetRadius() : 0.0f; const Vec3 frontOfTracerPos = pos + (dir * tracerHalfLength); if((frontOfTracerPos-m_startingPos).len2() > maxTravelledDistanceSqr) { return false; } if (!(m_tracerFlags & kTracerFlag_dontTranslate) && tracerHalfLength > 0.f) { //Ensure that never goes in front of the bullet const Vec3 dirFromFrontOfTracerToDestination = currentLimitDestination - frontOfTracerPos; if (dir.dot(dirFromFrontOfTracerToDestination) < 0) { pos += dirFromFrontOfTracerToDestination; } // ... and check if back of tracer is behind starting point, so adjust length. const Vec3 backOfTracerPos = pos - (dir * tracerHalfLength); const Vec3 dirFromBackOfTracerToStart = m_startingPos - backOfTracerPos; if (dir.dot(dirFromBackOfTracerToStart) > 0) { if(dir.dot((m_startingPos - pos)) > 0) { pos = m_startingPos + (dir * cry_frand() * tracerHalfLength); } lengthScale = ((pos - m_startingPos).GetLength() / tracerHalfLength); } } m_pos = newPos; Matrix34 tm(Matrix33::CreateRotationVDir(dir)); tm.AddTranslation(pos); pEntity->SetWorldTM(tm); //Do not scale effects if((m_tracerFlags & kTracerFlag_useGeometry)) { float finalFovScale = fovScale; if((m_tracerFlags & kTracerFlag_scaleToDistance) != 0) { lengthScale = dist * 0.5f; } else { const float cameraDistanceSqr = (m_pos-camera).len2(); const float minScale = GetGameConstCVar(g_tracers_minScale); const float maxScale = GetGameConstCVar(g_tracers_maxScale); const float minDistanceRange = GetGameConstCVar(g_tracers_minScaleAtDistance) * GetGameConstCVar(g_tracers_minScaleAtDistance); const float maxDistanceRange = max(GetGameConstCVar(g_tracers_maxScaleAtDistance) * GetGameConstCVar(g_tracers_maxScaleAtDistance), minDistanceRange + 1.0f); const float currentRefDistance = clamp(cameraDistanceSqr, minDistanceRange, maxDistanceRange); const float distanceToCameraFactor = ((currentRefDistance - minDistanceRange) / (maxDistanceRange - minDistanceRange)); const float distanceToCameraScale = LERP(minScale, maxScale, distanceToCameraFactor); lengthScale = m_scale * distanceToCameraScale; finalFovScale *= distanceToCameraScale; } const float widthScale = fovScale; tm.SetIdentity(); tm.SetScale(Vec3(m_scale * finalFovScale, lengthScale, m_scale * finalFovScale)); pEntity->SetSlotLocalTM(m_geometrySlot,tm); } } return true; }
void CPlayerVisTable::DoVisibilityCheck(const Vec3& localPlayerPosn, SVisTableEntry& visInfo, VisEntryIndex visIndex) { Vec3 vecToTarget; IEntity * pEntity = gEnv->pEntitySystem->GetEntity(visInfo.entityId); if(pEntity) { IPhysicalEntity* pTargetPhysEnt = pEntity->GetPhysics(); SDeferredLinetestBuffer& targetBuffer = m_linetestBuffers[GetCurrentLinetestBufferTargetIndex()]; if(targetBuffer.m_numLinetestsCurrentlyProcessing < kMaxVisTableLinetestsPerFrame) { visInfo.framesSinceLastCheck = 0; SDeferredLinetestReceiver * processingEntry = GetAvailableDeferredLinetestReceiver(targetBuffer); assert(processingEntry); Vec3 targetPosn = pEntity->GetWorldPos(); if (visInfo.flags & eVF_CheckAgainstCenter) { AABB targetBbox; pEntity->GetWorldBounds(targetBbox); if (!targetBbox.IsEmpty()) { targetPosn = targetBbox.GetCenter(); } float radius = min(min(targetBbox.max.x-targetBbox.min.x, targetBbox.max.y-targetBbox.min.y), targetBbox.max.z-targetBbox.min.z); targetPosn += (localPlayerPosn-targetPosn).GetNormalized() * radius * 0.25f; } targetPosn.z += visInfo.heightOffset; vecToTarget = targetPosn - localPlayerPosn; processingEntry->visTableIndex = visIndex; ray_hit hit; const int rayFlags = rwi_colltype_any(geom_colltype_solid&(~geom_colltype_player)) | rwi_ignore_noncolliding | rwi_pierceability(PIERCE_GLASS); m_numLinetestsThisFrame++; targetBuffer.m_numLinetestsCurrentlyProcessing++; visInfo.flags |= eVF_Pending; visInfo.flags &= ~eVF_CheckAgainstCenter; processingEntry->visBufferIndex = m_currentBufferTarget; const int numEntries = kMaxNumIgnoreEntities + 1; IPhysicalEntity* pSkipEnts[numEntries]; int numSkipEnts = 0; if(pTargetPhysEnt) { pSkipEnts[numSkipEnts] = pTargetPhysEnt; numSkipEnts++; } if (m_currentNumIgnoreEntities) { for(int i = 0; i < m_currentNumIgnoreEntities; ++i) { SIgnoreEntity& ignoreEnt = m_globalIgnoreEntities[i]; CRY_ASSERT(ignoreEnt.id); IEntity* pIgnoreEntity = gEnv->pEntitySystem->GetEntity(ignoreEnt.id); IPhysicalEntity* pIgnorePhysicsEntity = pIgnoreEntity ? pIgnoreEntity->GetPhysics() : NULL; if (pIgnorePhysicsEntity) { pSkipEnts[numSkipEnts] = pIgnorePhysicsEntity; numSkipEnts++; } } } CRY_ASSERT(processingEntry->queuedRayID == 0); processingEntry->queuedRayID = g_pGame->GetRayCaster().Queue( RayCastRequest::HighPriority, RayCastRequest(localPlayerPosn, vecToTarget, ent_terrain|ent_static|ent_sleeping_rigid|ent_rigid, rayFlags, pSkipEnts, numSkipEnts, 2), functor(*processingEntry, &SDeferredLinetestReceiver::OnDataReceived)); #if ALLOW_VISTABLE_DEBUGGING m_debugDraw.UpdateDebugTarget(visInfo.entityId, targetPosn, ((visInfo.flags & eVF_Visible) != 0)); #endif } } else { visInfo.flags |= eVF_Remove; } }