From 829d17679911ceefd2fa6be11d55cd2f983ddde9 Mon Sep 17 00:00:00 2001 From: Jeffreytsai1004 Date: Fri, 18 Apr 2025 11:19:13 +0800 Subject: [PATCH] Update --- .../FLESH/Private/DismemberedAnimInstance.cpp | 69 +++++ .../DismembermentGraphAsset.cpp | 74 +++++ .../Private/FLESHDismembermentComponent.cpp | 274 ++++++++++++++++++ 3 files changed, 417 insertions(+) create mode 100644 Source/FLESH/Private/DismemberedAnimInstance.cpp create mode 100644 Source/FLESH/Private/DismembermentGraph/DismembermentGraphAsset.cpp create mode 100644 Source/FLESH/Private/FLESHDismembermentComponent.cpp diff --git a/Source/FLESH/Private/DismemberedAnimInstance.cpp b/Source/FLESH/Private/DismemberedAnimInstance.cpp new file mode 100644 index 0000000..d7457db --- /dev/null +++ b/Source/FLESH/Private/DismemberedAnimInstance.cpp @@ -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; +} diff --git a/Source/FLESH/Private/DismembermentGraph/DismembermentGraphAsset.cpp b/Source/FLESH/Private/DismembermentGraph/DismembermentGraphAsset.cpp new file mode 100644 index 0000000..4f7d410 --- /dev/null +++ b/Source/FLESH/Private/DismembermentGraph/DismembermentGraphAsset.cpp @@ -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(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 diff --git a/Source/FLESH/Private/FLESHDismembermentComponent.cpp b/Source/FLESH/Private/FLESHDismembermentComponent.cpp new file mode 100644 index 0000000..97d984b --- /dev/null +++ b/Source/FLESH/Private/FLESHDismembermentComponent.cpp @@ -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(); + } + + if (TargetMesh) + { + DismembermentSystem = NewObject(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 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. +}