更新 Source/FLESH/Private/BloodPool.cpp
This commit is contained in:
@@ -1,114 +1,166 @@
|
|||||||
#include "BloodPool.h"
|
#include "BloodSystem.h"
|
||||||
#include "Components/BoxComponent.h"
|
#include "NiagaraComponent.h"
|
||||||
|
#include "NiagaraFunctionLibrary.h"
|
||||||
#include "Components/DecalComponent.h"
|
#include "Components/DecalComponent.h"
|
||||||
#include "Materials/MaterialInterface.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "Materials/MaterialInstanceDynamic.h"
|
#include "Engine/World.h"
|
||||||
#include "TimerManager.h"
|
|
||||||
|
|
||||||
// Sets default values
|
// Sets default values for this component's properties
|
||||||
ABloodPool::ABloodPool()
|
UBloodSystem::UBloodSystem()
|
||||||
{
|
{
|
||||||
// Set this actor to call Tick() every frame
|
// Set this component to be initialized when the game starts, and to be ticked every frame
|
||||||
PrimaryActorTick.bCanEverTick = false;
|
PrimaryComponentTick.bCanEverTick = true;
|
||||||
|
|
||||||
// Create and set up the collision component
|
|
||||||
Collision = CreateDefaultSubobject<UBoxComponent>(TEXT("Collision"));
|
|
||||||
RootComponent = Collision;
|
|
||||||
Collision->SetCollisionProfileName(TEXT("NoCollision"));
|
|
||||||
Collision->SetBoxExtent(FVector(1.0f, 100.0f, 100.0f));
|
|
||||||
|
|
||||||
// Create and set up the decal component
|
|
||||||
Decal = CreateDefaultSubobject<UDecalComponent>(TEXT("Decal"));
|
|
||||||
Decal->SetupAttachment(RootComponent);
|
|
||||||
Decal->SetRelativeRotation(FRotator(90.0f, 0.0f, 0.0f));
|
|
||||||
Decal->DecalSize = FVector(10.0f, 100.0f, 100.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when the game starts or when spawned
|
// Called when the game starts
|
||||||
void ABloodPool::BeginPlay()
|
void UBloodSystem::BeginPlay()
|
||||||
{
|
{
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
|
|
||||||
// Set the initial decal material
|
|
||||||
if (DecalMaterial)
|
|
||||||
{
|
|
||||||
UMaterialInstanceDynamic* DynamicMaterial = UMaterialInstanceDynamic::Create(DecalMaterial, this);
|
|
||||||
if (DynamicMaterial)
|
|
||||||
{
|
|
||||||
// Set the color parameter if it exists
|
|
||||||
DynamicMaterial->SetVectorParameterValue(FName("Color"), PoolColor);
|
|
||||||
Decal->SetMaterial(0, DynamicMaterial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the pool size
|
|
||||||
UpdatePoolSize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABloodPool::SetPoolSize(float NewSize)
|
// Called every frame
|
||||||
|
void UBloodSystem::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||||||
{
|
{
|
||||||
PoolSize = FMath::Max(0.1f, NewSize);
|
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||||||
UpdatePoolSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ABloodPool::SetPoolColor(const FLinearColor& NewColor)
|
// Clean up finished blood effects
|
||||||
{
|
for (int32 i = ActiveBloodEffects.Num() - 1; i >= 0; --i)
|
||||||
PoolColor = NewColor;
|
|
||||||
|
|
||||||
// Update the material color
|
|
||||||
if (Decal && Decal->GetMaterial(0))
|
|
||||||
{
|
{
|
||||||
UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(Decal->GetMaterial(0));
|
if (!ActiveBloodEffects[i] || !ActiveBloodEffects[i]->IsActive())
|
||||||
if (DynamicMaterial)
|
|
||||||
{
|
{
|
||||||
DynamicMaterial->SetVectorParameterValue(FName("Color"), PoolColor);
|
ActiveBloodEffects.RemoveAt(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ABloodPool::StartExpansion(float InExpansionRate, float MaxSize)
|
void UBloodSystem::SpawnBloodEffect(const FVector& Location, const FVector& Direction, float Intensity)
|
||||||
{
|
{
|
||||||
ExpansionRate = InExpansionRate;
|
// Ensure we have a valid blood spray system
|
||||||
MaxPoolSize = MaxSize;
|
if (!BloodSpraySystem)
|
||||||
bIsExpanding = true;
|
|
||||||
|
|
||||||
// Start the expansion timer
|
|
||||||
GetWorldTimerManager().SetTimer(ExpansionTimerHandle, this, &ABloodPool::ExpandPool, 0.1f, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ABloodPool::UpdatePoolSize()
|
|
||||||
{
|
|
||||||
// Update the decal size
|
|
||||||
if (Decal)
|
|
||||||
{
|
|
||||||
Decal->DecalSize = FVector(10.0f, 100.0f * PoolSize, 100.0f * PoolSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the collision box size
|
|
||||||
if (Collision)
|
|
||||||
{
|
|
||||||
Collision->SetBoxExtent(FVector(1.0f, 100.0f * PoolSize, 100.0f * PoolSize));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ABloodPool::ExpandPool()
|
|
||||||
{
|
|
||||||
if (!bIsExpanding)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increase the pool size
|
// Manage the number of active blood effects
|
||||||
PoolSize += ExpansionRate * 0.1f;
|
if (ActiveBloodEffects.Num() >= MaxBloodEffects)
|
||||||
|
|
||||||
// Check if we've reached the maximum size
|
|
||||||
if (PoolSize >= MaxPoolSize)
|
|
||||||
{
|
{
|
||||||
PoolSize = MaxPoolSize;
|
// Remove the oldest blood effect
|
||||||
bIsExpanding = false;
|
if (ActiveBloodEffects[0])
|
||||||
GetWorldTimerManager().ClearTimer(ExpansionTimerHandle);
|
{
|
||||||
|
ActiveBloodEffects[0]->DestroyComponent();
|
||||||
|
}
|
||||||
|
ActiveBloodEffects.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a rotation from the direction
|
||||||
|
FRotator Rotation = Direction.Rotation();
|
||||||
|
|
||||||
|
// Spawn the blood effect
|
||||||
|
UNiagaraComponent* BloodEffect = UNiagaraFunctionLibrary::SpawnSystemAtLocation(
|
||||||
|
GetWorld(),
|
||||||
|
BloodSpraySystem,
|
||||||
|
Location,
|
||||||
|
Rotation,
|
||||||
|
FVector(Intensity),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
ENCPoolMethod::AutoRelease
|
||||||
|
);
|
||||||
|
|
||||||
|
if (BloodEffect)
|
||||||
|
{
|
||||||
|
// Set the intensity parameter if it exists
|
||||||
|
BloodEffect->SetFloatParameter(FName("Intensity"), Intensity);
|
||||||
|
|
||||||
|
// Add to active blood effects
|
||||||
|
ActiveBloodEffects.Add(BloodEffect);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Update the pool size
|
|
||||||
UpdatePoolSize();
|
AActor* UBloodSystem::CreateBloodPool(const FVector& Location, float Size)
|
||||||
|
{
|
||||||
|
// Ensure we have a valid blood pool class
|
||||||
|
if (!BloodPoolClass)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage the number of active blood pools
|
||||||
|
if (ActiveBloodPools.Num() >= MaxBloodPools)
|
||||||
|
{
|
||||||
|
// Remove the oldest blood pool
|
||||||
|
if (ActiveBloodPools[0])
|
||||||
|
{
|
||||||
|
ActiveBloodPools[0]->Destroy();
|
||||||
|
}
|
||||||
|
ActiveBloodPools.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn the blood pool
|
||||||
|
FActorSpawnParameters SpawnParams;
|
||||||
|
SpawnParams.Owner = GetOwner();
|
||||||
|
SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButAlwaysSpawn;
|
||||||
|
|
||||||
|
// Trace downward to find the floor
|
||||||
|
FHitResult HitResult;
|
||||||
|
FVector TraceStart = Location;
|
||||||
|
FVector TraceEnd = Location - FVector(0, 0, 200.0f);
|
||||||
|
FCollisionQueryParams QueryParams;
|
||||||
|
QueryParams.AddIgnoredActor(GetOwner());
|
||||||
|
|
||||||
|
if (GetWorld()->LineTraceSingleByChannel(HitResult, TraceStart, TraceEnd, ECC_Visibility, QueryParams))
|
||||||
|
{
|
||||||
|
// Spawn at the hit location
|
||||||
|
AActor* BloodPool = GetWorld()->SpawnActor<AActor>(BloodPoolClass, HitResult.Location, FRotator::ZeroRotator, SpawnParams);
|
||||||
|
|
||||||
|
if (BloodPool)
|
||||||
|
{
|
||||||
|
// Set the size of the blood pool
|
||||||
|
BloodPool->SetActorScale3D(FVector(Size));
|
||||||
|
|
||||||
|
// Add to active blood pools
|
||||||
|
ActiveBloodPools.Add(BloodPool);
|
||||||
|
|
||||||
|
return BloodPool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
UDecalComponent* UBloodSystem::ApplyBloodDecal(UPrimitiveComponent* Component, const FVector& Location, const FVector& Direction, float Size)
|
||||||
|
{
|
||||||
|
// Ensure we have a valid blood decal material
|
||||||
|
if (!BloodDecalMaterial || !Component)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manage the number of active blood decals
|
||||||
|
if (ActiveBloodDecals.Num() >= MaxBloodDecals)
|
||||||
|
{
|
||||||
|
// Remove the oldest blood decal
|
||||||
|
if (ActiveBloodDecals[0])
|
||||||
|
{
|
||||||
|
ActiveBloodDecals[0]->DestroyComponent();
|
||||||
|
}
|
||||||
|
ActiveBloodDecals.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a rotation from the direction (opposite to the direction for the decal to face outward)
|
||||||
|
FRotator Rotation = (-Direction).Rotation();
|
||||||
|
|
||||||
|
// Create the decal component
|
||||||
|
UDecalComponent* DecalComponent = NewObject<UDecalComponent>(Component);
|
||||||
|
DecalComponent->SetupAttachment(Component);
|
||||||
|
DecalComponent->SetRelativeLocation(Component->GetComponentTransform().InverseTransformPosition(Location));
|
||||||
|
DecalComponent->SetRelativeRotation(Component->GetComponentTransform().InverseTransformRotation(Rotation.Quaternion()));
|
||||||
|
DecalComponent->SetDecalMaterial(BloodDecalMaterial);
|
||||||
|
DecalComponent->DecalSize = FVector(10.0f, Size * 100.0f, Size * 100.0f);
|
||||||
|
DecalComponent->RegisterComponent();
|
||||||
|
|
||||||
|
// Add to active blood decals
|
||||||
|
ActiveBloodDecals.Add(DecalComponent);
|
||||||
|
|
||||||
|
return DecalComponent;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user