Skip to content

Instantly share code, notes, and snippets.

@Mikea15
Last active May 17, 2022 07:25
Show Gist options
  • Save Mikea15/1de0dd7d4956b37d0b3b3cce10dabf2e to your computer and use it in GitHub Desktop.
Save Mikea15/1de0dd7d4956b37d0b3b3cce10dabf2e to your computer and use it in GitHub Desktop.
Pseudo-Untested-Modular-Target-Selection
// Copyright (c) Michael Adaixo - 2022
#pragma once
#include "CoreMinimal.h"
#include "ITargetSelector.generated.h"
/*
* Base TS Filter object
*/
UCLASS(ClassGroup = TargetSelector, abstract, EditInlineNew)
class UTSFilter : public UObject
{
GENERATED_BODY()
public:
virtual bool PassesFilters(const AActor* Querier, const AActor* Perceived) { return true; }
};
/*
* Affinity TS Filter
*/
UCLASS(meta = (DisplayName = "Target Selector | Filter | Affinity"))
class UTSFilter_Affinity : public UTSFilter
{
GENERATED_BODY()
public:
bool PassesFilters(const AActor* Querier, const AActor* Perceived) override { /* if then bla */ return true; }
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool AcceptFriendly;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool AcceptHostile;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool AcceptNeutral;
};
/*
* ZHeight TS Filter
*/
UCLASS(meta = (DisplayName = "Target Selector | Filter | ZHeight"))
class UTSFilter_ZDist : public UTSFilter
{
GENERATED_BODY()
public:
bool PassesFilters(const AActor* Querier, const AActor* Perceived) override { /* if then bla */ return true; }
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float HeightMarginOfError = 500.0f;
};
/*
* Base TS Weight object
*/
UCLASS(ClassGroup = TargetSelector, abstract, EditInlineNew)
class UTSWeight : public UObject
{
GENERATED_BODY()
public:
virtual float ApplyWeight(const AActor* Querier, const AActor* Perceived) { return 1.0f; }
float MaybeClamp(float Weight)
{
if (!bClampWeight) { return Weight; }
return FMath::Clamp(Weight, MinClamp, MaxClamp);
}
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool bClampWeight = false;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (EditCondition = "bClampWeight", EditConditionHides))
float MinClamp;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (EditCondition = "bClampWeight", EditConditionHides))
float MaxClamp;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool bNormalizeValues = false;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (EditCondition = "bNormalizeValues", EditConditionHides))
float MinValue;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (EditCondition = "bNormalizeValues", EditConditionHides))
float MaxValue;
};
/*
* Distance TS Weight
*/
UCLASS(meta = (DisplayName = "Target Selector | Weight | Distance"))
class UTSWeight_Distance : public UTSWeight
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (UIMin = 0.0, ClampMin = 0.0))
float MaxDistance;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
bool IsInvincible;
};
/*
* ThreatLevel TS Weight
*/
UCLASS(meta = (DisplayName = "Target Selector | Weight | Threat Level"))
class UTSWeight_ThreatLevel : public UTSWeight
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta = (UIMin = 0.0, ClampMin = 0.0))
float MaxThreat;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int ExampleOption2;
};
/*
* SameTarget TS Weight
*/
UCLASS(meta = (DisplayName = "Target Selector | Weight | SameTarget"))
class UTSWeight_SameTarget : public UTSWeight
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
float Multiplier;
};
/*
* Main TargetSelector
*/
UCLASS(Blueprintable, abstract, ClassGroup = TargetSelector, EditInlineNew)
class UTargetSelector : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Target Selector")
AActor* SelectTarget(const AActor* SelfActor, TArray<AActor*> PerceivedActor);
public:
UPROPERTY(EditDefaultsOnly, Instanced, Category = "Target Selector")
TArray<TObjectPtr<UTSFilter>> Filters;
UPROPERTY(EditDefaultsOnly, Instanced, Category = "Target Selector")
TArray<TObjectPtr<UTSWeight>> Weights;
};
// .cpp
AActor* UTargetSelector::SelectTarget(const AActor* SelfActor, TArray<AActor*> PerceivedActor)
{
AActor* BestActor = nullptr;
float BestScore = -FLT_MAX;
for (AActor* Perceived : PerceivedActor)
{
bool bPassedFilters = false;
for (const TObjectPtr<UTSFilter>& Filter : Filters)
{
bPassedFilters = Filter->PassesFilters(SelfActor, Perceived);
if (!bPassedFilters)
{
break;
}
}
if (!bPassedFilters)
{
continue;
}
float Score = 1.0f;
for (const TObjectPtr<UTSWeight>& Weight : Weights)
{
const float TempWeight = Weight->ApplyWeight(SelfActor, Perceived);
Score *= Weight->MaybeClamp(TempWeight);
if (Score <= 0.0f)
{
break;
}
}
if (Score > BestScore)
{
BestScore = Score;
BestActor = Perceived;
}
}
return BestActor;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment