Setup NPC director

This commit is contained in:
koritsa
2026-06-01 16:26:15 +03:00
parent cf73d79190
commit 30e5e4ca41
17 changed files with 590 additions and 50 deletions
+14 -9
View File
@@ -54,7 +54,7 @@ float UStatsManager::ComputeObservedExposureRate()
for (int32 i = Observers.Num() - 1; i >= 0; --i)
{
AActor* Observer = Observers[i].Get();
AActor* Observer = Observers[i].Actor.Get();
if (!Observer)
{
Observers.RemoveAtSwap(i);
@@ -64,7 +64,8 @@ float UStatsManager::ComputeObservedExposureRate()
const float Exposure = OwnerCharacter->GetObservedExposureFrom(Observer->GetActorLocation(), Observer);
if (Exposure > 0.0f)
{
SumNormalizedExposure += Exposure / MaxObservedExposure;
// Weight by NPC type (§10.2): a Stalker's stare contributes more than a Walker's glance.
SumNormalizedExposure += (Exposure / MaxObservedExposure) * Observers[i].Weight;
++ActiveObservers;
}
}
@@ -83,23 +84,27 @@ void UStatsManager::Init(UClothingManager* InClothingManager)
ClothingManager = InClothingManager;
}
void UStatsManager::SetObserved(const bool bObserved, AActor* Observer)
void UStatsManager::SetObserved(const bool bObserved, AActor* Observer, const float Weight)
{
if (!Observer)
return;
const int32 ExistingIndex = Observers.IndexOfByPredicate(
[Observer](const FObserverEntry& Entry) { return Entry.Actor == Observer; });
bool bChanged = false;
if (bObserved)
{
if (!Observers.Contains(Observer))
if (ExistingIndex == INDEX_NONE)
{
Observers.Add(Observer);
Observers.Add({ Observer, Weight });
bChanged = true;
}
}
else
else if (ExistingIndex != INDEX_NONE)
{
bChanged = Observers.Remove(Observer) > 0;
Observers.RemoveAtSwap(ExistingIndex);
bChanged = true;
}
if (bChanged)
@@ -109,9 +114,9 @@ void UStatsManager::SetObserved(const bool bObserved, AActor* Observer)
int32 UStatsManager::GetObserverCount() const
{
int32 Count = 0;
for (const TWeakObjectPtr<AActor>& Observer : Observers)
for (const FObserverEntry& Observer : Observers)
{
if (Observer.IsValid())
if (Observer.Actor.IsValid())
++Count;
}
return Count;
+14 -5
View File
@@ -45,8 +45,9 @@ public:
// Called by NPCAIController when an NPC gains or loses sight of the player. Observer is the
// observing pawn; its live location is re-traced each tick to weight embarrassment by the
// body parts that observer can actually see (GDD §7.1).
void SetObserved(bool bObserved, AActor* Observer);
// body parts that observer can actually see (GDD §7.1). Weight is the observer's NPC-type
// multiplier (§10.2) — Walkers read low, Stalkers high; ignored on the un-observe path.
void SetObserved(bool bObserved, AActor* Observer, float Weight = 1.0f);
// Number of NPCs currently perceiving the player (used by commission objectives, §13.4).
UFUNCTION(BlueprintPure)
@@ -84,7 +85,15 @@ private:
UPROPERTY()
TObjectPtr<ANakedDesireCharacter> OwnerCharacter;
// NPCs currently perceiving the player (added/removed via SetObserved). Weak so a destroyed
// observer drops out without dangling; stale entries are compacted during the tick.
TArray<TWeakObjectPtr<AActor>> Observers;
// One perceiving NPC and its observation weight (§10.2). Weak so a destroyed observer drops
// out without dangling.
struct FObserverEntry
{
TWeakObjectPtr<AActor> Actor;
float Weight = 1.0f;
};
// NPCs currently perceiving the player (added/removed via SetObserved). Stale entries are
// compacted during the tick.
TArray<FObserverEntry> Observers;
};