There are few more tricks you can do to your Struct to get them even more TArray-friendly.
Below is one of the structs we have in our game; note that we don’t explicitly add default constructor, “GENERATED_BODY()” does that for us, based on assignment in declaration, eg DamageMax = 0;
At the end, we overload “less than”, and “is equal” operators, to allow TArray.Sort() and TArray.Find(). In our case, effect (buff or debuff) is considered identical if it came from the same ParentAbility (spell) is the same effect index (when spells have more than one effect), came from the same instigator, and has the same name. We consider effect “smaller” than other effect, if time remaining is smaller.
USTRUCT(BlueprintType)
struct FAbilityEffect
{
GENERATED_BODY()
// Effect Type
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
EAbilityEffectType Type;
// Minimum damage, if applicable
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
int32 DamageMin = 0;
// Maximum damage, if applicable
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
int32 DamageMax = 0;
// Area affected in cm, if applicable
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
float AreaRadius = 0.f;
// Flag whether damage gets added to current weapon's damage
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
bool AddToWeapon = false;
// Duration in seconds
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
float Duration = 0.f;
// Stat Modifier (for Buffs and Debuffs)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
EStatModifier StatModifier;
// Modification amount absolute (negative for debuffs, positive for buffs)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
float ModifierAmount = 0.f;
// Modification amount percentage/fraction (1.0 is no change, 0.7 for 30% debuff, 1.3 for 30% buff)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
float ModifierPercentage = 1.f;
// Leap Inpulse
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = AbilityEffect)
float LeapImpulse = 0;
// particle effect while under the influence
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VisualEffects)
UParticleSystem* EffectParticle = NULL;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VisualEffects)
TSubclassOf<AActor> EffectReplacementActorClass = NULL;
// grounnd hit decal, on the ground of the hit (eg at the feet or enemy)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = VisualEffects)
TSubclassOf<class ADecalActor> GroundDecalClass;
// flag to enable right leg trails
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Properties)
bool RightLegTrails = false;
// flag to enable left leg trails
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Properties)
bool LeftLegTrails = false;
// animation montage while effect active
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Properties)
UAnimMontage* Animation = NULL;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
UParticleSystemComponent* EffectParticleComponent = NULL;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
AActor* EffectReplacementActor = NULL;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
FString Name;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
ATraverseBaseCharacter* Instigator = NULL;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
int32 Index = 0;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
float fRemainingTime = 0.f;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
int32 iRemainingTime = 0;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
float RemainingModifierAmount = 0.f;
UPROPERTY(BlueprintReadOnly, Category = RuntimeParams)
UAbility* ParentAbility = nullptr;
// support for TArray.Sort() -- we sort on float time remaining
FORCEINLINE bool operator<(const FAbilityEffect& V) const
{
return fRemainingTime < V.fRemainingTime;
}
// support for TArray.Find()
FORCEINLINE bool operator==(const FAbilityEffect& Other) const
{
if (Index != Other.Index) return false;
if (ParentAbility != Other.ParentAbility) return false;
if (Instigator != Other.Instigator) return false;
if (Name != Other.Name) return false;
return true;
}
};