Hello, I can’t consider your answer correct, because the main question is not how to process damage deal when OnBeginOverlap, but how the bullet or weapon actor should delegate damage to a specific entity. I have now come up with what seems to be a crutch, but ECS correct solution:
Fragments for my configure trait HitUnitTrait:
USTRUCT()
struct MASSSAMPLE_API FHealthFragment : public FMassFragment
{
GENERATED_BODY()
float Health = 0;
};
USTRUCT()
struct MASSSAMPLE_API FTargetFragment : public FMassFragment
{
GENERATED_BODY()
FVector TargetLocation;
};
USTRUCT(BlueprintType)
struct FOverlapStateData
{
GENERATED_BODY()
UPROPERTY(BlueprintReadWrite, EditAnywhere)
TArray<int32> CurrentOverlappingEntities;
UPROPERTY(BlueprintReadWrite, EditAnywhere)
TArray<int32> PreviousOverlappingEntities;
};
USTRUCT()
struct FOverlapStateFragment : public FMassFragment
{
GENERATED_BODY()
UPROPERTY()
FOverlapStateData OverlapStateData;
};
HitUnitProcess.h
UCLASS()
class MASSSAMPLE_API UHitUnitProcessor : public UMassProcessor
{
GENERATED_BODY()
public:
HitUnitProcessor();
protected:
virtual void ConfigureQueries() override
{
EntityQuery.AddRequirement<FTransformFragment>(EMassFragmentAccess::ReadOnly);
EntityQuery.AddRequirement<FHealthFragment>(EMassFragmentAccess::ReadWrite);
EntityQuery.AddRequirement<FOverlapStateFragment>(EMassFragmentAccess::ReadWrite);
EntityQuery.RegisterWithProcessor(*this);
}
virtual void Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) override;
private:
FMassEntityQuery EntityQuery;
};
HitUnitProcessor.cpp
void UHitUnitProcessor::Execute(
FMassEntityManager &EntityManager,
FMassExecutionContext &Context)
{
EntityQuery.ForEachEntityChunk(EntityManager, Context, [&](FMassExecutionContext& MassExecutionContext)
{
const auto TransformListView = MassExecutionContext.GetFragmentView<FTransformFragment>();
auto OverlapStateFragments = MassExecutionContext.GetMutableFragmentView<FOverlapStateFragment>();
const auto HealthFragmentsList = MassExecutionContext.GetMutableFragmentView<FHealthFragment>();
int i = 0;
for (int EntityIndex = 0; EntityIndex < MassExecutionContext.GetNumEntities(); ++EntityIndex)
{
i += 1;
const auto EntityLocation = TransformListView[EntityIndex].GetTransform().GetLocation();
FHealthFragment& HealthFragment = HealthFragmentsList[EntityIndex];
FOverlapStateFragment& OverlapStateFragment = OverlapStateFragments[EntityIndex];
TArray<FOverlapResult> OverlapResults;
FCollisionQueryParams QueryParams;
GetWorld()->OverlapMultiByChannel(
OverlapResults,
EntityLocation,
FQuat::Identity,
ECollisionChannel::ECC_GameTraceChannel1,
FCollisionShape::MakeSphere(150.0f),
QueryParams
);
TArray<int32> CurrentOverlappingEntities;
for (const FOverlapResult& Result : OverlapResults)
{
auto OverlappingComp = Result.GetComponent();
if (OverlappingComp && OverlappingComp->GetCollisionObjectType() == ECC_GameTraceChannel2)
{
int32 OverlappingEntityID = OverlappingComp->GetUniqueID();
CurrentOverlappingEntities.Add(OverlappingEntityID);
if (!OverlapStateFragment.OverlapStateData.PreviousOverlappingEntities.Contains(OverlappingEntityID))
{
int32 collchanel = static_cast<int32>(OverlappingComp->GetCollisionObjectType());
EntityManager.Defer().PushCommand<FMassDeferredSetCommand>(
[=](FMassEntityManager& Manager)
{
UE_LOG(LogTemp, Error, TEXT("%i overlaping with %i"), i, collchanel);
});
HealthFragment.Health -= 10.0f;
}
}
}
OverlapStateFragment.OverlapStateData.PreviousOverlappingEntities = MoveTemp(OverlapStateFragment.OverlapStateData.CurrentOverlappingEntities);
OverlapStateFragment.OverlapStateData.CurrentOverlappingEntities = MoveTemp(CurrentOverlappingEntities);
if (HealthFragment.Health <= 0)
{
Context.Defer().DestroyEntity(Context.GetEntity(EntityIndex));
}
}
});
}
but I think it’s a very complex calculation for an ECS execute per tick.