Update
This commit is contained in:
69
Source/FLESH/Private/DismemberedAnimInstance.cpp
Normal file
69
Source/FLESH/Private/DismemberedAnimInstance.cpp
Normal 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;
|
||||
}
|
@@ -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
|
274
Source/FLESH/Private/FLESHDismembermentComponent.cpp
Normal file
274
Source/FLESH/Private/FLESHDismembermentComponent.cpp
Normal 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.
|
||||
}
|
Reference in New Issue
Block a user