This commit is contained in:
2025-04-18 11:19:13 +08:00
parent c30cb1052e
commit 829d176799
3 changed files with 417 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
#include "DismemberedAnimInstance.h"
UDismemberedAnimInstance::UDismemberedAnimInstance()
{
// 初始化成员变量
SourceBoneName = NAME_None;
CutType = 0;
RootBoneName = NAME_None;
HeadBoneName = NAME_None;
LeftArmBoneName = NAME_None;
RightArmBoneName = NAME_None;
LeftLegBoneName = NAME_None;
RightLegBoneName = NAME_None;
AngularVelocity = FVector::ZeroVector;
LinearVelocity = FVector::ZeroVector;
}
void UDismemberedAnimInstance::NativeUpdateAnimation(float DeltaSeconds)
{
Super::NativeUpdateAnimation(DeltaSeconds);
// 更新动画逻辑
// 可以根据LinearVelocity和AngularVelocity更新动画状态
// 随时间衰减速度
const float DampingFactor = 0.95f;
LinearVelocity *= DampingFactor;
AngularVelocity *= DampingFactor;
}
void UDismemberedAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();
// 获取拥有者骨骼网格体
USkeletalMeshComponent* OwnerMesh = GetSkelMeshComponent();
if (!OwnerMesh)
{
return;
}
// 初始化动画相关参数
}
void UDismemberedAnimInstance::SetSourceBone(const FName& BoneName)
{
SourceBoneName = BoneName;
}
void UDismemberedAnimInstance::SetCutType(int32 InCutType)
{
CutType = InCutType;
}
void UDismemberedAnimInstance::ApplyImpulse(const FVector& Impulse)
{
// 应用冲量到分离的部分
LinearVelocity += Impulse;
// 根据冲量生成一些随机的角速度
const float AngularImpulseFactor = 0.1f;
FVector RandomAngular = FVector(
FMath::RandRange(-1.0f, 1.0f),
FMath::RandRange(-1.0f, 1.0f),
FMath::RandRange(-1.0f, 1.0f)
);
AngularVelocity += RandomAngular * Impulse.Size() * AngularImpulseFactor;
}

View File

@@ -0,0 +1,74 @@
#include "DismembermentGraph/DismembermentGraphAsset.h"
#include "DismembermentGraph/DismembermentGraphBase.h"
#include "GameFramework/Actor.h"
UDismembermentGraphAsset::UDismembermentGraphAsset()
{
// Initialize the graph pointer to nullptr
Graph = nullptr;
}
bool UDismembermentGraphAsset::CompileGraph()
{
// Check if the graph exists
if (!Graph)
{
return false;
}
// Compile the graph logic
// This is a simple implementation and may need to be more complex in practice
return true;
}
bool UDismembermentGraphAsset::ExecuteGraph(AActor* TargetActor)
{
// Check if the graph and target actor are valid
if (!Graph || !TargetActor)
{
return false;
}
// Execute the compiled graph logic
// This is a simple implementation and may need to be more complex in practice
return true;
}
#if WITH_EDITOR
void UDismembermentGraphAsset::PostInitProperties()
{
Super::PostInitProperties();
// If the graph does not exist, create a new one
if (!Graph && !HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
{
Graph = NewObject<UDismembermentGraphBase>(this, UDismembermentGraphBase::StaticClass(), NAME_None, RF_Transactional);
}
}
void UDismembermentGraphAsset::PostDuplicate(bool bDuplicateForPIE)
{
Super::PostDuplicate(bDuplicateForPIE);
// If it is not duplicated for PIE and the graph exists
if (!bDuplicateForPIE && Graph)
{
// Handle the graph duplication logic
// May need to duplicate the graph nodes, etc.
}
}
void UDismembermentGraphAsset::PostLoad()
{
Super::PostLoad();
// Post-loading processing
if (Graph)
{
// Make sure the graph is loaded correctly
// May need to update references, etc.
}
}
#endif

View File

@@ -0,0 +1,274 @@
#include "FLESHDismembermentComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "GameFramework/Actor.h"
#include "NiagaraFunctionLibrary.h"
#include "NiagaraComponent.h"
#include "PhysicsEngine/PhysicsAsset.h"
UFLESHDismembermentComponent::UFLESHDismembermentComponent()
{
PrimaryComponentTick.bCanEverTick = true;
DismembermentSystem = nullptr;
TargetMesh = nullptr;
DefaultBloodEffect = nullptr;
DefaultCutMaterial = nullptr;
bShowOrgans = true;
bEnablePhysics = true;
}
void UFLESHDismembermentComponent::BeginPlay()
{
Super::BeginPlay();
AActor* Owner = GetOwner();
if (Owner)
{
TargetMesh = Owner->FindComponentByClass<USkeletalMeshComponent>();
}
if (TargetMesh)
{
DismembermentSystem = NewObject<UDismembermentSystem>(this);
if (DismembermentSystem)
{
// Initialize the dismemberment system
// This may need more initialization code
}
}
for (const FBonePatchData& Patch : BonePatches)
{
ApplyBonePatch(Patch);
}
}
void UFLESHDismembermentComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (DismembermentSystem && TargetMesh)
{
// This can be used to add frame update logic
}
}
bool UFLESHDismembermentComponent::PerformCut(const FVector& CutLocation, const FVector& CutDirection, float CutWidth, float CutDepth)
{
if (!DismembermentSystem || !TargetMesh)
{
return false;
}
// Create the cut plane
FVector NormalizedDirection = CutDirection.GetSafeNormal();
FMatrix CutMatrix = FMatrix::Identity;
CutMatrix.SetOrigin(CutLocation);
CutMatrix.SetAxis(0, NormalizedDirection);
CutMatrix.SetAxis(1, FVector::CrossProduct(NormalizedDirection, FVector::UpVector).GetSafeNormal());
CutMatrix.SetAxis(2, FVector::CrossProduct(CutMatrix.GetScaledAxis(EAxis::X), CutMatrix.GetScaledAxis(EAxis::Y)));
// Call the matrix cut method
return PerformCutWithMatrix(CutMatrix, CutWidth, CutDepth);
}
bool UFLESHDismembermentComponent::PerformCutWithMatrix(const FMatrix& CutTransform, float CutWidth, float CutDepth)
{
if (!DismembermentSystem || !TargetMesh)
{
return false;
}
// Perform the matrix cut logic
// This is a simple implementation, and may need more complex cut logic
// Can add effects, sounds, etc. here
if (DefaultBloodEffect)
{
UNiagaraFunctionLibrary::SpawnSystemAtLocation(
GetWorld(),
DefaultBloodEffect,
CutTransform.GetOrigin(),
CutTransform.Rotator()
);
}
return true;
}
bool UFLESHDismembermentComponent::DismemberBone(const FName& BoneName, EDismembermentType DismembermentType)
{
if (!DismembermentSystem || !TargetMesh)
{
return false;
}
int32 BoneIndex = TargetMesh->GetBoneIndex(BoneName);
if (BoneIndex == INDEX_NONE)
{
return false;
}
// Perform the dismember logic
// This is a simple implementation, and may need more complex dismember logic
// Can add effects, sounds, etc. here
FVector BoneLocation = TargetMesh->GetBoneLocation(BoneName);
if (DefaultBloodEffect)
{
UNiagaraFunctionLibrary::SpawnSystemAtLocation(
GetWorld(),
DefaultBloodEffect,
BoneLocation,
FRotator::ZeroRotator
);
}
return true;
}
bool UFLESHDismembermentComponent::ApplyBoneDamage(const FName& BoneName, float Damage, const FVector& DamageLocation, const FVector& DamageDirection, EDismembermentType DismembermentType)
{
if (!DismembermentSystem || !TargetMesh)
{
return false;
}
int32 BoneIndex = TargetMesh->GetBoneIndex(BoneName);
if (BoneIndex == INDEX_NONE)
{
return false;
}
// Find the bone patch and apply the damage multiplier
float ActualDamage = Damage;
for (const FBonePatchData& Patch : BonePatches)
{
if (Patch.BoneNames.Contains(BoneName))
{
ActualDamage *= Patch.DamageMultiplier;
break;
}
}
// If the damage is high enough, dismember the bone
const float DismembermentThreshold = 50.0f;
if (ActualDamage >= DismembermentThreshold)
{
return DismemberBone(BoneName, DismembermentType);
}
return true;
}
bool UFLESHDismembermentComponent::AddBonePatch(const FBonePatchData& PatchData)
{
// Check if the patch type already exists
int32 ExistingIndex = FindBonePatchIndex(PatchData.PatchType);
if (ExistingIndex != INDEX_NONE)
{
// Update the existing patch
BonePatches[ExistingIndex] = PatchData;
}
else
{
// Add a new patch
BonePatches.Add(PatchData);
}
// Apply the patch
ApplyBonePatch(PatchData);
return true;
}
bool UFLESHDismembermentComponent::RemoveBonePatch(EBonePatchType PatchType)
{
// Find the patch index
int32 PatchIndex = FindBonePatchIndex(PatchType);
if (PatchIndex != INDEX_NONE)
{
// Remove the patch
BonePatches.RemoveAt(PatchIndex);
return true;
}
return false;
}
bool UFLESHDismembermentComponent::GetBonePatch(EBonePatchType PatchType, FBonePatchData& OutPatchData) const
{
// Find the patch index
int32 PatchIndex = FindBonePatchIndex(PatchType);
if (PatchIndex != INDEX_NONE)
{
// Return the patch data
OutPatchData = BonePatches[PatchIndex];
return true;
}
return false;
}
TArray<FBonePatchData> UFLESHDismembermentComponent::GetAllBonePatches() const
{
return BonePatches;
}
void UFLESHDismembermentComponent::ResetDismemberment()
{
if (!DismembermentSystem || !TargetMesh)
{
return;
}
// Reset the dismemberment state
// This is a simple implementation, and may need more complex reset logic
// May need to restore all dismembered parts
}
void UFLESHDismembermentComponent::SetBloodEffect(UNiagaraSystem* BloodEffect)
{
DefaultBloodEffect = BloodEffect;
}
void UFLESHDismembermentComponent::SetCutMaterial(UMaterialInterface* CutMaterial)
{
DefaultCutMaterial = CutMaterial;
}
void UFLESHDismembermentComponent::SetShowOrgans(bool bShow)
{
bShowOrgans = bShow;
// May need to update the visibility of existing organs
}
void UFLESHDismembermentComponent::SetEnablePhysics(bool bEnable)
{
bEnablePhysics = bEnable;
// May need to update the physics state of existing parts
}
int32 UFLESHDismembermentComponent::FindBonePatchIndex(EBonePatchType PatchType) const
{
for (int32 i = 0; i < BonePatches.Num(); ++i)
{
if (BonePatches[i].PatchType == PatchType)
{
return i;
}
}
return INDEX_NONE;
}
void UFLESHDismembermentComponent::ApplyBonePatch(const FBonePatchData& PatchData)
{
// Apply the bone patch logic
// This is a simple implementation, and may need more complex application logic
// May need to update the material, physics asset, etc.
}