This commit is contained in:
2025-04-17 23:59:17 +08:00
commit 88536f22da
57 changed files with 8094 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class FLESH : ModuleRules
{
public FLESH(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicIncludePaths.AddRange(
new string[] {
// ... add public include paths required here ...
}
);
PrivateIncludePaths.AddRange(
new string[] {
// ... add other private include paths required here ...
}
);
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"CoreUObject",
"Engine",
"InputCore",
"Niagara",
"GeometryCore",
"GeometryFramework",
"GeometryScriptingCore",
"ProceduralMeshComponent",
"PhysicsCore",
"ChaosCloth",
"ChaosNiagara",
"PhysicsControl",
// ... add other public dependencies that you statically link with here ...
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"Slate",
"SlateCore",
// ... add private dependencies that you statically link with here ...
}
);
DynamicallyLoadedModuleNames.AddRange(
new string[]
{
// ... add any modules that your module loads dynamically here ...
}
);
}
}

View File

@@ -0,0 +1,136 @@
#include "AnatomicalLayerSystem.h"
// Constructor
UAnatomicalLayerSystem::UAnatomicalLayerSystem()
{
}
// Add a new anatomical layer
int32 UAnatomicalLayerSystem::AddLayer(const FName& LayerName, EAnatomicalLayerType LayerType)
{
// Create new layer
FAnatomicalLayer NewLayer;
NewLayer.LayerName = LayerName;
NewLayer.LayerType = LayerType;
// Set default properties based on type
switch (LayerType)
{
case EAnatomicalLayerType::Skin:
NewLayer.Thickness = 0.5f;
NewLayer.Density = 1.0f;
NewLayer.Elasticity = 0.7f;
NewLayer.FractureThreshold = 50.0f;
break;
case EAnatomicalLayerType::Muscle:
NewLayer.Thickness = 1.0f;
NewLayer.Density = 1.2f;
NewLayer.Elasticity = 0.6f;
NewLayer.FractureThreshold = 80.0f;
break;
case EAnatomicalLayerType::Bone:
NewLayer.Thickness = 2.0f;
NewLayer.Density = 1.5f;
NewLayer.Elasticity = 0.3f;
NewLayer.FractureThreshold = 150.0f;
break;
case EAnatomicalLayerType::Organ:
NewLayer.Thickness = 1.5f;
NewLayer.Density = 1.1f;
NewLayer.Elasticity = 0.8f;
NewLayer.FractureThreshold = 30.0f;
break;
case EAnatomicalLayerType::Blood:
NewLayer.Thickness = 0.1f;
NewLayer.Density = 1.0f;
NewLayer.Elasticity = 0.9f;
NewLayer.FractureThreshold = 10.0f;
break;
default:
break;
}
// Add to array
Layers.Add(NewLayer);
// Return index
return Layers.Num() - 1;
}
// Remove anatomical layer at specified index
bool UAnatomicalLayerSystem::RemoveLayer(int32 LayerIndex)
{
// Check if index is valid
if (Layers.IsValidIndex(LayerIndex))
{
Layers.RemoveAt(LayerIndex);
return true;
}
return false;
}
// Get anatomical layer at specified index
FAnatomicalLayer UAnatomicalLayerSystem::GetLayer(int32 LayerIndex) const
{
// Check if index is valid
if (Layers.IsValidIndex(LayerIndex))
{
return Layers[LayerIndex];
}
// Return empty layer
return FAnatomicalLayer();
}
// Get all anatomical layers
TArray<FAnatomicalLayer> UAnatomicalLayerSystem::GetAllLayers() const
{
return Layers;
}
// Set anatomical layer data at specified index
bool UAnatomicalLayerSystem::SetLayer(int32 LayerIndex, const FAnatomicalLayer& Layer)
{
// Check if index is valid
if (Layers.IsValidIndex(LayerIndex))
{
Layers[LayerIndex] = Layer;
return true;
}
return false;
}
// Get layer count
int32 UAnatomicalLayerSystem::GetLayerCount() const
{
return Layers.Num();
}
// Get layers by type
TArray<FAnatomicalLayer> UAnatomicalLayerSystem::GetLayersByType(EAnatomicalLayerType LayerType) const
{
TArray<FAnatomicalLayer> Result;
// Iterate through all layers, find layers matching the type
for (const FAnatomicalLayer& Layer : Layers)
{
if (Layer.LayerType == LayerType)
{
Result.Add(Layer);
}
}
return Result;
}
// Set physics for all layers
void UAnatomicalLayerSystem::SetPhysicsForAllLayers(bool bEnable)
{
// Iterate through all layers, set physics property
for (FAnatomicalLayer& Layer : Layers)
{
Layer.bEnablePhysics = bEnable;
}
}

View File

@@ -0,0 +1,114 @@
#include "BloodPool.h"
#include "Components/BoxComponent.h"
#include "Components/DecalComponent.h"
#include "Materials/MaterialInterface.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "TimerManager.h"
// Sets default values
ABloodPool::ABloodPool()
{
// Set this actor to call Tick() every frame
PrimaryActorTick.bCanEverTick = false;
// 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
void ABloodPool::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)
{
PoolSize = FMath::Max(0.1f, NewSize);
UpdatePoolSize();
}
void ABloodPool::SetPoolColor(const FLinearColor& NewColor)
{
PoolColor = NewColor;
// Update the material color
if (Decal && Decal->GetMaterial(0))
{
UMaterialInstanceDynamic* DynamicMaterial = Cast<UMaterialInstanceDynamic>(Decal->GetMaterial(0));
if (DynamicMaterial)
{
DynamicMaterial->SetVectorParameterValue(FName("Color"), PoolColor);
}
}
}
void ABloodPool::StartExpansion(float ExpansionRate, float MaxSize)
{
this->ExpansionRate = ExpansionRate;
MaxPoolSize = MaxSize;
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;
}
// Increase the pool size
PoolSize += ExpansionRate * 0.1f;
// Check if we've reached the maximum size
if (PoolSize >= MaxPoolSize)
{
PoolSize = MaxPoolSize;
bIsExpanding = false;
GetWorldTimerManager().ClearTimer(ExpansionTimerHandle);
}
// Update the pool size
UpdatePoolSize();
}

View File

@@ -0,0 +1,166 @@
#include "BloodSystem.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "Components/DecalComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Engine/World.h"
// Sets default values for this component's properties
UBloodSystem::UBloodSystem()
{
// Set this component to be initialized when the game starts, and to be ticked every frame
PrimaryComponentTick.bCanEverTick = true;
}
// Called when the game starts
void UBloodSystem::BeginPlay()
{
Super::BeginPlay();
}
// Called every frame
void UBloodSystem::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// Clean up finished blood effects
for (int32 i = ActiveBloodEffects.Num() - 1; i >= 0; --i)
{
if (!ActiveBloodEffects[i] || !ActiveBloodEffects[i]->IsActive())
{
ActiveBloodEffects.RemoveAt(i);
}
}
}
void UBloodSystem::SpawnBloodEffect(const FVector& Location, const FVector& Direction, float Intensity)
{
// Ensure we have a valid blood spray system
if (!BloodSpraySystem)
{
return;
}
// Manage the number of active blood effects
if (ActiveBloodEffects.Num() >= MaxBloodEffects)
{
// Remove the oldest blood effect
if (ActiveBloodEffects[0])
{
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);
}
}
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;
}

View File

@@ -0,0 +1,283 @@
#include "BooleanCutTool.h"
#include "Engine/StaticMesh.h"
#include "Engine/SkeletalMesh.h"
#include "ProceduralMeshComponent.h"
#include "Materials/MaterialInterface.h"
#include "GeometryScriptingCore.h"
#include "GeometryScript/MeshBooleanFunctions.h"
#include "GeometryScript/MeshPrimitiveFunctions.h"
#include "DynamicMesh/DynamicMesh3.h"
#include "GeometryScript/MeshTransformFunctions.h"
// Constructor
UBooleanCutTool::UBooleanCutTool()
{
}
// Perform boolean cut on static mesh
TArray<UStaticMesh*> UBooleanCutTool::CutStaticMesh(UStaticMesh* TargetMesh, const FCutPlane& CutPlane, bool bCreateCap)
{
TArray<UStaticMesh*> Result;
// Check if target mesh is valid
if (!TargetMesh)
{
return Result;
}
// Create cut plane mesh
UStaticMesh* CutPlaneMesh = CreateCutPlaneMesh(CutPlane);
if (!CutPlaneMesh)
{
return Result;
}
// Use GeometryScript to perform boolean cut
// Note: This is just a framework, actual implementation requires GeometryScript API
// Create positive part mesh
UStaticMesh* PositiveMesh = NewObject<UStaticMesh>();
// TODO: Use GeometryScript to perform boolean difference operation for positive part
// Create negative part mesh
UStaticMesh* NegativeMesh = NewObject<UStaticMesh>();
// TODO: Use GeometryScript to perform boolean difference operation for negative part
// If cap creation is needed
if (bCreateCap)
{
// TODO: Create cap for positive and negative parts
}
// Add to result array
Result.Add(PositiveMesh);
Result.Add(NegativeMesh);
return Result;
}
// Perform boolean cut on skeletal mesh
TArray<USkeletalMesh*> UBooleanCutTool::CutSkeletalMesh(USkeletalMesh* TargetMesh, const FCutPlane& CutPlane, FName BoneName, bool bCreateCap)
{
TArray<USkeletalMesh*> Result;
// Check if target mesh is valid
if (!TargetMesh)
{
return Result;
}
// Create cut plane mesh
UStaticMesh* CutPlaneMesh = CreateCutPlaneMesh(CutPlane);
if (!CutPlaneMesh)
{
return Result;
}
// Use GeometryScript to perform boolean cut
// Note: This is just a framework, actual implementation requires GeometryScript API
// If bone name is specified, only cut the part influenced by the bone
if (BoneName != NAME_None)
{
// TODO: Get vertices influenced by the bone, only cut these vertices
}
// Create positive part skeletal mesh
USkeletalMesh* PositiveMesh = NewObject<USkeletalMesh>();
// TODO: Use GeometryScript to perform boolean difference operation for positive part
// Create negative part skeletal mesh
USkeletalMesh* NegativeMesh = NewObject<USkeletalMesh>();
// TODO: Use GeometryScript to perform boolean difference operation for negative part
// If cap creation is needed
if (bCreateCap)
{
// TODO: Create cap for positive and negative parts
}
// Add to result array
Result.Add(PositiveMesh);
Result.Add(NegativeMesh);
return Result;
}
// Perform boolean cut on procedural mesh
TArray<UProceduralMeshComponent*> UBooleanCutTool::CutProceduralMesh(UProceduralMeshComponent* TargetMesh, const FCutPlane& CutPlane, bool bCreateCap)
{
TArray<UProceduralMeshComponent*> Result;
// Check if target mesh is valid
if (!TargetMesh)
{
return Result;
}
// Get mesh data
TArray<FVector> Vertices;
TArray<int32> Triangles;
TArray<FVector> Normals;
TArray<FVector2D> UVs;
TArray<FColor> VertexColors;
TArray<FProcMeshTangent> Tangents;
TargetMesh->GetSectionMeshData(0, Vertices, Triangles, Normals, UVs, VertexColors, Tangents);
// Calculate intersection points between cut plane and mesh
TArray<FVector> IntersectionPoints = CalculateIntersectionPoints(Vertices, Triangles, CutPlane);
// Create positive part procedural mesh
UProceduralMeshComponent* PositiveMesh = NewObject<UProceduralMeshComponent>(TargetMesh->GetOwner());
PositiveMesh->RegisterComponent();
// Create negative part procedural mesh
UProceduralMeshComponent* NegativeMesh = NewObject<UProceduralMeshComponent>(TargetMesh->GetOwner());
NegativeMesh->RegisterComponent();
// Split mesh
TArray<FVector> PositiveVertices;
TArray<int32> PositiveTriangles;
TArray<FVector> PositiveNormals;
TArray<FVector2D> PositiveUVs;
TArray<FColor> PositiveVertexColors;
TArray<FProcMeshTangent> PositiveTangents;
TArray<FVector> NegativeVertices;
TArray<int32> NegativeTriangles;
TArray<FVector> NegativeNormals;
TArray<FVector2D> NegativeUVs;
TArray<FColor> NegativeVertexColors;
TArray<FProcMeshTangent> NegativeTangents;
// TODO: Split mesh data based on cut plane
// Create positive part mesh
PositiveMesh->CreateMeshSection(0, PositiveVertices, PositiveTriangles, PositiveNormals, PositiveUVs, PositiveVertexColors, PositiveTangents, true);
// Create negative part mesh
NegativeMesh->CreateMeshSection(0, NegativeVertices, NegativeTriangles, NegativeNormals, NegativeUVs, NegativeVertexColors, NegativeTangents, true);
// If cap creation is needed
if (bCreateCap)
{
CreateCapMesh(IntersectionPoints, CutPlane, PositiveMesh);
CreateCapMesh(IntersectionPoints, CutPlane, NegativeMesh);
}
// Set material
if (CutMaterial)
{
PositiveMesh->SetMaterial(0, TargetMesh->GetMaterial(0));
PositiveMesh->SetMaterial(1, CutMaterial);
NegativeMesh->SetMaterial(0, TargetMesh->GetMaterial(0));
NegativeMesh->SetMaterial(1, CutMaterial);
}
// Add to result array
Result.Add(PositiveMesh);
Result.Add(NegativeMesh);
return Result;
}
// Create cut plane mesh
UStaticMesh* UBooleanCutTool::CreateCutPlaneMesh(const FCutPlane& CutPlane)
{
// Create a plane mesh
UStaticMesh* PlaneMesh = NewObject<UStaticMesh>();
// TODO: Use GeometryScript to create plane mesh
// Note: This is just a framework, actual implementation requires GeometryScript API
return PlaneMesh;
}
// Set cut material
void UBooleanCutTool::SetCutMaterial(UMaterialInterface* Material)
{
CutMaterial = Material;
}
// Get cut material
UMaterialInterface* UBooleanCutTool::GetCutMaterial() const
{
return CutMaterial;
}
// Calculate intersection points between cut plane and mesh
TArray<FVector> UBooleanCutTool::CalculateIntersectionPoints(const TArray<FVector>& Vertices, const TArray<int32>& Indices, const FCutPlane& CutPlane)
{
TArray<FVector> IntersectionPoints;
// Check if index array is for triangles
if (Indices.Num() % 3 != 0)
{
return IntersectionPoints;
}
// Iterate through all triangles
for (int32 i = 0; i < Indices.Num(); i += 3)
{
// Get three vertices of the triangle
FVector V0 = Vertices[Indices[i]];
FVector V1 = Vertices[Indices[i + 1]];
FVector V2 = Vertices[Indices[i + 2]];
// Calculate signed distance from each vertex to the cut plane
float D0 = FVector::DotProduct(V0 - CutPlane.Location, CutPlane.Normal);
float D1 = FVector::DotProduct(V1 - CutPlane.Location, CutPlane.Normal);
float D2 = FVector::DotProduct(V2 - CutPlane.Location, CutPlane.Normal);
// Check if triangle intersects with cut plane
if ((D0 * D1 <= 0.0f) || (D0 * D2 <= 0.0f) || (D1 * D2 <= 0.0f))
{
// Calculate intersection points of edges with cut plane
if (D0 * D1 <= 0.0f)
{
// Edge V0-V1 intersects with cut plane
float T = D0 / (D0 - D1);
FVector IntersectionPoint = V0 + T * (V1 - V0);
IntersectionPoints.Add(IntersectionPoint);
}
if (D0 * D2 <= 0.0f)
{
// Edge V0-V2 intersects with cut plane
float T = D0 / (D0 - D2);
FVector IntersectionPoint = V0 + T * (V2 - V0);
IntersectionPoints.Add(IntersectionPoint);
}
if (D1 * D2 <= 0.0f)
{
// Edge V1-V2 intersects with cut plane
float T = D1 / (D1 - D2);
FVector IntersectionPoint = V1 + T * (V2 - V1);
IntersectionPoints.Add(IntersectionPoint);
}
}
}
return IntersectionPoints;
}
// Create cap mesh
void UBooleanCutTool::CreateCapMesh(const TArray<FVector>& IntersectionPoints, const FCutPlane& CutPlane, UProceduralMeshComponent* TargetMesh)
{
// Check if there are enough intersection points
if (IntersectionPoints.Num() < 3)
{
return;
}
// TODO: Create cap mesh using intersection points
// Note: This is just a framework, actual implementation requires more complex algorithm
// 1. Project intersection points onto cut plane
// 2. Triangulate projected points
// 3. Create cap mesh
// 4. Add to target mesh
}

View File

@@ -0,0 +1,276 @@
#include "DismembermentSystem.h"
#include "ProceduralMeshComponent.h"
#include "PhysicsEngine/PhysicsAsset.h"
#include "Components/SkeletalMeshComponent.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "Materials/MaterialInterface.h"
#include "Kismet/GameplayStatics.h"
// Sets default values for this component's properties
UDismembermentSystem::UDismembermentSystem()
{
// Set this component to be initialized when the game starts, and to be ticked every frame
PrimaryComponentTick.bCanEverTick = true;
}
// Called when the game starts
void UDismembermentSystem::BeginPlay()
{
Super::BeginPlay();
// Get the skeletal mesh component from the owner
AActor* Owner = GetOwner();
if (Owner)
{
TargetMesh = Owner->FindComponentByClass<USkeletalMeshComponent>();
}
}
// Called every frame
void UDismembermentSystem::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
}
bool UDismembermentSystem::PerformCut(const FVector& CutLocation, const FVector& CutDirection, float CutWidth, float CutDepth)
{
// Ensure we have a valid target mesh
if (!TargetMesh)
{
return false;
}
// Implementation will use Geometry Script to perform boolean cutting operations
// This is a placeholder for the actual implementation
// Convert world location to local space
FVector LocalCutLocation = TargetMesh->GetComponentTransform().InverseTransformPosition(CutLocation);
FVector LocalCutDirection = TargetMesh->GetComponentTransform().InverseTransformVector(CutDirection);
// TODO: Implement real-time boolean cutting using Geometry Script
return true;
}
bool UDismembermentSystem::DismemberAtBone(const FName& BoneName, const FVector& CutDirection, EDismembermentType DismembermentType)
{
// Ensure we have a valid target mesh
if (!TargetMesh)
{
return false;
}
// Check if the bone exists
int32 BoneIndex = TargetMesh->GetBoneIndex(BoneName);
if (BoneIndex == INDEX_NONE)
{
return false;
}
// Find the bone data
int32 RegisteredBoneIndex = FindBoneIndex(BoneName);
if (RegisteredBoneIndex == INDEX_NONE)
{
// Bone not registered for dismemberment
return false;
}
// Check if the bone is already dismembered
if (RegisteredBones[RegisteredBoneIndex].bIsDismembered)
{
// Already dismembered
return false;
}
// Get the transform of the bone
FTransform BoneTransform = TargetMesh->GetBoneTransform(BoneIndex);
// Create a procedural mesh for the dismembered part
UProceduralMeshComponent* DismemberedPart = CreateProceduralMeshFromSkeletalMesh(TargetMesh, 0, 0);
if (!DismemberedPart)
{
return false;
}
// Add the dismembered part to the map
DismemberedParts.Add(BoneName, DismemberedPart);
// Mark the bone as dismembered
RegisteredBones[RegisteredBoneIndex].bIsDismembered = true;
// Spawn blood effect at the cut location
SpawnBloodEffect(BoneTransform.GetLocation(), CutDirection);
// Hide the bone in the original skeletal mesh
// This requires modifying the skeletal mesh's vertex weights or using a material to hide the bone
return true;
}
bool UDismembermentSystem::ApplyBoneDamage(const FName& BoneName, float Damage, const FVector& DamageLocation, const FVector& DamageDirection, EDismembermentType DismembermentType)
{
// Find the bone data
int32 RegisteredBoneIndex = FindBoneIndex(BoneName);
if (RegisteredBoneIndex == INDEX_NONE)
{
// Bone not registered for dismemberment
return false;
}
// Check if the bone is already dismembered
if (RegisteredBones[RegisteredBoneIndex].bIsDismembered)
{
// Already dismembered
return false;
}
// Apply damage to the bone
RegisteredBones[RegisteredBoneIndex].Health -= Damage;
// Check if the bone should be dismembered
if (RegisteredBones[RegisteredBoneIndex].Health <= RegisteredBones[RegisteredBoneIndex].DismembermentThreshold)
{
// Dismember the bone
return DismemberAtBone(BoneName, DamageDirection, DismembermentType);
}
// Spawn a smaller blood effect to indicate damage
if (Damage > 0)
{
SpawnBloodEffect(DamageLocation, DamageDirection, FMath::Clamp(Damage / 100.0f, 0.1f, 1.0f));
}
return true;
}
bool UDismembermentSystem::RegisterBone(const FDismembermentBoneData& BoneData)
{
// Check if the bone already exists
for (int32 i = 0; i < RegisteredBones.Num(); ++i)
{
if (RegisteredBones[i].BoneName == BoneData.BoneName)
{
// Update existing bone data
RegisteredBones[i] = BoneData;
return true;
}
}
// Add new bone data
RegisteredBones.Add(BoneData);
return true;
}
void UDismembermentSystem::SetBloodEffect(UNiagaraSystem* BloodEffect)
{
BloodEffectSystem = BloodEffect;
}
void UDismembermentSystem::SetCutMaterial(UMaterialInterface* CutMaterial)
{
CutSurfaceMaterial = CutMaterial;
}
bool UDismembermentSystem::GetBoneData(const FName& BoneName, FDismembermentBoneData& OutBoneData) const
{
int32 BoneIndex = FindBoneIndex(BoneName);
if (BoneIndex != INDEX_NONE)
{
OutBoneData = RegisteredBones[BoneIndex];
return true;
}
return false;
}
TArray<FDismembermentBoneData> UDismembermentSystem::GetAllBones() const
{
return RegisteredBones;
}
void UDismembermentSystem::ResetDismemberment()
{
// Reset all bones
for (int32 i = 0; i < RegisteredBones.Num(); ++i)
{
RegisteredBones[i].bIsDismembered = false;
RegisteredBones[i].Health = 100.0f;
}
// Destroy all dismembered parts
for (auto& Part : DismemberedParts)
{
if (Part.Value)
{
Part.Value->DestroyComponent();
}
}
DismemberedParts.Empty();
// Show all bones in the original skeletal mesh
// This requires restoring the skeletal mesh's vertex weights or material
}
UProceduralMeshComponent* UDismembermentSystem::CreateProceduralMeshFromSkeletalMesh(USkeletalMeshComponent* SkelMesh, int32 LODIndex, int32 SectionIndex)
{
// Ensure we have a valid skeletal mesh
if (!SkelMesh)
{
return nullptr;
}
// Create a new procedural mesh component
UProceduralMeshComponent* ProcMesh = NewObject<UProceduralMeshComponent>(GetOwner());
ProcMesh->RegisterComponent();
// TODO: Extract mesh data from the skeletal mesh and create a procedural mesh
// This will involve:
// 1. Getting vertex positions, normals, UVs, etc. from the skeletal mesh
// 2. Creating triangles for the procedural mesh
// 3. Setting up materials
// 4. Setting up collision
return ProcMesh;
}
void UDismembermentSystem::SpawnBloodEffect(const FVector& Location, const FVector& Direction, float Intensity)
{
// Ensure we have a valid blood effect system
if (!BloodEffectSystem)
{
return;
}
// Create a rotation from the direction
FRotator Rotation = Direction.Rotation();
// Spawn the blood effect
UNiagaraComponent* BloodEffect = UNiagaraFunctionLibrary::SpawnSystemAtLocation(
GetWorld(),
BloodEffectSystem,
Location,
Rotation,
FVector(Intensity),
true,
true,
ENCPoolMethod::AutoRelease
);
if (BloodEffect)
{
// Set the intensity parameter if it exists
BloodEffect->SetFloatParameter(FName("Intensity"), Intensity);
}
}
int32 UDismembermentSystem::FindBoneIndex(const FName& BoneName) const
{
for (int32 i = 0; i < RegisteredBones.Num(); ++i)
{
if (RegisteredBones[i].BoneName == BoneName)
{
return i;
}
}
return INDEX_NONE;
}

View File

@@ -0,0 +1,20 @@
#include "FLESHModule.h"
#include "Modules/ModuleManager.h"
#define LOCTEXT_NAMESPACE "FFLESHModule"
void FFLESHModule::StartupModule()
{
// This code will execute after your module is loaded into memory
// The exact timing is specified in the .uplugin file per-module
}
void FFLESHModule::ShutdownModule()
{
// This function may be called during shutdown to clean up your module
// For modules that support dynamic reloading, we call this function before unloading the module
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FFLESHModule, FLESH)

View File

@@ -0,0 +1,159 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "AnatomicalLayerSystem.generated.h"
/**
* Anatomical layer type enumeration
*/
UENUM(BlueprintType)
enum class EAnatomicalLayerType : uint8
{
Skin,
Muscle,
Bone,
Organ,
Blood,
Custom
};
/**
* Anatomical layer data structure
*/
USTRUCT(BlueprintType)
struct FAnatomicalLayer
{
GENERATED_BODY()
// Layer name
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
FName LayerName;
// Layer type
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
EAnatomicalLayerType LayerType;
// Layer mesh
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
TObjectPtr<UStaticMesh> LayerMesh;
// Layer material
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
TObjectPtr<UMaterialInterface> LayerMaterial;
// Layer thickness
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
float Thickness = 1.0f;
// Layer density
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
float Density = 1.0f;
// Layer elasticity
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
float Elasticity = 0.5f;
// Layer fracture threshold
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
float FractureThreshold = 100.0f;
// Enable physics
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
bool bEnablePhysics = true;
// Is visible
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Anatomy")
bool bVisible = true;
// Constructor
FAnatomicalLayer()
: LayerName(NAME_None)
, LayerType(EAnatomicalLayerType::Skin)
, LayerMesh(nullptr)
, LayerMaterial(nullptr)
{
}
};
/**
* Anatomical layer system class
* Manages multi-layer system for bones, organs and physics properties
*/
UCLASS(BlueprintType, Blueprintable)
class FLESH_API UAnatomicalLayerSystem : public UObject
{
GENERATED_BODY()
public:
// Constructor
UAnatomicalLayerSystem();
/**
* Add a new anatomical layer
* @param LayerName - Layer name
* @param LayerType - Layer type
* @return Index of the newly added layer
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
int32 AddLayer(const FName& LayerName, EAnatomicalLayerType LayerType);
/**
* Remove an anatomical layer by index
* @param LayerIndex - Layer index
* @return Whether the removal was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
bool RemoveLayer(int32 LayerIndex);
/**
* Get an anatomical layer by index
* @param LayerIndex - Layer index
* @return Anatomical layer data
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
FAnatomicalLayer GetLayer(int32 LayerIndex) const;
/**
* Get all anatomical layers
* @return Array of anatomical layers
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
TArray<FAnatomicalLayer> GetAllLayers() const;
/**
* Set an anatomical layer by index
* @param LayerIndex - Layer index
* @param Layer - New layer data
* @return Whether the setting was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
bool SetLayer(int32 LayerIndex, const FAnatomicalLayer& Layer);
/**
* Get the number of layers
* @return Number of layers
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
int32 GetLayerCount() const;
/**
* Get layers by type
* @param LayerType - Layer type
* @return Array of layers matching the type
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
TArray<FAnatomicalLayer> GetLayersByType(EAnatomicalLayerType LayerType) const;
/**
* Set physics for all layers
* @param bEnable - Whether to enable physics
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Anatomy")
void SetPhysicsForAllLayers(bool bEnable);
private:
// Array of anatomical layers
UPROPERTY(EditAnywhere, Category = "FLESH|Anatomy")
TArray<FAnatomicalLayer> Layers;
};

View File

@@ -0,0 +1,92 @@
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BloodPool.generated.h"
// Forward declarations
class UBoxComponent;
class UDecalComponent;
class UMaterialInterface;
/**
* Blood pool actor class, used to create blood pools on surfaces
*/
UCLASS()
class FLESH_API ABloodPool : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ABloodPool();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
/**
* Set the blood pool size
* @param NewSize - New size for the blood pool
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Blood")
void SetPoolSize(float NewSize);
/**
* Set the blood pool color
* @param NewColor - New color for the blood pool
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Blood")
void SetPoolColor(const FLinearColor& NewColor);
/**
* Start blood pool expansion
* @param ExpansionRate - Rate of expansion
* @param MaxSize - Maximum size
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Blood")
void StartExpansion(float ExpansionRate = 1.0f, float MaxSize = 3.0f);
private:
// Collision component for surface detection
UPROPERTY(VisibleAnywhere, Category = "Components")
TObjectPtr<UBoxComponent> Collision;
// Decal component for rendering the blood pool
UPROPERTY(VisibleAnywhere, Category = "Components")
TObjectPtr<UDecalComponent> Decal;
// Blood pool decal material
UPROPERTY(EditAnywhere, Category = "Appearance")
TObjectPtr<UMaterialInterface> DecalMaterial;
// Current blood pool size
UPROPERTY(EditAnywhere, Category = "Appearance")
float PoolSize = 1.0f;
// Blood pool color
UPROPERTY(EditAnywhere, Category = "Appearance")
FLinearColor PoolColor = FLinearColor::Red;
// Expansion rate
UPROPERTY(EditAnywhere, Category = "Expansion")
float ExpansionRate = 0.5f;
// Maximum blood pool size
UPROPERTY(EditAnywhere, Category = "Expansion")
float MaxPoolSize = 2.0f;
// Whether the pool is expanding
UPROPERTY()
bool bIsExpanding = false;
// Blood pool expansion timer handle
FTimerHandle ExpansionTimerHandle;
// Internal function to update the blood pool size
void UpdatePoolSize();
// Internal function to expand the blood pool
void ExpandPool();
};

View File

@@ -0,0 +1,98 @@
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "NiagaraSystem.h"
#include "BloodSystem.generated.h"
// Forward declarations
class UNiagaraComponent;
class UDecalComponent;
/**
* Blood system component for the FLESH plugin
* Handles blood effects, pools, and decals
*/
UCLASS(ClassGroup=(FLESH), meta=(BlueprintSpawnableComponent))
class FLESH_API UBloodSystem : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UBloodSystem();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
/**
* Spawn blood effect at the specified location
* @param Location - World location to spawn the blood effect
* @param Direction - Direction of the blood spray
* @param Intensity - Intensity of the blood effect (0.0-1.0)
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Blood")
void SpawnBloodEffect(const FVector& Location, const FVector& Direction, float Intensity = 1.0f);
/**
* Create a blood pool at the specified location
* @param Location - World location to create the blood pool
* @param Size - Size of the blood pool
* @return The created blood pool actor
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Blood")
AActor* CreateBloodPool(const FVector& Location, float Size = 1.0f);
/**
* Apply a blood decal to the specified component
* @param Component - Component to apply the blood decal to
* @param Location - World location of the decal
* @param Direction - Direction the decal should face
* @param Size - Size of the decal
* @return The created decal component
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Blood")
UDecalComponent* ApplyBloodDecal(UPrimitiveComponent* Component, const FVector& Location, const FVector& Direction, float Size = 1.0f);
private:
// Niagara system for blood spray effects
UPROPERTY(EditAnywhere, Category = "FLESH|Blood", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UNiagaraSystem> BloodSpraySystem;
// Material for blood decals
UPROPERTY(EditAnywhere, Category = "FLESH|Blood", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UMaterialInterface> BloodDecalMaterial;
// Blood pool class to spawn
UPROPERTY(EditAnywhere, Category = "FLESH|Blood", meta = (AllowPrivateAccess = "true"))
TSubclassOf<AActor> BloodPoolClass;
// Active blood effects
UPROPERTY()
TArray<TObjectPtr<UNiagaraComponent>> ActiveBloodEffects;
// Active blood decals
UPROPERTY()
TArray<TObjectPtr<UDecalComponent>> ActiveBloodDecals;
// Active blood pools
UPROPERTY()
TArray<TObjectPtr<AActor>> ActiveBloodPools;
// Maximum number of active blood effects
UPROPERTY(EditAnywhere, Category = "FLESH|Blood|Limits", meta = (AllowPrivateAccess = "true"))
int32 MaxBloodEffects = 10;
// Maximum number of active blood decals
UPROPERTY(EditAnywhere, Category = "FLESH|Blood|Limits", meta = (AllowPrivateAccess = "true"))
int32 MaxBloodDecals = 30;
// Maximum number of active blood pools
UPROPERTY(EditAnywhere, Category = "FLESH|Blood|Limits", meta = (AllowPrivateAccess = "true"))
int32 MaxBloodPools = 5;
};

View File

@@ -0,0 +1,129 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "BooleanCutTool.generated.h"
// Forward declarations
class UStaticMesh;
class USkeletalMesh;
class UProceduralMeshComponent;
/**
* Cut plane definition
*/
USTRUCT(BlueprintType)
struct FCutPlane
{
GENERATED_BODY()
// Cut plane location
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Cutting")
FVector Location;
// Cut plane normal
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Cutting")
FVector Normal;
// Cut plane width
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Cutting")
float Width = 100.0f;
// Cut plane height
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Cutting")
float Height = 100.0f;
// Constructor
FCutPlane()
: Location(FVector::ZeroVector)
, Normal(FVector::UpVector)
{
}
// Constructor with parameters
FCutPlane(const FVector& InLocation, const FVector& InNormal, float InWidth = 100.0f, float InHeight = 100.0f)
: Location(InLocation)
, Normal(InNormal)
, Width(InWidth)
, Height(InHeight)
{
}
};
/**
* Boolean cut tool class
* Provides real-time boolean cutting functionality
*/
UCLASS(BlueprintType)
class FLESH_API UBooleanCutTool : public UObject
{
GENERATED_BODY()
public:
// Constructor
UBooleanCutTool();
/**
* Perform boolean cut on static mesh
* @param TargetMesh - Target static mesh
* @param CutPlane - Cut plane
* @param bCreateCap - Whether to create a cap
* @return Array of cut meshes [0] is positive side, [1] is negative side
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Cutting")
TArray<UStaticMesh*> CutStaticMesh(UStaticMesh* TargetMesh, const FCutPlane& CutPlane, bool bCreateCap = true);
/**
* Perform boolean cut on skeletal mesh
* @param TargetMesh - Target skeletal mesh
* @param CutPlane - Cut plane
* @param BoneName - Bone name, if specified only cuts the part influenced by this bone
* @param bCreateCap - Whether to create a cap
* @return Array of cut skeletal meshes [0] is positive side, [1] is negative side
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Cutting")
TArray<USkeletalMesh*> CutSkeletalMesh(USkeletalMesh* TargetMesh, const FCutPlane& CutPlane, FName BoneName = NAME_None, bool bCreateCap = true);
/**
* Perform boolean cut on procedural mesh
* @param TargetMesh - Target procedural mesh
* @param CutPlane - Cut plane
* @param bCreateCap - Whether to create a cap
* @return Array of cut procedural meshes [0] is positive side, [1] is negative side
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Cutting")
TArray<UProceduralMeshComponent*> CutProceduralMesh(UProceduralMeshComponent* TargetMesh, const FCutPlane& CutPlane, bool bCreateCap = true);
/**
* Create cut plane mesh
* @param CutPlane - Cut plane
* @return Cut plane mesh
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Cutting")
UStaticMesh* CreateCutPlaneMesh(const FCutPlane& CutPlane);
/**
* Set cut material
* @param Material - Cut material
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Cutting")
void SetCutMaterial(UMaterialInterface* Material);
/**
* Get cut material
* @return Current cut material
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Cutting")
UMaterialInterface* GetCutMaterial() const;
private:
// Cut material
UPROPERTY()
TObjectPtr<UMaterialInterface> CutMaterial;
// Internal function to calculate intersection points between cut plane and mesh
TArray<FVector> CalculateIntersectionPoints(const TArray<FVector>& Vertices, const TArray<int32>& Indices, const FCutPlane& CutPlane);
// Internal function to create cap mesh
void CreateCapMesh(const TArray<FVector>& IntersectionPoints, const FCutPlane& CutPlane, UProceduralMeshComponent* TargetMesh);
};

View File

@@ -0,0 +1,87 @@
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "DismemberedAnimInstance.generated.h"
/**
* Animation instance class for dismembered body parts
* Handles animation of separated limbs and body parts
*/
UCLASS()
class FLESH_API UDismemberedAnimInstance : public UAnimInstance
{
GENERATED_BODY()
public:
// Constructor
UDismemberedAnimInstance();
// Called when animation updates
virtual void NativeUpdateAnimation(float DeltaSeconds) override;
// Called to initialize animation
virtual void NativeInitializeAnimation() override;
/**
* Set the source bone name this dismembered part was cut from
* @param BoneName - Name of the source bone
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Animation")
void SetSourceBone(const FName& BoneName);
/**
* Set the cut type for this dismembered part
* @param CutType - Type of cut that created this part
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Animation")
void SetCutType(int32 CutType);
/**
* Apply an impulse to the dismembered part
* @param Impulse - Impulse vector to apply
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Animation")
void ApplyImpulse(const FVector& Impulse);
private:
// Name of the bone this part was cut from
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName SourceBoneName;
// Type of cut that created this part
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
int32 CutType;
// Root bone name
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName RootBoneName;
// Head bone name
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName HeadBoneName;
// Left arm bone name
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName LeftArmBoneName;
// Right arm bone name
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName RightArmBoneName;
// Left leg bone name
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName LeftLegBoneName;
// Right leg bone name
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FName RightLegBoneName;
// Current angular velocity
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FVector AngularVelocity;
// Current linear velocity
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "FLESH|Animation", meta = (AllowPrivateAccess = "true"))
FVector LinearVelocity;
};

View File

@@ -0,0 +1,41 @@
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "DismembermentGraphAsset.generated.h"
/**
* Asset that contains a dismemberment graph
* Used for visual programming of dismemberment logic
*/
UCLASS(BlueprintType)
class FLESH_API UDismembermentGraphAsset : public UObject
{
GENERATED_BODY()
public:
UDismembermentGraphAsset();
// The graph owned by this asset
UPROPERTY()
class UDismembermentGraph* Graph;
// Compile the graph into executable logic
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool CompileGraph();
// Execute the compiled graph
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool ExecuteGraph(class AActor* TargetActor);
#if WITH_EDITOR
// Called when the asset is created
virtual void PostInitProperties() override;
// Called when the asset is duplicated
virtual void PostDuplicate(bool bDuplicateForPIE) override;
// Called when the asset is loaded
virtual void PostLoad() override;
#endif
};

View File

@@ -0,0 +1,204 @@
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "DismembermentSystem.generated.h"
// Forward declarations
class USkeletalMeshComponent;
class UProceduralMeshComponent;
class UNiagaraSystem;
class UMaterialInterface;
/**
* Bone dismemberment type enumeration
*/
UENUM(BlueprintType)
enum class EDismembermentType : uint8
{
None,
Cut, // Clean cut
Tear, // Torn flesh
Crush, // Crushed bone
Blast, // Explosion damage
Burn, // Burn damage
Custom // Custom dismemberment type
};
/**
* Bone data structure for dismemberment
*/
USTRUCT(BlueprintType)
struct FDismembermentBoneData
{
GENERATED_BODY()
// Bone name
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
FName BoneName;
// Parent bone name
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
FName ParentBoneName;
// Bone health
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
float Health = 100.0f;
// Damage threshold before dismemberment
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
float DismembermentThreshold = 50.0f;
// Blood effect socket name
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
FName BloodSocketName;
// Whether this bone can be dismembered
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
bool bCanBeDismembered = true;
// Whether this bone is critical (death if dismembered)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
bool bIsCritical = false;
// Whether this bone is already dismembered
UPROPERTY(BlueprintReadOnly, Category = "FLESH|Dismemberment")
bool bIsDismembered = false;
// Constructor
FDismembermentBoneData()
: BoneName(NAME_None)
, ParentBoneName(NAME_None)
, BloodSocketName(NAME_None)
{
}
};
/**
* Main component for the FLESH dismemberment system
* Handles real-time boolean cutting, multi-layer cutting, and physics interactions
*/
UCLASS(ClassGroup=(FLESH), meta=(BlueprintSpawnableComponent))
class FLESH_API UDismembermentSystem : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UDismembermentSystem();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
/**
* Perform a cut on the owner's mesh at the specified location and direction
* @param CutLocation - World location of the cut
* @param CutDirection - Direction of the cut
* @param CutWidth - Width of the cut
* @param CutDepth - Depth of the cut
* @return True if the cut was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool PerformCut(const FVector& CutLocation, const FVector& CutDirection, float CutWidth = 1.0f, float CutDepth = 10.0f);
/**
* Perform a dismemberment at the specified bone
* @param BoneName - Name of the bone to dismember
* @param CutDirection - Direction of the cut
* @param DismembermentType - Type of dismemberment to perform
* @return True if the dismemberment was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool DismemberAtBone(const FName& BoneName, const FVector& CutDirection, EDismembermentType DismembermentType = EDismembermentType::Cut);
/**
* Apply damage to a specific bone
* @param BoneName - Name of the bone to damage
* @param Damage - Amount of damage to apply
* @param DamageLocation - World location of the damage
* @param DamageDirection - Direction of the damage
* @param DismembermentType - Type of damage for potential dismemberment
* @return True if damage was applied
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool ApplyBoneDamage(const FName& BoneName, float Damage, const FVector& DamageLocation, const FVector& DamageDirection, EDismembermentType DismembermentType = EDismembermentType::Cut);
/**
* Register a bone for dismemberment
* @param BoneData - Bone data to register
* @return True if the bone was registered
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool RegisterBone(const FDismembermentBoneData& BoneData);
/**
* Set the blood effect for dismemberment
* @param BloodEffect - Niagara system for blood effects
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void SetBloodEffect(UNiagaraSystem* BloodEffect);
/**
* Set the cut material for dismemberment
* @param CutMaterial - Material to use for cut surfaces
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void SetCutMaterial(UMaterialInterface* CutMaterial);
/**
* Get the bone data for a specific bone
* @param BoneName - Name of the bone
* @param OutBoneData - Output bone data
* @return True if the bone data was found
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool GetBoneData(const FName& BoneName, FDismembermentBoneData& OutBoneData) const;
/**
* Get all registered bones
* @return Array of all registered bone data
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
TArray<FDismembermentBoneData> GetAllBones() const;
/**
* Reset all dismemberment (restore all bones)
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void ResetDismemberment();
private:
// The skeletal mesh to perform dismemberment on
UPROPERTY()
TObjectPtr<USkeletalMeshComponent> TargetMesh;
// Map of bone names to their corresponding procedural mesh components
UPROPERTY()
TMap<FName, TObjectPtr<UProceduralMeshComponent>> DismemberedParts;
// Registered bones for dismemberment
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment")
TArray<FDismembermentBoneData> RegisteredBones;
// Niagara system for blood effects
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment")
TObjectPtr<UNiagaraSystem> BloodEffectSystem;
// Material for cut surfaces
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment")
TObjectPtr<UMaterialInterface> CutSurfaceMaterial;
// Internal function to create a procedural mesh from a skeletal mesh section
UProceduralMeshComponent* CreateProceduralMeshFromSkeletalMesh(USkeletalMeshComponent* SkelMesh, int32 LODIndex, int32 SectionIndex);
// Internal function to spawn blood effects
void SpawnBloodEffect(const FVector& Location, const FVector& Direction, float Intensity = 1.0f);
// Internal function to find bone index by name
int32 FindBoneIndex(const FName& BoneName) const;
};

View File

@@ -0,0 +1,245 @@
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "NiagaraSystem.h"
#include "DismembermentSystem.h"
#include "FLESHDismembermentComponent.generated.h"
// Forward declarations
class USkeletalMeshComponent;
class UNiagaraSystem;
class UMaterialInterface;
/**
* Bone patch type for customizing dismemberment effects
*/
UENUM(BlueprintType)
enum class EBonePatchType : uint8
{
Default, // Default patch
Head, // Head specific patch
Arm, // Arm specific patch
Leg, // Leg specific patch
Torso, // Torso specific patch
Custom // Custom patch
};
/**
* Bone patch data structure for customizing dismemberment effects
*/
USTRUCT(BlueprintType)
struct FBonePatchData
{
GENERATED_BODY()
// Patch type
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
EBonePatchType PatchType = EBonePatchType::Default;
// Bone names affected by this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
TArray<FName> BoneNames;
// Custom cut material for this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
TObjectPtr<UMaterialInterface> CustomCutMaterial = nullptr;
// Custom blood effect for this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
TObjectPtr<UNiagaraSystem> CustomBloodEffect = nullptr;
// Damage multiplier for this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment", meta = (ClampMin = "0.0", ClampMax = "10.0"))
float DamageMultiplier = 1.0f;
// Whether this patch has organs
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
bool bHasOrgans = false;
// Organ mesh for this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment", meta = (EditCondition = "bHasOrgans"))
TObjectPtr<UStaticMesh> OrganMesh = nullptr;
// Organ material for this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment", meta = (EditCondition = "bHasOrgans"))
TObjectPtr<UMaterialInterface> OrganMaterial = nullptr;
// Whether this patch has custom physics
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment")
bool bHasCustomPhysics = false;
// Physics asset for this patch
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FLESH|Dismemberment", meta = (EditCondition = "bHasCustomPhysics"))
TObjectPtr<UPhysicsAsset> CustomPhysicsAsset = nullptr;
// Constructor
FBonePatchData()
{
}
};
/**
* Main component for the FLESH dismemberment system with blueprint support
* Provides easy-to-use blueprint interface for the dismemberment system
*/
UCLASS(ClassGroup=(FLESH), meta=(BlueprintSpawnableComponent))
class FLESH_API UFLESHDismembermentComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UFLESHDismembermentComponent();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
/**
* Perform a cut at the specified location and direction
* @param CutLocation - World location of the cut
* @param CutDirection - Direction of the cut
* @param CutWidth - Width of the cut
* @param CutDepth - Depth of the cut
* @return True if the cut was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool PerformCut(const FVector& CutLocation, const FVector& CutDirection, float CutWidth = 1.0f, float CutDepth = 10.0f);
/**
* Perform a cut using a transformation matrix
* @param CutTransform - Transformation matrix for the cut
* @param CutWidth - Width of the cut
* @param CutDepth - Depth of the cut
* @return True if the cut was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool PerformCutWithMatrix(const FMatrix& CutTransform, float CutWidth = 1.0f, float CutDepth = 10.0f);
/**
* Dismember a specific bone
* @param BoneName - Name of the bone to dismember
* @param DismembermentType - Type of dismemberment to perform
* @return True if the dismemberment was successful
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool DismemberBone(const FName& BoneName, EDismembermentType DismembermentType = EDismembermentType::Cut);
/**
* Apply damage to a specific bone
* @param BoneName - Name of the bone to damage
* @param Damage - Amount of damage to apply
* @param DamageLocation - World location of the damage
* @param DamageDirection - Direction of the damage
* @param DismembermentType - Type of damage for potential dismemberment
* @return True if damage was applied
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool ApplyBoneDamage(const FName& BoneName, float Damage, const FVector& DamageLocation, const FVector& DamageDirection, EDismembermentType DismembermentType = EDismembermentType::Cut);
/**
* Add a bone patch
* @param PatchData - Patch data to add
* @return True if the patch was added
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool AddBonePatch(const FBonePatchData& PatchData);
/**
* Remove a bone patch
* @param PatchType - Type of patch to remove
* @return True if the patch was removed
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool RemoveBonePatch(EBonePatchType PatchType);
/**
* Get a bone patch by type
* @param PatchType - Type of patch to get
* @param OutPatchData - Output patch data
* @return True if the patch was found
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
bool GetBonePatch(EBonePatchType PatchType, FBonePatchData& OutPatchData) const;
/**
* Get all bone patches
* @return Array of all bone patches
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
TArray<FBonePatchData> GetAllBonePatches() const;
/**
* Reset all dismemberment (restore all bones)
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void ResetDismemberment();
/**
* Set the blood effect for dismemberment
* @param BloodEffect - Niagara system for blood effects
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void SetBloodEffect(UNiagaraSystem* BloodEffect);
/**
* Set the cut material for dismemberment
* @param CutMaterial - Material to use for cut surfaces
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void SetCutMaterial(UMaterialInterface* CutMaterial);
/**
* Set whether to show organs
* @param bShow - Whether to show organs
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void SetShowOrgans(bool bShow);
/**
* Set whether to enable physics
* @param bEnable - Whether to enable physics
*/
UFUNCTION(BlueprintCallable, Category = "FLESH|Dismemberment")
void SetEnablePhysics(bool bEnable);
private:
// The dismemberment system
UPROPERTY()
TObjectPtr<UDismembermentSystem> DismembermentSystem;
// The target skeletal mesh component
UPROPERTY()
TObjectPtr<USkeletalMeshComponent> TargetMesh;
// Default blood effect
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UNiagaraSystem> DefaultBloodEffect;
// Default cut material
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment", meta = (AllowPrivateAccess = "true"))
TObjectPtr<UMaterialInterface> DefaultCutMaterial;
// Whether to show organs
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment", meta = (AllowPrivateAccess = "true"))
bool bShowOrgans = true;
// Whether to enable physics
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment", meta = (AllowPrivateAccess = "true"))
bool bEnablePhysics = true;
// Bone patches
UPROPERTY(EditAnywhere, Category = "FLESH|Dismemberment", meta = (AllowPrivateAccess = "true"))
TArray<FBonePatchData> BonePatches;
// Internal function to find a bone patch by type
int32 FindBonePatchIndex(EBonePatchType PatchType) const;
// Internal function to apply a bone patch
void ApplyBonePatch(const FBonePatchData& PatchData);
};

View File

@@ -0,0 +1,21 @@
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
/**
* FLESH Module - Fully Locational Evisceration System for Humanoids
*/
class FLESH_API FFLESHModule : public IModuleInterface
{
public:
/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
/** Singleton getter */
static FFLESHModule& Get()
{
return FModuleManager::LoadModuleChecked<FFLESHModule>("FLESH");
}
};