Moduł mający za zadanie określać poziom widoczności gracza przez najbliższych przeciwników oraz przedstawiać te informacje na HUD’zie.
DirectionVisiblitySystem.h
#pragma once #include "stdafx.h" class CDirectionVisibilitySystem { typedef O3::Containers::CArray<O3::Math::CVector3> TVisibilityPoints; public: CDirectionVisibilitySystem(); void Run(O3::QPtr<Objects::CVMobileObject> player); void ClearTracking(); void BeginTracking(); protected: float CalculatePlayerVisiblityPercentage(O3::QPtr<Objects::CVMobileObject> fromMob) const; TVisibilityPoints& PreparePlayerVisibilityPointList(TVisibilityPoints& visList, O3::QPtr<Objects::CVMobileObject> player) const; private: O3::Double m_lastUpdateTime; };
DirectionVisiblitySystem.cpp
#include "stdafx.h" //all tweakables goes here O3::CConfigVar c_directionVisiblitySystemRangeSq(O3::CONFIG_VAR_TYPE_FLOAT, "c_directionVisiblitySystemRangeSq", "62500", "Client", O3::CONFIG_VAR_FLAGS_SYSTEM, "Direction Visiblity System maximum range squared"); O3::CConfigVar c_directionVisiblitySystemEnabled(O3::CONFIG_VAR_TYPE_BOOL, "c_directionVisiblitySystemEnabled", "false", "Client", O3::CONFIG_VAR_FLAGS_SYSTEM, "Enable/disable direction visiblity system"); O3::CConfigVar c_directionVisiblitySystemDebugRaycasts(O3::CONFIG_VAR_TYPE_BOOL, "c_directionVisiblitySystemDebugRaycasts", "false", "Client", O3::CONFIG_VAR_FLAGS_SYSTEM, "Enable/disable visualization of visibility check raycasts"); O3::CConfigVar c_directionVisiblitySystemDebugMobs(O3::CONFIG_VAR_TYPE_BOOL, "c_directionVisiblitySystemDebugMobs", "false", "Client", O3::CONFIG_VAR_FLAGS_SYSTEM, "Enable/disable highlighting of tracked mobs (CTRL must be pressed)"); O3::CConfigVar c_directionVisiblitySystemMaxTrackedMobs(O3::CONFIG_VAR_TYPE_INT, "c_directionVisiblitySystemMaxTrackedMobs", "3", "Client", O3::CONFIG_VAR_FLAGS_SYSTEM, "Sets desired number of mobs that should be gathered for gui tracking"); O3::CConfigVar c_directionVisiblitySystemUpdateInterval(O3::CONFIG_VAR_TYPE_FLOAT, "c_directionVisiblitySystemUpdateInterval", "0.3", "Client", O3::CONFIG_VAR_FLAGS_SYSTEM, "Update interval in seconds"); //the actual code CDirectionVisibilitySystem::CDirectionVisibilitySystem(): m_lastUpdateTime(0) { } void CDirectionVisibilitySystem::Run(O3::QPtr<Objects::CVMobileObject> player) { if (c_directionVisiblitySystemEnabled.GetBoolValue() && player && player->IsAlive()) { if (GetServicePtr()->GetEngine()->GetTimer()->GetSeconds() - m_lastUpdateTime >= (double)c_directionVisiblitySystemUpdateInterval.GetFloatValue()) { auto& mobList = GetServicePtr()->GetWorldManager()->GetMobsList(true); O3::Math::CVector3 playerPos = player->GetPosition(); GUI::Args::SMobTrackingOnDirectionUI args; for (auto it=mobList.begin(); it != mobList.end(); ++it) { const O3::QPtr<Objects::CVMobileObject>& mob = (*it); if (mob) { if (c_directionVisiblitySystemDebugMobs.GetBoolValue() && mob->GetEntity()) { const_cast<Objects::CVMobileObject*>(mob.ConstIPtr())->GetEntity()->SetSelection(false, true, Items::SelectionTypes::SELECTION_UNKNOWN); } if ((mob->GetPosition()-playerPos).LengthSq() <= c_directionVisiblitySystemRangeSq.GetFloatValue()) { if (mob->IsAI() && mob->IsAggroing(player)) { float targetVisiblityPercentage = CalculatePlayerVisiblityPercentage(mob); if (targetVisiblityPercentage > 0.0f) { if (c_directionVisiblitySystemDebugMobs.GetBoolValue() && mob->GetEntity()) { const_cast<Objects::CVMobileObject*>(mob.ConstIPtr())->GetEntity()->SetSelection(true, true, Items::SelectionTypes::SELECTION_MOB); } args.Ids.push_back(mob->GetVarId().ToUInt64()); args.Factors.push_back(targetVisiblityPercentage); if (args.Ids.size() == c_directionVisiblitySystemMaxTrackedMobs.GetIntValue()) { break; } } } } } } GUI::Events::MobTrackingOnDirectionUI.Invoke(O3::EventSystem::CEventSender(), args); m_lastUpdateTime = GetServicePtr()->GetEngine()->GetTimer()->GetSeconds(); } } } void CDirectionVisibilitySystem::ClearTracking() { GUI::Args::SMobTrackingOnDirectionUI args; GUI::Events::MobTrackingOnDirectionUI.Invoke(O3::EventSystem::CEventSender(), args); } void CDirectionVisibilitySystem::BeginTracking() { m_lastUpdateTime = GetServicePtr()->GetEngine()->GetTimer()->GetSeconds(); //this will cause tracking to actually begin after update interval value } CDirectionVisibilitySystem::TVisibilityPoints& CDirectionVisibilitySystem::PreparePlayerVisibilityPointList(CDirectionVisibilitySystem::TVisibilityPoints& visList, O3::QPtr<Objects::CVMobileObject> player) const { if (player) { player->GetAllCollidersCenterPointsFromZone(Objects::EHitZone::Head2, visList); player->GetAllCollidersCenterPointsFromZone(Objects::EHitZone::Torso, visList); player->GetAllCollidersCenterPointsFromZone(Objects::EHitZone::LeftLeg, visList); visList.RemoveBack(); //remove last leg bone in chain (right foot) player->GetAllCollidersCenterPointsFromZone(Objects::EHitZone::RightLeg, visList); visList.RemoveBack(); //remove last leg bone in chain (left foot) } return visList; } float CDirectionVisibilitySystem::CalculatePlayerVisiblityPercentage(O3::QPtr<Objects::CVMobileObject> fromMob) const { if (fromMob && GetServicePtr()->GetMobController()) { if (O3::QPtr<Objects::CVMobileObject> player = GetServicePtr()->GetMobController()->GetControledMob()) { O3::Math::CVector3 source = fromMob->GetPosition() + fromMob->GetTargetPoint(); int targetHitCount = 0; O3::Physics::CRaycastHit result; TVisibilityPoints visibilityPoints; PreparePlayerVisibilityPointList(visibilityPoints, player); for (int i =0; i<visibilityPoints.GetSize(); ++i) { O3::Math::CVector3 dir = (visibilityPoints[i] - source).Normalize(); O3::QPtr<Objects::CVVisibleObject> pTargetObject = GetServicePtr()->GetWorldManager()->PickObjectEx( &result, source, dir, O3::Physics::SHAPE_GROUP_TARGET | O3::Physics::SHAPE_GROUP_ELEMENT, 0, fromMob->GetVarId()); if (pTargetObject && pTargetObject->GetVarId() == player->GetVarId()) { targetHitCount++; } if (c_directionVisiblitySystemDebugRaycasts.GetBoolValue()) { O3::ULong color = pTargetObject && pTargetObject->GetVarId() == player->GetVarId() ? 0xffff000f : 0xff00ff00; GetServicePtr()->GetEngine()->GetRenderer()->AddDebugLine(color, source, visibilityPoints[i]); } } return (float)targetHitCount / (float)visibilityPoints.GetSize(); //rework? } } return 0.0f; }
Przykład użycia
//this is called each frame, as a part of CMobController::Run void CMobController::RunDirectionVisiblitySystem() { m_directionVisibilitySystem.Run(m_controlledMob); } ... ... //when player 'alive' state changes void CMobController::ControledMob_AliveChanged(O3::EventSystem::CEventSender& sender, O3::EventSystem::CEventArgs& args) { if (!GetControledMob()->IsAlive()) { m_directionVisibilitySystem.ClearTracking(); } else { m_directionVisibilitySystem.BeginTracking(); } }