init
This commit is contained in:
+81
@@ -0,0 +1,81 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
|
||||
#include "AnimNotifyState_KawaiiPhysics.h"
|
||||
#include "KawaiiPhysicsLibrary.h"
|
||||
#include "Misc/UObjectToken.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimNotifyState_KawaiiPhysics)
|
||||
|
||||
#define LOCTEXT_NAMESPACE "KawaiiPhysics_AnimNotifyState"
|
||||
|
||||
UAnimNotifyState_KawaiiPhysicsAddExternalForce::UAnimNotifyState_KawaiiPhysicsAddExternalForce(
|
||||
const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
NotifyColor = FColor(255, 170, 0, 255);
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
}
|
||||
|
||||
FString UAnimNotifyState_KawaiiPhysicsAddExternalForce::GetNotifyName_Implementation() const
|
||||
{
|
||||
return FString(TEXT("KP: Add ExternalForce"));
|
||||
}
|
||||
|
||||
void UAnimNotifyState_KawaiiPhysicsAddExternalForce::NotifyBegin(USkeletalMeshComponent* MeshComp,
|
||||
UAnimSequenceBase* Animation,
|
||||
float TotalDuration,
|
||||
const FAnimNotifyEventReference& EventReference)
|
||||
{
|
||||
UKawaiiPhysicsLibrary::AddExternalForcesToComponent(MeshComp, AdditionalExternalForces, this,
|
||||
FilterTags, bFilterExactMatch);
|
||||
Super::NotifyBegin(MeshComp, Animation, TotalDuration, EventReference);
|
||||
}
|
||||
|
||||
void UAnimNotifyState_KawaiiPhysicsAddExternalForce::NotifyEnd(USkeletalMeshComponent* MeshComp,
|
||||
UAnimSequenceBase* Animation,
|
||||
const FAnimNotifyEventReference& EventReference)
|
||||
{
|
||||
UKawaiiPhysicsLibrary::RemoveExternalForcesFromComponent(MeshComp, this, FilterTags, bFilterExactMatch);
|
||||
|
||||
Super::NotifyEnd(MeshComp, Animation, EventReference);
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void UAnimNotifyState_KawaiiPhysicsAddExternalForce::ValidateAssociatedAssets()
|
||||
{
|
||||
static const FName NAME_AssetCheck("AssetCheck");
|
||||
|
||||
if (const UAnimSequenceBase* ContainingAsset = Cast<UAnimSequenceBase>(GetContainingAsset()))
|
||||
{
|
||||
for (auto& ForceInstancedStruct : AdditionalExternalForces)
|
||||
{
|
||||
if (!ForceInstancedStruct.IsValid())
|
||||
{
|
||||
FMessageLog AssetCheckLog(NAME_AssetCheck);
|
||||
|
||||
const FText MessageLooping = FText::Format(
|
||||
NSLOCTEXT("AnimNotify", "ExternalForce_ShouldSet",
|
||||
" AnimNotifyState(KawaiiPhysics_AddExternalForce) doesn't have a valid ExternalForce in {0}"),
|
||||
FText::AsCultureInvariant(ContainingAsset->GetPathName()));
|
||||
|
||||
AssetCheckLog.Warning()
|
||||
->AddToken(FUObjectToken::Create(ContainingAsset))
|
||||
->AddToken(FTextToken::Create(MessageLooping));
|
||||
|
||||
if (GIsEditor)
|
||||
{
|
||||
constexpr bool bForce = true;
|
||||
AssetCheckLog.Notify(MessageLooping, EMessageSeverity::Warning, bForce);
|
||||
}
|
||||
}
|
||||
|
||||
//const auto& ExternalForce = ForceInstancedStruct.Get<FKawaiiPhysics_ExternalForce>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "Animation/AnimNotifies/AnimNotifyState.h"
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
#include "StructUtils/InstancedStruct.h"
|
||||
#else
|
||||
#include "InstancedStruct.h"
|
||||
#endif
|
||||
|
||||
#include "AnimNotifyState_KawaiiPhysics.generated.h"
|
||||
|
||||
/**
|
||||
* UAnimNotifyState_KawaiiPhysicsAddExternalForce
|
||||
*
|
||||
* This class represents an animation notify state that adds external forces to a skeletal mesh component
|
||||
* during an animation sequence. It inherits from UAnimNotifyState and provides functionality to add and remove
|
||||
* external forces at the beginning and end of the animation notify state.
|
||||
*/
|
||||
UCLASS(Blueprintable, meta = (DisplayName = "KawaiiPhyiscs: Add ExternalForce"))
|
||||
class KAWAIIPHYSICS_API UAnimNotifyState_KawaiiPhysicsAddExternalForce : public UAnimNotifyState
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor for UAnimNotifyState_KawaiiPhysicsAddExternalForce.
|
||||
*
|
||||
* @param ObjectInitializer - The object initializer for this class.
|
||||
*/
|
||||
UAnimNotifyState_KawaiiPhysicsAddExternalForce(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
/**
|
||||
* Gets the name of the notify state.
|
||||
*
|
||||
* @return The name of the notify state as a string.
|
||||
*/
|
||||
virtual FString GetNotifyName_Implementation() const override;
|
||||
|
||||
/**
|
||||
* Called when the animation notify state begins.
|
||||
*
|
||||
* @param MeshComp - The skeletal mesh component.
|
||||
* @param Animation - The animation sequence.
|
||||
* @param TotalDuration - The total duration of the notify state.
|
||||
* @param EventReference - The event reference.
|
||||
*/
|
||||
virtual void NotifyBegin(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation, float TotalDuration,
|
||||
const FAnimNotifyEventReference& EventReference) override;
|
||||
|
||||
/**
|
||||
* Called when the animation notify state ends.
|
||||
*
|
||||
* @param MeshComp - The skeletal mesh component.
|
||||
* @param Animation - The animation sequence.
|
||||
* @param EventReference - The event reference.
|
||||
*/
|
||||
virtual void NotifyEnd(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
|
||||
const FAnimNotifyEventReference& EventReference) override;
|
||||
|
||||
/**
|
||||
* Additional external forces to be applied to the skeletal mesh component.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExternalForce",
|
||||
meta = (BaseStruct = "/Script/KawaiiPhysics.KawaiiPhysics_ExternalForce", ExcludeBaseStruct))
|
||||
TArray<FInstancedStruct> AdditionalExternalForces;
|
||||
|
||||
/**
|
||||
* Tags used to filter which external forces are applied.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExternalForce")
|
||||
FGameplayTagContainer FilterTags;
|
||||
|
||||
/**
|
||||
* Whether to filter tags to exact matches (if False, parent tags will also be included).
|
||||
* Tagのフィルタリングにて完全一致にするか否か(Falseの場合は親Tagも含めます)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExternalForce")
|
||||
bool bFilterExactMatch;
|
||||
|
||||
#if WITH_EDITOR
|
||||
/**
|
||||
* Validates the associated assets in the editor.
|
||||
*/
|
||||
virtual void ValidateAssociatedAssets() override;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "AnimNotify_KawaiiPhysics.h"
|
||||
#include "KawaiiPhysicsLibrary.h"
|
||||
#include "Misc/UObjectToken.h"
|
||||
#include "Logging/MessageLog.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimNotify_KawaiiPhysics)
|
||||
|
||||
#define LOCTEXT_NAMESPACE "KawaiiPhysics_AnimNotify"
|
||||
|
||||
UAnimNotify_KawaiiPhysicsAddExternalForce::UAnimNotify_KawaiiPhysicsAddExternalForce(
|
||||
const FObjectInitializer& ObjectInitializer)
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
NotifyColor = FColor(255, 170, 0, 255);
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
}
|
||||
|
||||
FString UAnimNotify_KawaiiPhysicsAddExternalForce::GetNotifyName_Implementation() const
|
||||
{
|
||||
return FString(TEXT("KP: Add ExternalForce"));
|
||||
}
|
||||
|
||||
void UAnimNotify_KawaiiPhysicsAddExternalForce::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
|
||||
const FAnimNotifyEventReference& EventReference)
|
||||
{
|
||||
UKawaiiPhysicsLibrary::AddExternalForcesToComponent(MeshComp, AdditionalExternalForces, this,
|
||||
FilterTags, bFilterExactMatch, true);
|
||||
|
||||
Super::Notify(MeshComp, Animation, EventReference);
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void UAnimNotify_KawaiiPhysicsAddExternalForce::ValidateAssociatedAssets()
|
||||
{
|
||||
static const FName NAME_AssetCheck("AssetCheck");
|
||||
|
||||
if (const UAnimSequenceBase* ContainingAsset = Cast<UAnimSequenceBase>(GetContainingAsset()))
|
||||
{
|
||||
for (auto& ForceInstancedStruct : AdditionalExternalForces)
|
||||
{
|
||||
if (!ForceInstancedStruct.IsValid())
|
||||
{
|
||||
FMessageLog AssetCheckLog(NAME_AssetCheck);
|
||||
|
||||
const FText MessageLooping = FText::Format(
|
||||
NSLOCTEXT("AnimNotify", "ExternalForce_ShouldSet",
|
||||
" AnimNotify(KawaiiPhysics_AddExternalForce) doesn't have a valid ExternalForce in {0}"),
|
||||
FText::AsCultureInvariant(ContainingAsset->GetPathName()));
|
||||
|
||||
AssetCheckLog.Warning()
|
||||
->AddToken(FUObjectToken::Create(ContainingAsset))
|
||||
->AddToken(FTextToken::Create(MessageLooping));
|
||||
|
||||
if (GIsEditor)
|
||||
{
|
||||
constexpr bool bForce = true;
|
||||
AssetCheckLog.Notify(MessageLooping, EMessageSeverity::Warning, bForce);
|
||||
}
|
||||
}
|
||||
|
||||
//const auto& ExternalForce = ForceInstancedStruct.Get<FKawaiiPhysics_ExternalForce>();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,80 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GameplayTagContainer.h"
|
||||
#include "Animation/AnimNotifies/AnimNotify.h"
|
||||
|
||||
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
|
||||
#include "StructUtils/InstancedStruct.h"
|
||||
#else
|
||||
#include "InstancedStruct.h"
|
||||
#endif
|
||||
|
||||
#include "AnimNotify_KawaiiPhysics.generated.h"
|
||||
|
||||
/**
|
||||
* UAnimNotify_KawaiiPhysicsAddExternalForce
|
||||
*
|
||||
* This class represents an animation notify that adds external forces to a skeletal mesh component
|
||||
* during an animation sequence. It inherits from UAnimNotify and provides functionality to add and remove
|
||||
* external forces when the notify is triggered.
|
||||
*/
|
||||
UCLASS(Blueprintable, meta = (DisplayName = "KawaiiPhyiscs: Add ExternalForce"))
|
||||
class KAWAIIPHYSICS_API UAnimNotify_KawaiiPhysicsAddExternalForce : public UAnimNotify
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor for UAnimNotify_KawaiiPhysicsAddExternalForce.
|
||||
*
|
||||
* @param ObjectInitializer - The object initializer for this class.
|
||||
*/
|
||||
UAnimNotify_KawaiiPhysicsAddExternalForce(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
/**
|
||||
* Gets the name of the notify.
|
||||
*
|
||||
* @return The name of the notify as a string.
|
||||
*/
|
||||
virtual FString GetNotifyName_Implementation() const override;
|
||||
|
||||
/**
|
||||
* Called when the animation notify is triggered.
|
||||
*
|
||||
* @param MeshComp - The skeletal mesh component.
|
||||
* @param Animation - The animation sequence.
|
||||
* @param EventReference - The event reference.
|
||||
*/
|
||||
virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation,
|
||||
const FAnimNotifyEventReference& EventReference) override;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Additional external forces to be applied to the skeletal mesh component.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExternalForce",
|
||||
meta = (BaseStruct = "/Script/KawaiiPhysics.KawaiiPhysics_ExternalForce", ExcludeBaseStruct))
|
||||
TArray<FInstancedStruct> AdditionalExternalForces;
|
||||
|
||||
/**
|
||||
* Tags used to filter which external forces are applied.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExternalForce")
|
||||
FGameplayTagContainer FilterTags;
|
||||
|
||||
/**
|
||||
* Whether to filter tags to exact matches (if False, parent tags will also be included).
|
||||
* Tagのフィルタリングにて完全一致にするか否か(Falseの場合は親Tagも含めます)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ExternalForce")
|
||||
bool bFilterExactMatch;
|
||||
|
||||
#if WITH_EDITOR
|
||||
/**
|
||||
* Validates the associated assets in the editor.
|
||||
*/
|
||||
virtual void ValidateAssociatedAssets() override;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class KawaiiPhysics : ModuleRules
|
||||
{
|
||||
public KawaiiPhysics(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new[]
|
||||
{
|
||||
"Core",
|
||||
"AnimGraphRuntime",
|
||||
"GameplayTags"
|
||||
}
|
||||
);
|
||||
|
||||
// StructUtils plugin has been integrated into the engine starting from 5.5
|
||||
if (Target.Version.MajorVersion == 5 && Target.Version.MinorVersion <= 4)
|
||||
{
|
||||
PublicDependencyModuleNames.Add("StructUtils");
|
||||
}
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore"
|
||||
}
|
||||
);
|
||||
|
||||
if (Target.bBuildEditor)
|
||||
{
|
||||
PublicDependencyModuleNames.Add("UnrealEd");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "KawaiiPhysics.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FKawaiiPhysicsModule"
|
||||
|
||||
void FKawaiiPhysicsModule::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||
}
|
||||
|
||||
void FKawaiiPhysicsModule::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(FKawaiiPhysicsModule, KawaiiPhysics)
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
|
||||
#include "KawaiiPhysicsBoneConstraintsDataAsset.h"
|
||||
|
||||
#include "KawaiiPhysics.h"
|
||||
#include "Internationalization/Regex.h"
|
||||
|
||||
#if WITH_EDITOR
|
||||
#include "Editor.h"
|
||||
#endif
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(KawaiiPhysicsBoneConstraintsDataAsset)
|
||||
|
||||
struct FBoneConstraintDataCustomVersion
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
// FNameからFBoneReferenceに移行
|
||||
ChangeToBoneReference = 0,
|
||||
|
||||
// ------------------------------------------------------
|
||||
VersionPlusOne,
|
||||
LatestVersion = VersionPlusOne - 1
|
||||
};
|
||||
|
||||
// The GUID for this custom version number
|
||||
const static FGuid GUID;
|
||||
|
||||
private:
|
||||
FBoneConstraintDataCustomVersion()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
const FGuid FBoneConstraintDataCustomVersion::GUID(0xA1C4D3F6, 0x5B2E7A8D, 0x9F6E4B3C, 0xD7E1A8B2);
|
||||
FCustomVersionRegistration GRegisterBoneConstraintDataCustomVersion(FBoneConstraintDataCustomVersion::GUID,
|
||||
FBoneConstraintDataCustomVersion::LatestVersion,
|
||||
TEXT("BoneConstraintData"));
|
||||
|
||||
void FModifyBoneConstraintData::Update(const FModifyBoneConstraint& BoneConstraint)
|
||||
{
|
||||
BoneReference1 = BoneConstraint.Bone1;
|
||||
BoneReference2 = BoneConstraint.Bone2;
|
||||
bOverrideCompliance = BoneConstraint.bOverrideCompliance;
|
||||
ComplianceType = BoneConstraint.ComplianceType;
|
||||
}
|
||||
|
||||
TArray<FModifyBoneConstraint> UKawaiiPhysicsBoneConstraintsDataAsset::GenerateBoneConstraints()
|
||||
{
|
||||
TArray<FModifyBoneConstraint> BoneConstraints;
|
||||
|
||||
for (const FModifyBoneConstraintData& BoneConstraintData : BoneConstraintsData)
|
||||
{
|
||||
FModifyBoneConstraint BoneConstraint;
|
||||
BoneConstraint.Bone1 = BoneConstraintData.BoneReference1;
|
||||
BoneConstraint.Bone2 = BoneConstraintData.BoneReference2;
|
||||
BoneConstraint.bOverrideCompliance = BoneConstraintData.bOverrideCompliance;
|
||||
BoneConstraint.ComplianceType = BoneConstraintData.ComplianceType;
|
||||
|
||||
BoneConstraints.Add(BoneConstraint);
|
||||
}
|
||||
|
||||
return BoneConstraints;
|
||||
}
|
||||
|
||||
void UKawaiiPhysicsBoneConstraintsDataAsset::Serialize(FStructuredArchiveRecord Record)
|
||||
{
|
||||
Super::Serialize(Record);
|
||||
|
||||
Record.GetUnderlyingArchive().UsingCustomVersion(FBoneConstraintDataCustomVersion::GUID);
|
||||
}
|
||||
|
||||
void UKawaiiPhysicsBoneConstraintsDataAsset::PostLoad()
|
||||
{
|
||||
Super::PostLoad();
|
||||
|
||||
if (GetLinkerCustomVersion(FBoneConstraintDataCustomVersion::GUID) <
|
||||
FBoneConstraintDataCustomVersion::ChangeToBoneReference)
|
||||
{
|
||||
for (auto& Data : BoneConstraintsData)
|
||||
{
|
||||
Data.BoneReference1 = FBoneReference(Data.BoneName1);
|
||||
Data.BoneReference2 = FBoneReference(Data.BoneName2);
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
UpdatePreviewBoneList();
|
||||
#endif
|
||||
UE_LOG(LogKawaiiPhysics, Log, TEXT("Update : BoneName -> BoneReference (%s)"), *this->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
USkeleton* UKawaiiPhysicsBoneConstraintsDataAsset::GetSkeleton(bool& bInvalidSkeletonIsError,
|
||||
const IPropertyHandle* PropertyHandle)
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
return PreviewSkeleton.LoadSynchronous();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
#define LOCTEXT_NAMESPACE "KawaiiPhysicsBoneConstraintsDataAsset"
|
||||
|
||||
void UKawaiiPhysicsBoneConstraintsDataAsset::ApplyRegex()
|
||||
{
|
||||
GEditor->BeginTransaction(FText::FromString("ApplyRegex"));
|
||||
Modify();
|
||||
|
||||
UpdatePreviewBoneList();
|
||||
|
||||
for (FRegexPatternBoneSet& Pattern : RegexPatternList)
|
||||
{
|
||||
const FRegexPattern Pattern1 = FRegexPattern(Pattern.RegexPatternBone1);
|
||||
const FRegexPattern Pattern2 = FRegexPattern(Pattern.RegexPatternBone2);
|
||||
|
||||
FRegexMatcher Matcher1(Pattern1, PreviewBoneListString);
|
||||
FRegexMatcher Matcher2(Pattern2, PreviewBoneListString);
|
||||
|
||||
while (Matcher1.FindNext() && Matcher2.FindNext())
|
||||
{
|
||||
FModifyBoneConstraintData BoneConstraintData;
|
||||
BoneConstraintData.BoneReference1 = FBoneReference(FName(*Matcher1.GetCaptureGroup(0)));
|
||||
BoneConstraintData.BoneReference2 = FBoneReference(FName(*Matcher2.GetCaptureGroup(0)));
|
||||
BoneConstraintsData.Add(BoneConstraintData);
|
||||
}
|
||||
}
|
||||
|
||||
GEditor->EndTransaction();
|
||||
}
|
||||
|
||||
|
||||
void UKawaiiPhysicsBoneConstraintsDataAsset::UpdatePreviewBoneList()
|
||||
{
|
||||
PreviewBoneList.Empty();
|
||||
PreviewBoneListString.Empty();
|
||||
|
||||
if (!PreviewSkeleton.IsValid())
|
||||
{
|
||||
PreviewSkeleton.LoadSynchronous();
|
||||
}
|
||||
|
||||
if (PreviewSkeleton.IsValid())
|
||||
{
|
||||
const FReferenceSkeleton& RefSkeleton = PreviewSkeleton->GetReferenceSkeleton();
|
||||
const TArray<FMeshBoneInfo>& RefBoneInfo = RefSkeleton.GetRefBoneInfo();
|
||||
|
||||
for (const FMeshBoneInfo& BoneInfo : RefBoneInfo)
|
||||
{
|
||||
PreviewBoneList.Add(BoneInfo.Name);
|
||||
PreviewBoneListString.Append(BoneInfo.Name.ToString());
|
||||
PreviewBoneListString.Append(TEXT(", "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UKawaiiPhysicsBoneConstraintsDataAsset::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
const FName PropertyName = PropertyChangedEvent.MemberProperty
|
||||
? PropertyChangedEvent.MemberProperty->GetFName()
|
||||
: NAME_None;
|
||||
|
||||
if (PropertyName == FName(TEXT("PreviewSkeleton")))
|
||||
{
|
||||
UpdatePreviewBoneList();
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
#endif
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "KawaiiPhysicsCustomExternalForce.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(KawaiiPhysicsCustomExternalForce)
|
||||
@@ -0,0 +1,322 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "KawaiiPhysicsExternalForce.h"
|
||||
|
||||
#include "SceneInterface.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(KawaiiPhysicsExternalForce)
|
||||
|
||||
DECLARE_CYCLE_STAT(TEXT("KawaiiPhysics_ExternalForce_Basic_Apply"), STAT_KawaiiPhysics_ExternalForce_Basic_Apply,
|
||||
STATGROUP_Anim);
|
||||
DECLARE_CYCLE_STAT(TEXT("KawaiiPhysics_ExternalForce_Gravity_Apply"), STAT_KawaiiPhysics_ExternalForce_Gravity_Apply,
|
||||
STATGROUP_Anim);
|
||||
DECLARE_CYCLE_STAT(TEXT("KawaiiPhysics_ExternalForce_Curve_Apply"), STAT_KawaiiPhysics_ExternalForce_Curve_Apply,
|
||||
STATGROUP_Anim);
|
||||
DECLARE_CYCLE_STAT(TEXT("KawaiiPhysics_ExternalForce_Wind_Apply"), STAT_KawaiiPhysics_ExternalForce_Wind_Apply,
|
||||
STATGROUP_Anim);
|
||||
|
||||
///
|
||||
/// Basic
|
||||
///
|
||||
void FKawaiiPhysics_ExternalForce_Basic::PreApply(FAnimNode_KawaiiPhysics& Node,
|
||||
const USkeletalMeshComponent* SkelComp)
|
||||
{
|
||||
Super::PreApply(Node, SkelComp);
|
||||
|
||||
PrevTime = Time;
|
||||
Time += Node.DeltaTime;
|
||||
if (Interval > 0.0f)
|
||||
{
|
||||
if (Time > Interval)
|
||||
{
|
||||
Force = ForceDir * RandomizedForceScale;
|
||||
Time = FMath::Fmod(Time, Interval);
|
||||
}
|
||||
else
|
||||
{
|
||||
Force = FVector::ZeroVector;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Force = ForceDir * RandomizedForceScale;
|
||||
}
|
||||
|
||||
if (ExternalForceSpace == EExternalForceSpace::WorldSpace)
|
||||
{
|
||||
Force = ComponentTransform.InverseTransformVector(Force);
|
||||
}
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Basic::Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext, const FTransform& BoneTM)
|
||||
{
|
||||
if (!CanApply(Bone))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPE_CYCLE_COUNTER(STAT_KawaiiPhysics_ExternalForce_Basic_Apply);
|
||||
|
||||
float ForceRate = 1.0f;
|
||||
if (const auto Curve = ForceRateByBoneLengthRate.GetRichCurve(); !Curve->IsEmpty())
|
||||
{
|
||||
ForceRate = Curve->Eval(Bone.LengthRateFromRoot);
|
||||
}
|
||||
|
||||
if (ExternalForceSpace == EExternalForceSpace::BoneSpace)
|
||||
{
|
||||
const FVector BoneForce = BoneTM.TransformVector(Force);
|
||||
Bone.Location += BoneForce * ForceRate * Node.DeltaTime;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
BoneForceMap.Add(Bone.BoneRef.BoneName, BoneForce);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Bone.Location += Force * ForceRate * Node.DeltaTime;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
BoneForceMap.Add(Bone.BoneRef.BoneName, Force * ForceRate);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Gravity
|
||||
///
|
||||
void FKawaiiPhysics_ExternalForce_Gravity::PreApply(FAnimNode_KawaiiPhysics& Node,
|
||||
const USkeletalMeshComponent* SkelComp)
|
||||
{
|
||||
Super::PreApply(Node, SkelComp);
|
||||
|
||||
Force = bUseOverrideGravityDirection ? OverrideGravityDirection : FVector(0, 0, -1.0f);
|
||||
|
||||
// For Character's Custom Gravity Direction
|
||||
if (const ACharacter* Character = Cast<ACharacter>(SkelComp->GetOwner()))
|
||||
{
|
||||
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 3
|
||||
if (bUseCharacterGravityDirection)
|
||||
{
|
||||
Force = Character->GetGravityDirection();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bUseCharacterGravityScale)
|
||||
{
|
||||
if (const UCharacterMovementComponent* CharacterMovementComponent = Character->
|
||||
GetCharacterMovement())
|
||||
{
|
||||
Force *= CharacterMovementComponent->GetGravityZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Force *= RandomizedForceScale;
|
||||
Force = ComponentTransform.InverseTransformVector(Force);
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Gravity::Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext,
|
||||
const FTransform& BoneTM)
|
||||
{
|
||||
if (!CanApply(Bone))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPE_CYCLE_COUNTER(STAT_KawaiiPhysics_ExternalForce_Gravity_Apply);
|
||||
|
||||
float ForceRate = 1.0f;
|
||||
if (const auto Curve = ForceRateByBoneLengthRate.GetRichCurve(); !Curve->IsEmpty())
|
||||
{
|
||||
ForceRate = Curve->Eval(Bone.LengthRateFromRoot);
|
||||
}
|
||||
|
||||
Bone.Location += 0.5f * Force * ForceRate * Node.DeltaTime * Node.DeltaTime;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
BoneForceMap.Add(Bone.BoneRef.BoneName, Force * ForceRate);
|
||||
AnimDrawDebug(Bone, Node, PoseContext);
|
||||
#endif
|
||||
}
|
||||
|
||||
///
|
||||
/// Curve
|
||||
///
|
||||
void FKawaiiPhysics_ExternalForce_Curve::InitMaxCurveTime()
|
||||
{
|
||||
if (const FRichCurve* CurveX = ForceCurve.GetRichCurve(0); CurveX && !CurveX->IsEmpty())
|
||||
{
|
||||
MaxCurveTime = FMath::Max(MaxCurveTime, CurveX->GetLastKey().Time);
|
||||
}
|
||||
if (const FRichCurve* CurveY = ForceCurve.GetRichCurve(1); CurveY && !CurveY->IsEmpty())
|
||||
{
|
||||
MaxCurveTime = FMath::Max(MaxCurveTime, CurveY->GetLastKey().Time);
|
||||
}
|
||||
if (const FRichCurve* CurveZ = ForceCurve.GetRichCurve(2); CurveZ && !CurveZ->IsEmpty())
|
||||
{
|
||||
MaxCurveTime = FMath::Max(MaxCurveTime, CurveZ->GetLastKey().Time);
|
||||
}
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Curve::Initialize(const FAnimationInitializeContext& Context)
|
||||
{
|
||||
FKawaiiPhysics_ExternalForce::Initialize(Context);
|
||||
|
||||
InitMaxCurveTime();
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Curve::PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp)
|
||||
{
|
||||
Super::PreApply(Node, SkelComp);
|
||||
|
||||
#if WITH_EDITOR
|
||||
InitMaxCurveTime();
|
||||
#endif
|
||||
|
||||
PrevTime = Time;
|
||||
|
||||
if (CurveEvaluateType == EExternalForceCurveEvaluateType::Single)
|
||||
{
|
||||
Time += Node.DeltaTime * TimeScale;
|
||||
if (MaxCurveTime > 0 && Time > MaxCurveTime)
|
||||
{
|
||||
Time = FMath::Fmod(Time, MaxCurveTime);
|
||||
}
|
||||
Force = ForceCurve.GetValue(Time) * RandomizedForceScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
TArray<FVector> CurveValues;
|
||||
const float SubStep = Node.DeltaTime * TimeScale / SubstepCount;
|
||||
|
||||
for (int i = 0; i < SubstepCount; ++i)
|
||||
{
|
||||
Time += SubStep;
|
||||
if (MaxCurveTime > 0 && Time > MaxCurveTime)
|
||||
{
|
||||
Time = FMath::Fmod(Time, MaxCurveTime);
|
||||
}
|
||||
CurveValues.Add(ForceCurve.GetValue(Time));
|
||||
}
|
||||
|
||||
Force = FVector::ZeroVector;
|
||||
switch (CurveEvaluateType)
|
||||
{
|
||||
case EExternalForceCurveEvaluateType::Average:
|
||||
for (const auto& CurveValue : CurveValues)
|
||||
{
|
||||
Force += CurveValue;
|
||||
}
|
||||
Force /= static_cast<float>(SubstepCount);
|
||||
|
||||
break;
|
||||
|
||||
case EExternalForceCurveEvaluateType::Max:
|
||||
Force = FVector(FLT_MIN);
|
||||
for (const auto& CurveValue : CurveValues)
|
||||
{
|
||||
Force = FVector::Max(Force, CurveValue);
|
||||
}
|
||||
break;
|
||||
case EExternalForceCurveEvaluateType::Min:
|
||||
Force = FVector(FLT_MAX);
|
||||
for (const auto& CurveValue : CurveValues)
|
||||
{
|
||||
Force = FVector::Min(Force, CurveValue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Force *= RandomizedForceScale;
|
||||
}
|
||||
|
||||
if (ExternalForceSpace == EExternalForceSpace::WorldSpace)
|
||||
{
|
||||
Force = ComponentTransform.InverseTransformVector(Force);
|
||||
}
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Curve::Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext, const FTransform& BoneTM)
|
||||
{
|
||||
if (!CanApply(Bone))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPE_CYCLE_COUNTER(STAT_KawaiiPhysics_ExternalForce_Curve_Apply);
|
||||
|
||||
float ForceRate = 1.0f;
|
||||
if (const auto Curve = ForceRateByBoneLengthRate.GetRichCurve(); !Curve->IsEmpty())
|
||||
{
|
||||
ForceRate = Curve->Eval(Bone.LengthRateFromRoot);
|
||||
}
|
||||
|
||||
if (ExternalForceSpace == EExternalForceSpace::BoneSpace)
|
||||
{
|
||||
const FVector BoneForce = BoneTM.TransformVector(Force);
|
||||
Bone.Location += BoneForce * ForceRate * Node.DeltaTime;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
BoneForceMap.Add(Bone.BoneRef.BoneName, BoneForce * ForceRate);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Bone.Location += Force * ForceRate * Node.DeltaTime;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
BoneForceMap.Add(Bone.BoneRef.BoneName, Force * ForceRate);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
AnimDrawDebug(Bone, Node, PoseContext);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Wind::PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp)
|
||||
{
|
||||
Super::PreApply(Node, SkelComp);
|
||||
|
||||
World = SkelComp ? SkelComp->GetWorld() : nullptr;
|
||||
}
|
||||
|
||||
void FKawaiiPhysics_ExternalForce_Wind::Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext, const FTransform& BoneTM)
|
||||
{
|
||||
const FSceneInterface* Scene = World && World->Scene ? World->Scene : nullptr;
|
||||
if (!CanApply(Bone) || !Scene)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SCOPE_CYCLE_COUNTER(STAT_KawaiiPhysics_ExternalForce_Wind_Apply);
|
||||
|
||||
float ForceRate = 1.0f;
|
||||
if (const auto Curve = ForceRateByBoneLengthRate.GetRichCurve(); !Curve->IsEmpty())
|
||||
{
|
||||
ForceRate = Curve->Eval(Bone.LengthRateFromRoot);
|
||||
}
|
||||
|
||||
FVector WindDirection = FVector::ZeroVector;
|
||||
float WindSpeed, WindMinGust, WindMaxGust = 0.0f;
|
||||
Scene->GetWindParameters(ComponentTransform.TransformPosition(Bone.PoseLocation), WindDirection,
|
||||
WindSpeed, WindMinGust, WindMaxGust);
|
||||
WindDirection = ComponentTransform.InverseTransformVector(WindDirection);
|
||||
WindDirection *= WindSpeed;
|
||||
|
||||
Bone.Location += WindDirection * ForceRate * RandomizedForceScale * Node.DeltaTime;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
BoneForceMap.Add(Bone.BoneRef.BoneName, WindDirection * ForceRate * RandomizedForceScale);
|
||||
AnimDrawDebug(Bone, Node, PoseContext);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "KawaiiPhysicsLibrary.h"
|
||||
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "BlueprintGameplayTagLibrary.h"
|
||||
#include "KawaiiPhysicsExternalForce.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(KawaiiPhysicsLibrary)
|
||||
|
||||
DEFINE_LOG_CATEGORY_STATIC(LogKawaiiPhysicsLibrary, Verbose, All);
|
||||
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::ConvertToKawaiiPhysics(const FAnimNodeReference& Node,
|
||||
EAnimNodeReferenceConversionResult& Result)
|
||||
{
|
||||
return FAnimNodeReference::ConvertToType<FKawaiiPhysicsReference>(Node, Result);
|
||||
}
|
||||
|
||||
bool UKawaiiPhysicsLibrary::CollectKawaiiPhysicsNodes(TArray<FKawaiiPhysicsReference>& Nodes,
|
||||
UAnimInstance* AnimInstance,
|
||||
const FGameplayTagContainer& FilterTags, bool bFilterExactMatch)
|
||||
{
|
||||
if (!ensure(AnimInstance && AnimInstance->GetClass()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bResult = false;
|
||||
if (const IAnimClassInterface* AnimClassInterface =
|
||||
IAnimClassInterface::GetFromClass((AnimInstance->GetClass())))
|
||||
{
|
||||
const TArray<FStructProperty*>& AnimNodeProperties = AnimClassInterface->GetAnimNodeProperties();
|
||||
for (int i = 0; i < AnimNodeProperties.Num(); ++i)
|
||||
{
|
||||
if (AnimNodeProperties[i]->Struct->
|
||||
IsChildOf(FKawaiiPhysicsReference::FInternalNodeType::StaticStruct()))
|
||||
{
|
||||
EAnimNodeReferenceConversionResult Result;
|
||||
FKawaiiPhysicsReference KawaiiPhysicsReference = ConvertToKawaiiPhysics(
|
||||
FAnimNodeReference(AnimInstance, i), Result);
|
||||
|
||||
if (Result == EAnimNodeReferenceConversionResult::Succeeded)
|
||||
{
|
||||
auto& Tag = KawaiiPhysicsReference.GetAnimNode<FAnimNode_KawaiiPhysics>().KawaiiPhysicsTag;
|
||||
if (FilterTags.IsEmpty() || UBlueprintGameplayTagLibrary::MatchesAnyTags(
|
||||
Tag, FilterTags, bFilterExactMatch))
|
||||
{
|
||||
Nodes.Add(KawaiiPhysicsReference);
|
||||
bResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool UKawaiiPhysicsLibrary::CollectKawaiiPhysicsNodes(TArray<FKawaiiPhysicsReference>& Nodes,
|
||||
USkeletalMeshComponent* MeshComp,
|
||||
const FGameplayTagContainer& FilterTags, bool bFilterExactMatch)
|
||||
{
|
||||
if (!ensure(MeshComp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const int NodeNum = Nodes.Num();
|
||||
|
||||
if (UAnimInstance* AnimInstance = MeshComp->GetAnimInstance())
|
||||
{
|
||||
CollectKawaiiPhysicsNodes(Nodes, AnimInstance, FilterTags,
|
||||
bFilterExactMatch);
|
||||
}
|
||||
|
||||
const TArray<UAnimInstance*>& LinkedInstances =
|
||||
const_cast<const USkeletalMeshComponent*>(MeshComp)->GetLinkedAnimInstances();
|
||||
for (UAnimInstance* LinkedInstance : LinkedInstances)
|
||||
{
|
||||
CollectKawaiiPhysicsNodes(Nodes, LinkedInstance, FilterTags,
|
||||
bFilterExactMatch);
|
||||
}
|
||||
|
||||
if (UAnimInstance* PostProcessAnimInstance = MeshComp->GetPostProcessInstance())
|
||||
{
|
||||
CollectKawaiiPhysicsNodes(Nodes, PostProcessAnimInstance, FilterTags,
|
||||
bFilterExactMatch);
|
||||
}
|
||||
|
||||
return NodeNum != Nodes.Num();
|
||||
}
|
||||
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::ResetDynamics(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("ResetDynamics"),
|
||||
[](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
InKawaiiPhysics.ResetDynamics(ETeleportType::ResetPhysics);
|
||||
});
|
||||
|
||||
return KawaiiPhysics;
|
||||
}
|
||||
|
||||
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::SetRootBoneName(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
FName& RootBoneName)
|
||||
{
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("SetRootBoneName"),
|
||||
[RootBoneName](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
InKawaiiPhysics.RootBone = FBoneReference(RootBoneName);
|
||||
});
|
||||
|
||||
return KawaiiPhysics;
|
||||
}
|
||||
|
||||
FName UKawaiiPhysicsLibrary::GetRootBoneName(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
FName RootBoneName;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("GetRootBoneName"),
|
||||
[&RootBoneName](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
RootBoneName = InKawaiiPhysics.RootBone.BoneName;
|
||||
});
|
||||
|
||||
return RootBoneName;
|
||||
}
|
||||
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::SetExcludeBoneNames(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
TArray<FName>& ExcludeBoneNames)
|
||||
{
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("SetExcludeBoneNames"),
|
||||
[&ExcludeBoneNames](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
InKawaiiPhysics.ExcludeBones.Empty();
|
||||
for (auto& ExcludeBoneName : ExcludeBoneNames)
|
||||
{
|
||||
InKawaiiPhysics.ExcludeBones.Add(FBoneReference(ExcludeBoneName));
|
||||
}
|
||||
});
|
||||
|
||||
return KawaiiPhysics;
|
||||
}
|
||||
|
||||
TArray<FName> UKawaiiPhysicsLibrary::GetExcludeBoneNames(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
TArray<FName> ExcludeBoneNames;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("GetExcludeBoneNames"),
|
||||
[&ExcludeBoneNames](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
for (auto& ExcludeBone : InKawaiiPhysics.ExcludeBones)
|
||||
{
|
||||
ExcludeBoneNames.Add(ExcludeBone.BoneName);
|
||||
}
|
||||
});
|
||||
|
||||
return ExcludeBoneNames;
|
||||
}
|
||||
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::AddExternalForceWithExecResult(
|
||||
EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
FInstancedStruct& ExternalForce, UObject* Owner)
|
||||
{
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
if (AddExternalForce(KawaiiPhysics, ExternalForce, Owner))
|
||||
{
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
|
||||
return KawaiiPhysics;
|
||||
}
|
||||
|
||||
bool UKawaiiPhysicsLibrary::AddExternalForce(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
FInstancedStruct& ExternalForce, UObject* Owner, bool bIsOneShot)
|
||||
{
|
||||
bool bResult = false;
|
||||
|
||||
if (ExternalForce.IsValid())
|
||||
{
|
||||
if (auto* ExternalForcePtr = ExternalForce.GetMutablePtr<FKawaiiPhysics_ExternalForce>())
|
||||
{
|
||||
ExternalForcePtr->ExternalOwner = Owner;
|
||||
ExternalForcePtr->bIsOneShot = bIsOneShot;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("AddExternalForce"),
|
||||
[&](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
InKawaiiPhysics.ExternalForces.Add(ExternalForce);
|
||||
});
|
||||
|
||||
bResult = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool UKawaiiPhysicsLibrary::AddExternalForcesToComponent(USkeletalMeshComponent* MeshComp,
|
||||
TArray<FInstancedStruct>& ExternalForces,
|
||||
UObject* Owner,
|
||||
FGameplayTagContainer& FilterTags,
|
||||
bool bFilterExactMatch, bool bIsOneShot)
|
||||
{
|
||||
bool bResult = false;
|
||||
|
||||
TArray<FKawaiiPhysicsReference> KawaiiPhysicsReferences;
|
||||
CollectKawaiiPhysicsNodes(KawaiiPhysicsReferences, MeshComp, FilterTags, bFilterExactMatch);
|
||||
for (auto& KawaiiPhysicsReference : KawaiiPhysicsReferences)
|
||||
{
|
||||
for (auto& AExternalForce : ExternalForces)
|
||||
{
|
||||
if (AExternalForce.IsValid())
|
||||
{
|
||||
if (AddExternalForce(KawaiiPhysicsReference, AExternalForce, Owner, bIsOneShot))
|
||||
{
|
||||
bResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool UKawaiiPhysicsLibrary::RemoveExternalForcesFromComponent(USkeletalMeshComponent* MeshComp, UObject* Owner,
|
||||
FGameplayTagContainer& FilterTags, bool bFilterExactMatch)
|
||||
{
|
||||
bool bResult = false;
|
||||
|
||||
TArray<FKawaiiPhysicsReference> KawaiiPhysicsReferences;
|
||||
CollectKawaiiPhysicsNodes(KawaiiPhysicsReferences, MeshComp, FilterTags, bFilterExactMatch);
|
||||
for (auto& KawaiiPhysicsReference : KawaiiPhysicsReferences)
|
||||
{
|
||||
KawaiiPhysicsReference.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("RemoveExternalForce"),
|
||||
[&](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
const int32 NumRemoved = InKawaiiPhysics.ExternalForces.RemoveAll([&](FInstancedStruct& InstancedStruct)
|
||||
{
|
||||
const auto* ExternalForcePtr = InstancedStruct.GetMutablePtr<FKawaiiPhysics_ExternalForce>();
|
||||
return ExternalForcePtr && ExternalForcePtr->ExternalOwner == Owner;
|
||||
});
|
||||
|
||||
if (NumRemoved > 0)
|
||||
{
|
||||
bResult = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
DEFINE_FUNCTION(UKawaiiPhysicsLibrary::execSetExternalForceWildcardProperty)
|
||||
{
|
||||
P_GET_ENUM_REF(EKawaiiPhysicsAccessExternalForceResult, ExecResult);
|
||||
P_GET_STRUCT_REF(FKawaiiPhysicsReference, KawaiiPhysics);
|
||||
P_GET_PROPERTY(FIntProperty, ExternalForceIndex);
|
||||
P_GET_STRUCT_REF(FName, PropertyName);
|
||||
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
// Read wildcard Value input.
|
||||
Stack.MostRecentPropertyAddress = nullptr;
|
||||
Stack.MostRecentPropertyContainer = nullptr;
|
||||
Stack.StepCompiledIn<FStructProperty>(nullptr);
|
||||
|
||||
const FProperty* ValueProp = CastField<FProperty>(Stack.MostRecentProperty);
|
||||
void* ValuePtr = Stack.MostRecentPropertyAddress;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("GetExternalForceWildcardProperty"),
|
||||
[&ExecResult, &ExternalForceIndex, &PropertyName, &ValuePtr](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
if (InKawaiiPhysics.ExternalForces.IsValidIndex(ExternalForceIndex) &&
|
||||
InKawaiiPhysics.ExternalForces[ExternalForceIndex].IsValid())
|
||||
{
|
||||
const auto* ScriptStruct = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetScriptStruct();
|
||||
auto& Force = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetMutable<
|
||||
FKawaiiPhysics_ExternalForce>();
|
||||
|
||||
if (const FProperty* Property = FindFProperty<FProperty>(ScriptStruct, PropertyName))
|
||||
{
|
||||
Property->CopyCompleteValue(Property->ContainerPtrToValuePtr<uint8>(&Force), ValuePtr);
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
P_FINISH;
|
||||
}
|
||||
|
||||
DEFINE_FUNCTION(UKawaiiPhysicsLibrary::execGetExternalForceWildcardProperty)
|
||||
{
|
||||
P_GET_ENUM_REF(EKawaiiPhysicsAccessExternalForceResult, ExecResult);
|
||||
P_GET_STRUCT_REF(FKawaiiPhysicsReference, KawaiiPhysics);
|
||||
P_GET_PROPERTY(FIntProperty, ExternalForceIndex);
|
||||
P_GET_STRUCT_REF(FName, PropertyName);
|
||||
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
// Read wildcard Value input.
|
||||
Stack.MostRecentPropertyAddress = nullptr;
|
||||
Stack.MostRecentPropertyContainer = nullptr;
|
||||
Stack.StepCompiledIn<FStructProperty>(nullptr);
|
||||
|
||||
const FProperty* ValueProp = CastField<FProperty>(Stack.MostRecentProperty);
|
||||
void* ValuePtr = Stack.MostRecentPropertyAddress;
|
||||
|
||||
void* Result = nullptr;
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("GetExternalForceWildcardProperty"),
|
||||
[&Result, &ExecResult, &ExternalForceIndex, &PropertyName](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
if (InKawaiiPhysics.ExternalForces.IsValidIndex(ExternalForceIndex) &&
|
||||
InKawaiiPhysics.ExternalForces[ExternalForceIndex].IsValid())
|
||||
{
|
||||
const auto* ScriptStruct = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetScriptStruct();
|
||||
auto& Force = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetMutable<
|
||||
FKawaiiPhysics_ExternalForce>();
|
||||
|
||||
if (const FProperty* Property = FindFProperty<FProperty>(ScriptStruct, PropertyName))
|
||||
{
|
||||
Result = Property->ContainerPtrToValuePtr<void>(&Force);
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
P_FINISH;
|
||||
|
||||
if (ValuePtr && Result)
|
||||
{
|
||||
P_NATIVE_BEGIN;
|
||||
ValueProp->CopyCompleteValue(ValuePtr, Result);
|
||||
P_NATIVE_END;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
|
||||
#include "KawaiiPhysicsLimitsDataAsset.h"
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "KawaiiPhysics.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(KawaiiPhysicsLimitsDataAsset)
|
||||
|
||||
DEFINE_LOG_CATEGORY(LogKawaiiPhysics);
|
||||
|
||||
struct FCollisionLimitDataCustomVersion
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
// FNameからFBoneReferenceに移行
|
||||
ChangeToBoneReference = 0,
|
||||
DeprecateLimitData,
|
||||
|
||||
// ------------------------------------------------------
|
||||
VersionPlusOne,
|
||||
LatestVersion = VersionPlusOne - 1
|
||||
};
|
||||
|
||||
// The GUID for this custom version number
|
||||
const static FGuid GUID;
|
||||
|
||||
private:
|
||||
FCollisionLimitDataCustomVersion()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
const FGuid FCollisionLimitDataCustomVersion::GUID(0x3A1F7B2E, 0x7B9D6E8C, 0x4C2A9F1D, 0x85B3E4F1);
|
||||
FCustomVersionRegistration GRegisterCollisionLimitDataCustomVersion(FCollisionLimitDataCustomVersion::GUID,
|
||||
FCollisionLimitDataCustomVersion::LatestVersion,
|
||||
TEXT("CollisionLimitData"));
|
||||
|
||||
#if WITH_EDITOR
|
||||
template <typename CollisionLimitType>
|
||||
void UpdateCollisionLimit(TArray<CollisionLimitType>& CollisionLimitsData, const CollisionLimitType& NewLimit)
|
||||
{
|
||||
for (auto& LimitData : CollisionLimitsData)
|
||||
{
|
||||
if (LimitData.Guid == NewLimit.Guid)
|
||||
{
|
||||
LimitData = NewLimit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UKawaiiPhysicsLimitsDataAsset::UpdateLimit(FCollisionLimitBase* Limit)
|
||||
{
|
||||
switch (Limit->Type)
|
||||
{
|
||||
case ECollisionLimitType::Spherical:
|
||||
UpdateCollisionLimit(SphericalLimits, *static_cast<FSphericalLimit*>(Limit));
|
||||
break;
|
||||
case ECollisionLimitType::Capsule:
|
||||
UpdateCollisionLimit(CapsuleLimits, *static_cast<FCapsuleLimit*>(Limit));
|
||||
break;
|
||||
case ECollisionLimitType::Box:
|
||||
UpdateCollisionLimit(BoxLimits, *static_cast<FBoxLimit*>(Limit));
|
||||
break;
|
||||
case ECollisionLimitType::Planar:
|
||||
UpdateCollisionLimit(PlanarLimits, *static_cast<FPlanarLimit*>(Limit));
|
||||
break;
|
||||
case ECollisionLimitType::None:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MarkPackageDirty();
|
||||
}
|
||||
|
||||
template <typename CollisionLimitDataType, typename CollisionLimitType>
|
||||
void SyncCollisionLimits(const TArray<CollisionLimitDataType>& CollisionLimitData,
|
||||
TArray<CollisionLimitType>& CollisionLimits)
|
||||
{
|
||||
CollisionLimits.Empty();
|
||||
for (const auto& Data : CollisionLimitData)
|
||||
{
|
||||
CollisionLimits.Add(Data.Convert());
|
||||
}
|
||||
}
|
||||
|
||||
void UKawaiiPhysicsLimitsDataAsset::Sync()
|
||||
{
|
||||
SyncCollisionLimits(SphericalLimitsData, SphericalLimits);
|
||||
SyncCollisionLimits(CapsuleLimitsData, CapsuleLimits);
|
||||
SyncCollisionLimits(BoxLimitsData, BoxLimits);
|
||||
SyncCollisionLimits(PlanarLimitsData, PlanarLimits);
|
||||
}
|
||||
|
||||
void UKawaiiPhysicsLimitsDataAsset::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeChainProperty(PropertyChangedEvent);
|
||||
|
||||
|
||||
FName ArrayPropertyName = PropertyChangedEvent.MemberProperty
|
||||
? PropertyChangedEvent.MemberProperty->GetFName()
|
||||
: NAME_None;
|
||||
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet &&
|
||||
PropertyChangedEvent.PropertyChain.GetActiveMemberNode())
|
||||
{
|
||||
ArrayPropertyName = PropertyChangedEvent.PropertyChain.GetActiveMemberNode()->GetValue()->GetFName();
|
||||
}
|
||||
|
||||
auto UpdateLimits = [&](auto& Limits)
|
||||
{
|
||||
int32 ArrayIndex = PropertyChangedEvent.GetArrayIndex(ArrayPropertyName.ToString());
|
||||
|
||||
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd ||
|
||||
PropertyChangedEvent.ChangeType == EPropertyChangeType::ValueSet)
|
||||
{
|
||||
Limits[ArrayIndex].SourceType = ECollisionSourceType::DataAsset;
|
||||
}
|
||||
else if (PropertyChangedEvent.ChangeType == EPropertyChangeType::Duplicate)
|
||||
{
|
||||
Limits[ArrayIndex].Guid = FGuid::NewGuid();
|
||||
}
|
||||
};
|
||||
|
||||
if (ArrayPropertyName == GET_MEMBER_NAME_CHECKED(UKawaiiPhysicsLimitsDataAsset, SphericalLimits))
|
||||
{
|
||||
UpdateLimits(SphericalLimits);
|
||||
}
|
||||
else if (ArrayPropertyName == GET_MEMBER_NAME_CHECKED(UKawaiiPhysicsLimitsDataAsset, CapsuleLimits))
|
||||
{
|
||||
UpdateLimits(CapsuleLimits);
|
||||
}
|
||||
else if (ArrayPropertyName == GET_MEMBER_NAME_CHECKED(UKawaiiPhysicsLimitsDataAsset, BoxLimits))
|
||||
{
|
||||
UpdateLimits(BoxLimits);
|
||||
}
|
||||
else if (ArrayPropertyName == GET_MEMBER_NAME_CHECKED(UKawaiiPhysicsLimitsDataAsset, PlanarLimits))
|
||||
{
|
||||
UpdateLimits(PlanarLimits);
|
||||
}
|
||||
|
||||
OnLimitsChanged.Broadcast(PropertyChangedEvent);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
void UKawaiiPhysicsLimitsDataAsset::Serialize(FStructuredArchiveRecord Record)
|
||||
{
|
||||
Super::Serialize(Record);
|
||||
|
||||
Record.GetUnderlyingArchive().UsingCustomVersion(FCollisionLimitDataCustomVersion::GUID);
|
||||
}
|
||||
#endif
|
||||
|
||||
USkeleton* UKawaiiPhysicsLimitsDataAsset::GetSkeleton(bool& bInvalidSkeletonIsError,
|
||||
const IPropertyHandle* PropertyHandle)
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
return Skeleton;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void UKawaiiPhysicsLimitsDataAsset::PostLoad()
|
||||
{
|
||||
Super::PostLoad();
|
||||
|
||||
if (GetLinkerCustomVersion(FCollisionLimitDataCustomVersion::GUID) <
|
||||
FCollisionLimitDataCustomVersion::ChangeToBoneReference)
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
for (auto& Data : SphericalLimitsData)
|
||||
{
|
||||
Data.DrivingBoneReference = FBoneReference(Data.DrivingBoneName);
|
||||
}
|
||||
for (auto& Data : CapsuleLimitsData)
|
||||
{
|
||||
Data.DrivingBoneReference = FBoneReference(Data.DrivingBoneName);
|
||||
}
|
||||
for (auto& Data : BoxLimitsData)
|
||||
{
|
||||
Data.DrivingBoneReference = FBoneReference(Data.DrivingBoneName);
|
||||
}
|
||||
for (auto& Data : PlanarLimitsData)
|
||||
{
|
||||
Data.DrivingBoneReference = FBoneReference(Data.DrivingBoneName);
|
||||
}
|
||||
UE_LOG(LogKawaiiPhysics, Log, TEXT("Update : BoneName -> BoneReference (%s)"), *this->GetName());
|
||||
#endif
|
||||
}
|
||||
|
||||
if (GetLinkerCustomVersion(FCollisionLimitDataCustomVersion::GUID) <
|
||||
FCollisionLimitDataCustomVersion::DeprecateLimitData)
|
||||
{
|
||||
#if WITH_EDITORONLY_DATA
|
||||
Sync();
|
||||
UE_LOG(LogKawaiiPhysics, Log, TEXT("Update : Deprecate LimitData (%s)"), *this->GetName());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Modules/ModuleInterface.h"
|
||||
|
||||
DECLARE_LOG_CATEGORY_EXTERN(LogKawaiiPhysics, Log, All);
|
||||
|
||||
class FKawaiiPhysicsModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "Interfaces/Interface_BoneReferenceSkeletonProvider.h"
|
||||
#include "KawaiiPhysicsBoneConstraintsDataAsset.generated.h"
|
||||
|
||||
/**
|
||||
* Struct representing the data for modifying bone constraints in KawaiiPhysics.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct KAWAIIPHYSICS_API FModifyBoneConstraintData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Name of the first bone (deprecated) */
|
||||
UPROPERTY()
|
||||
FName BoneName1;
|
||||
|
||||
/** Name of the second bone (deprecated) */
|
||||
UPROPERTY()
|
||||
FName BoneName2;
|
||||
|
||||
/** Reference to the first bone */
|
||||
UPROPERTY(EditAnywhere, category = "KawaiiPhysics")
|
||||
FBoneReference BoneReference1;
|
||||
|
||||
/** Reference to the second bone */
|
||||
UPROPERTY(EditAnywhere, category = "KawaiiPhysics")
|
||||
FBoneReference BoneReference2;
|
||||
|
||||
/** Whether to override the compliance type */
|
||||
UPROPERTY(EditAnywhere, category = "KawaiiPhysics", meta=(InlineEditConditionToggle))
|
||||
bool bOverrideCompliance = false;
|
||||
|
||||
/** The compliance type to use if overriding */
|
||||
UPROPERTY(EditAnywhere, category = "KawaiiPhysics", meta=(EditCondition="bOverrideCompliance"))
|
||||
EXPBDComplianceType ComplianceType = EXPBDComplianceType::Leather;
|
||||
|
||||
/**
|
||||
* Updates the bone constraint data with the given constraint.
|
||||
* @param BoneConstraint The bone constraint to update from.
|
||||
*/
|
||||
void Update(const FModifyBoneConstraint& BoneConstraint);
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct representing a set of regex patterns for bones in KawaiiPhysics.
|
||||
*/
|
||||
USTRUCT(BlueprintType)
|
||||
struct FRegexPatternBoneSet
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Regex pattern for the first bone */
|
||||
UPROPERTY(EditAnywhere, Category="Helper")
|
||||
FString RegexPatternBone1;
|
||||
|
||||
/** Regex pattern for the second bone */
|
||||
UPROPERTY(EditAnywhere, Category="Helper")
|
||||
FString RegexPatternBone2;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Data asset for managing bone constraints in KawaiiPhysics.
|
||||
*/
|
||||
UCLASS(Blueprintable)
|
||||
class KAWAIIPHYSICS_API UKawaiiPhysicsBoneConstraintsDataAsset : public UDataAsset,
|
||||
public IBoneReferenceSkeletonProvider
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Array of bone constraint data */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Bone Constraint (Experimental)",
|
||||
meta=(TitleProperty="{BoneReference1} - {BoneReference2}"))
|
||||
TArray<FModifyBoneConstraintData> BoneConstraintsData;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
|
||||
/** List of regex patterns for bones */
|
||||
UPROPERTY(EditAnywhere, Category="Helper")
|
||||
TArray<FRegexPatternBoneSet> RegexPatternList;
|
||||
|
||||
/** Preview skeleton for editor */
|
||||
UPROPERTY(EditAnywhere, Category = "Skeleton")
|
||||
TSoftObjectPtr<USkeleton> PreviewSkeleton;
|
||||
|
||||
/** List of preview bones */
|
||||
UPROPERTY(VisibleAnywhere, Category = "Skeleton", meta= (EditCondition=false))
|
||||
TArray<FBoneReference> PreviewBoneList;
|
||||
|
||||
/** String representation of the preview bone list */
|
||||
UPROPERTY()
|
||||
FString PreviewBoneListString;
|
||||
#endif
|
||||
|
||||
// Begin UObject Interface.
|
||||
virtual void Serialize(FStructuredArchiveRecord Record) override;
|
||||
virtual void PostLoad() override;
|
||||
// End UObject Interface.
|
||||
|
||||
// IBoneReferenceSkeletonProvider interface
|
||||
virtual USkeleton* GetSkeleton(bool& bInvalidSkeletonIsError, const IPropertyHandle* PropertyHandle) override;
|
||||
|
||||
/** Generates bone constraints based on the current data */
|
||||
TArray<FModifyBoneConstraint> GenerateBoneConstraints();
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
/** Applies regex patterns to the bone constraints */
|
||||
UFUNCTION(BlueprintCallable, CallInEditor, Category="Helper")
|
||||
void ApplyRegex();
|
||||
|
||||
/** Updates the preview bone list */
|
||||
void UpdatePreviewBoneList();
|
||||
|
||||
/** Handles property changes in the editor */
|
||||
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "KawaiiPhysicsCustomExternalForce.generated.h"
|
||||
|
||||
|
||||
UCLASS(Abstract, Blueprintable, EditInlineNew, CollapseCategories)
|
||||
class KAWAIIPHYSICS_API UKawaiiPhysics_CustomExternalForce : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayPriority=1), Category="KawaiiPhysics|CustomExternalForce")
|
||||
bool bIsEnabled = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayPriority=1), Category="KawaiiPhysics|CustomExternalForce")
|
||||
bool bDrawDebug = false;
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
void PreApply(UPARAM(ref) FAnimNode_KawaiiPhysics& Node,
|
||||
const USkeletalMeshComponent* SkelComp);
|
||||
|
||||
virtual void PreApply_Implementation(
|
||||
UPARAM(ref) FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp)PURE_VIRTUAL(,);
|
||||
|
||||
UFUNCTION(BlueprintNativeEvent)
|
||||
void Apply(UPARAM(ref) FAnimNode_KawaiiPhysics& Node, int32 ModifyBoneIndex,
|
||||
const USkeletalMeshComponent* SkelComp, const FTransform& BoneTransform);
|
||||
|
||||
virtual void Apply_Implementation(
|
||||
UPARAM(ref) FAnimNode_KawaiiPhysics& Node, int32 ModifyBoneIndex, const USkeletalMeshComponent* SkelComp,
|
||||
const FTransform& BoneTransform)
|
||||
{
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="KawaiiPhysics|CustomExternalForce")
|
||||
virtual bool IsDebugEnabled()
|
||||
{
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
if (CVarAnimNodeKawaiiPhysicsDebug.GetValueOnAnyThread())
|
||||
{
|
||||
return bDrawDebug;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,448 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "SceneManagement.h"
|
||||
#include "Curves/CurveVector.h"
|
||||
#include "KawaiiPhysicsExternalForce.generated.h"
|
||||
|
||||
/**
|
||||
* Enum representing the space in which external forces are simulated.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EExternalForceSpace : uint8
|
||||
{
|
||||
/** Simulate in component space. Moving the entire skeletal mesh will have no affect on velocities */
|
||||
ComponentSpace,
|
||||
/** Simulate in world space. Moving the skeletal mesh will generate velocity changes */
|
||||
WorldSpace,
|
||||
/** Simulate in another bone space. Moving the entire skeletal mesh and individually modifying the base bone will have no affect on velocities */
|
||||
BoneSpace,
|
||||
};
|
||||
|
||||
/**
|
||||
* Enum representing the evaluation type for external force curves.
|
||||
*/
|
||||
UENUM(BlueprintType)
|
||||
enum class EExternalForceCurveEvaluateType : uint8
|
||||
{
|
||||
/** Evaluate the curve at a single point */
|
||||
Single,
|
||||
/** Evaluate the curve by averaging multiple points */
|
||||
Average,
|
||||
/** Evaluate the curve by taking the maximum value from multiple points */
|
||||
Max,
|
||||
/** Evaluate the curve by taking the minimum value from multiple points */
|
||||
Min
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// Base
|
||||
///
|
||||
USTRUCT(BlueprintType)
|
||||
struct KAWAIIPHYSICS_API FKawaiiPhysics_ExternalForce
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Whether the external force is enabled */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayPriority=1), Category="KawaiiPhysics|ExternalForce")
|
||||
bool bIsEnabled = true;
|
||||
|
||||
/** Whether to draw debug information for the external force */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayPriority=1), Category="KawaiiPhysics|ExternalForce")
|
||||
bool bDrawDebug = false;
|
||||
|
||||
/**
|
||||
* 外力を適応するボーンを指定(=指定しなかったボーンには適応しない)
|
||||
* Specify the bones to which the external force will be applied (= the force will not be applied to bones that are not specified)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, meta=(DisplayPriority=1), Category="KawaiiPhysics|ExternalForce")
|
||||
TArray<FBoneReference> ApplyBoneFilter;
|
||||
|
||||
/**
|
||||
* 外力を適応しないボーンを指定
|
||||
* Specify the bones to which the external force will be NOT applied
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, meta=(DisplayPriority=1), Category="KawaiiPhysics|ExternalForce")
|
||||
TArray<FBoneReference> IgnoreBoneFilter;
|
||||
|
||||
/** The space in which the external force is simulated */
|
||||
UPROPERTY(EditAnywhere, meta=(DisplayPriority=1, EditCondition=bCanSelectForceSpace, EditConditionHides),
|
||||
Category="KawaiiPhysics|ExternalForce")
|
||||
EExternalForceSpace ExternalForceSpace = EExternalForceSpace::WorldSpace;
|
||||
|
||||
/** Range for randomizing the force scale */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(DisplayPriority=1), Category="KawaiiPhysics|ExternalForce")
|
||||
FFloatInterval RandomForceScaleRange = FFloatInterval(1.0f, 1.0f);
|
||||
|
||||
/** Owner of the external force */
|
||||
UPROPERTY()
|
||||
TObjectPtr<UObject> ExternalOwner;
|
||||
|
||||
/** Whether the external force is applied only once */
|
||||
UPROPERTY()
|
||||
bool bIsOneShot = false;
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
/** Length of the debug arrow */
|
||||
float DebugArrowLength = 5.0f;
|
||||
|
||||
/** Size of the debug arrow */
|
||||
float DebugArrowSize = 1.0f;
|
||||
|
||||
/** Offset for the debug arrow */
|
||||
FVector DebugArrowOffset = FVector::Zero();
|
||||
|
||||
/** Map of bone names to forces for debugging */
|
||||
TMap<FName, FVector> BoneForceMap;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/** Randomized scale of the force */
|
||||
UPROPERTY()
|
||||
float RandomizedForceScale = 0.0f;
|
||||
|
||||
/** The force vector */
|
||||
UPROPERTY()
|
||||
FVector Force = FVector::Zero();
|
||||
|
||||
/** Transform of the component */
|
||||
UPROPERTY()
|
||||
FTransform ComponentTransform;
|
||||
|
||||
/** Whether the force space can be selected */
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
bool bCanSelectForceSpace = true;
|
||||
|
||||
public:
|
||||
virtual ~FKawaiiPhysics_ExternalForce() = default;
|
||||
|
||||
virtual void Initialize(const FAnimationInitializeContext& Context)
|
||||
{
|
||||
}
|
||||
|
||||
/** Prepares the external force before applying it */
|
||||
virtual void PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp)
|
||||
{
|
||||
ComponentTransform = SkelComp->GetComponentTransform();
|
||||
RandomizedForceScale = FMath::RandRange(RandomForceScaleRange.Min, RandomForceScaleRange.Max);
|
||||
}
|
||||
|
||||
/** Applies the external force to a bone */
|
||||
virtual void Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext, const FTransform& BoneTM = FTransform::Identity)
|
||||
{
|
||||
}
|
||||
|
||||
/** Finalizes the external force after applying it */
|
||||
virtual void PostApply(FAnimNode_KawaiiPhysics& Node)
|
||||
{
|
||||
if (bIsOneShot)
|
||||
{
|
||||
Node.ExternalForces.RemoveAll([&](FInstancedStruct& InstancedStruct)
|
||||
{
|
||||
const auto* ExternalForcePtr = InstancedStruct.GetMutablePtr<FKawaiiPhysics_ExternalForce>();
|
||||
return ExternalForcePtr == this;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks if debug information should be drawn */
|
||||
virtual bool IsDebugEnabled(bool bInPersona = false)
|
||||
{
|
||||
if (bInPersona)
|
||||
{
|
||||
return bDrawDebug && bIsEnabled;
|
||||
}
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
if (CVarAnimNodeKawaiiPhysicsDebug.GetValueOnAnyThread())
|
||||
{
|
||||
return bDrawDebug && bIsEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if ENABLE_ANIM_DEBUG
|
||||
/** Draws debug information for the external force */
|
||||
virtual void AnimDrawDebug(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext)
|
||||
{
|
||||
if (IsDebugEnabled() && !Force.IsZero())
|
||||
{
|
||||
const auto AnimInstanceProxy = PoseContext.AnimInstanceProxy;
|
||||
const FVector ModifyRootBoneLocationWS = AnimInstanceProxy->GetComponentTransform().TransformPosition(
|
||||
Bone.Location);
|
||||
|
||||
AnimInstanceProxy->AnimDrawDebugDirectionalArrow(
|
||||
ModifyRootBoneLocationWS + DebugArrowOffset,
|
||||
ModifyRootBoneLocationWS + DebugArrowOffset + BoneForceMap.Find(Bone.BoneRef.BoneName)->GetSafeNormal()
|
||||
*
|
||||
DebugArrowLength,
|
||||
DebugArrowSize, FColor::Red, false, 0.f, 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_EDITOR
|
||||
/** Draws debug information for the external force in edit mode */
|
||||
virtual void AnimDrawDebugForEditMode(const FKawaiiPhysicsModifyBone& ModifyBone,
|
||||
const FAnimNode_KawaiiPhysics& Node, FPrimitiveDrawInterface* PDI)
|
||||
{
|
||||
if (IsDebugEnabled(true) && CanApply(ModifyBone) && !Force.IsNearlyZero() && BoneForceMap.Contains(
|
||||
ModifyBone.BoneRef.BoneName))
|
||||
{
|
||||
const FTransform ArrowTransform = FTransform(
|
||||
BoneForceMap.Find(ModifyBone.BoneRef.BoneName)->GetSafeNormal().ToOrientationRotator(),
|
||||
ModifyBone.Location + DebugArrowOffset);
|
||||
DrawDirectionalArrow(PDI, ArrowTransform.ToMatrixNoScale(), FColor::Red, DebugArrowLength, DebugArrowSize,
|
||||
SDPG_Foreground, 1.0f);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
/** Checks if the external force can be applied to a bone */
|
||||
bool CanApply(const FKawaiiPhysicsModifyBone& Bone) const
|
||||
{
|
||||
if (!ApplyBoneFilter.IsEmpty() && !ApplyBoneFilter.Contains(Bone.BoneRef))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IgnoreBoneFilter.IsEmpty() && IgnoreBoneFilter.Contains(Bone.BoneRef))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
///
|
||||
/// Basic
|
||||
///
|
||||
USTRUCT(BlueprintType, DisplayName = "Basic")
|
||||
struct KAWAIIPHYSICS_API FKawaiiPhysics_ExternalForce_Basic : public FKawaiiPhysics_ExternalForce
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Direction of the force */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
FVector ForceDir = FVector::Zero();
|
||||
|
||||
/**
|
||||
* 各ボーンに適用するForce Rateを補正。
|
||||
* 「RootBoneから特定のボーンまでの長さ / RootBoneから末端のボーンまでの長さ」(0.0~1.0)の値におけるカーブの値をForceRateに乗算
|
||||
* Corrects the Force Rate applied to each bone.
|
||||
* Multiplies the ForceRate by the curve value for "Length from RootBone to specific bone / Length from RootBone to end bone" (0.0~1.0)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
FRuntimeFloatCurve ForceRateByBoneLengthRate;
|
||||
|
||||
/** Interval for applying the force */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
float Interval = 0.0f;
|
||||
|
||||
virtual void PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp) override;
|
||||
virtual void Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext,
|
||||
const FTransform& BoneTM = FTransform::Identity) override;
|
||||
|
||||
private:
|
||||
/** Current time */
|
||||
UPROPERTY()
|
||||
float Time = 0.0f;
|
||||
|
||||
/** Previous time */
|
||||
UPROPERTY()
|
||||
float PrevTime = 0.0f;
|
||||
};
|
||||
|
||||
///
|
||||
/// Gravity
|
||||
///
|
||||
USTRUCT(BlueprintType, DisplayName = "Gravity")
|
||||
struct KAWAIIPHYSICS_API FKawaiiPhysics_ExternalForce_Gravity : public FKawaiiPhysics_ExternalForce
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FKawaiiPhysics_ExternalForce_Gravity()
|
||||
{
|
||||
bCanSelectForceSpace = false;
|
||||
ExternalForceSpace = EExternalForceSpace::WorldSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* 各ボーンに適用するForce Rateを補正。
|
||||
* 「RootBoneから特定のボーンまでの長さ / RootBoneから末端のボーンまでの長さ」(0.0~1.0)の値におけるカーブの値をForceRateに乗算
|
||||
* Corrects the Force Rate applied to each bone.
|
||||
* Multiplies the ForceRate by the curve value for "Length from RootBone to specific bone / Length from RootBone to end bone" (0.0~1.0)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
FRuntimeFloatCurve ForceRateByBoneLengthRate;
|
||||
|
||||
/**
|
||||
* Character側で設定されたCustomGravityDirectionを使用するフラグ(UE5.4以降)
|
||||
* Flag to use CustomGravityDirection set on the Character side (UE5.4 and later)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
bool bUseCharacterGravityDirection = false;
|
||||
|
||||
/**
|
||||
* Character側で設定されたGravityScaleを使用するフラグ
|
||||
* Flag to use GravityScale set on the Character side
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
bool bUseCharacterGravityScale = false;
|
||||
|
||||
/**
|
||||
* Direction to override the gravity.
|
||||
* This direction is used when bUseOverrideGravityDirection is true.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,
|
||||
meta = (EditCondition = "bUseOverrideGravityDirection"), Category="KawaiiPhysics|ExternalForce")
|
||||
FVector OverrideGravityDirection = FVector::Zero();
|
||||
|
||||
/**
|
||||
* Flag to determine whether to use the override gravity direction.
|
||||
* If true, the gravity direction will be overridden by OverrideGravityDirection.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (InlineEditConditionToggle),
|
||||
Category="KawaiiPhysics|ExternalForce")
|
||||
bool bUseOverrideGravityDirection = false;
|
||||
|
||||
virtual void PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp) override;
|
||||
virtual void Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext,
|
||||
const FTransform& BoneTM = FTransform::Identity) override;
|
||||
};
|
||||
|
||||
///
|
||||
/// Curve
|
||||
///
|
||||
USTRUCT(BlueprintType, DisplayName = "Curve")
|
||||
struct KAWAIIPHYSICS_API FKawaiiPhysics_ExternalForce_Curve : public FKawaiiPhysics_ExternalForce
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/**
|
||||
* 時間に応じて変化する外力をカーブで設定。X軸:Time Y軸:Force
|
||||
* Set the external force that changes over time using a curve. X-axis: Time Y-axis: Force
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (XAxisName="Time", YAxisName="Force"),
|
||||
Category="KawaiiPhysics|ExternalForce")
|
||||
FRuntimeVectorCurve ForceCurve;
|
||||
|
||||
/**
|
||||
* カーブの評価方式。
|
||||
* Single以外に設定した場合:前フレームからの経過時間をSubstepCountで分割し、
|
||||
* 分割後の各時間におけるカーブの値の平均・最大値・最小値を外力として使用
|
||||
* Curve evaluation method
|
||||
* If set to anything other than Single: The time elapsed from the previous frame is divided by SubstepCount,
|
||||
* and the Average, Maximum, or Minimum values of the curve at each time point after division are used as external forces.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
EExternalForceCurveEvaluateType CurveEvaluateType = EExternalForceCurveEvaluateType::Single;
|
||||
|
||||
/**
|
||||
* 経過時間の分割数
|
||||
* Number of divisions of elapsed time
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite,
|
||||
meta=(EditCondition="CurveEvaluateType!=EExternalForceCurveEvaluateType::Single"),
|
||||
Category="KawaiiPhysics|ExternalForce")
|
||||
int SubstepCount = 10;
|
||||
|
||||
/**
|
||||
* Scale factor for the time.
|
||||
* This value is used to scale the time for the external force.
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category ="KawaiiPhysics|ExternalForce")
|
||||
float TimeScale = 1.0f;
|
||||
|
||||
/**
|
||||
* 各ボーンに適用するForce Rateを補正。
|
||||
* 「RootBoneから特定のボーンまでの長さ / RootBoneから末端のボーンまでの長さ」(0.0~1.0)の値におけるカーブの値をForceRateに乗算
|
||||
* Corrects the Force Rate applied to each bone.
|
||||
* Multiplies the ForceRate by the curve value for "Length from RootBone to specific bone / Length from RootBone to end bone" (0.0~1.0)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
FRuntimeFloatCurve ForceRateByBoneLengthRate;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Current time.
|
||||
* This value is used to track the current time for the external force.
|
||||
*/
|
||||
UPROPERTY()
|
||||
float Time = 0.0f;
|
||||
|
||||
/**
|
||||
* Previous time.
|
||||
* This value is used to track the previous time for the external force.
|
||||
*/
|
||||
UPROPERTY()
|
||||
float PrevTime = 0.0f;
|
||||
|
||||
/**
|
||||
* Maximum curve time.
|
||||
* This value is used to track the maximum time for the force curve.
|
||||
*/
|
||||
UPROPERTY()
|
||||
float MaxCurveTime = 0.0f;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Initializes the maximum curve time.
|
||||
* This function calculates the maximum time value from the ForceCurve and sets it to MaxCurveTime.
|
||||
*/
|
||||
void InitMaxCurveTime();
|
||||
|
||||
virtual void Initialize(const FAnimationInitializeContext& Context) override;
|
||||
virtual void PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp) override;
|
||||
virtual void Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext,
|
||||
const FTransform& BoneTM = FTransform::Identity) override;
|
||||
};
|
||||
|
||||
///
|
||||
/// Wind
|
||||
///
|
||||
USTRUCT(BlueprintType, DisplayName = "Wind")
|
||||
struct KAWAIIPHYSICS_API FKawaiiPhysics_ExternalForce_Wind : public FKawaiiPhysics_ExternalForce
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
FKawaiiPhysics_ExternalForce_Wind()
|
||||
{
|
||||
bCanSelectForceSpace = false;
|
||||
ExternalForceSpace = EExternalForceSpace::WorldSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* 各ボーンに適用するForce Rateを補正。
|
||||
* 「RootBoneから特定のボーンまでの長さ / RootBoneから末端のボーンまでの長さ」(0.0~1.0)の値におけるカーブの値をForceRateに乗算
|
||||
* Corrects the Force Rate applied to each bone.
|
||||
* Multiplies the ForceRate by the curve value for "Length from RootBone to specific bone / Length from RootBone to end bone" (0.0~1.0)
|
||||
*/
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="KawaiiPhysics|ExternalForce")
|
||||
FRuntimeFloatCurve ForceRateByBoneLengthRate;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Pointer to the world.
|
||||
* This is used to access the world context for the external force.
|
||||
*/
|
||||
UPROPERTY()
|
||||
TObjectPtr<UWorld> World;
|
||||
|
||||
public:
|
||||
virtual void PreApply(FAnimNode_KawaiiPhysics& Node, const USkeletalMeshComponent* SkelComp) override;
|
||||
virtual void Apply(FKawaiiPhysicsModifyBone& Bone, FAnimNode_KawaiiPhysics& Node,
|
||||
const FComponentSpacePoseContext& PoseContext,
|
||||
const FTransform& BoneTM = FTransform::Identity) override;
|
||||
};
|
||||
@@ -0,0 +1,584 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "KawaiiPhysicsExternalForce.h"
|
||||
#include "Animation/AnimNodeReference.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "KawaiiPhysicsLibrary.generated.h"
|
||||
|
||||
UENUM()
|
||||
enum class EKawaiiPhysicsAccessExternalForceResult : uint8
|
||||
{
|
||||
Valid,
|
||||
NotValid,
|
||||
};
|
||||
|
||||
#define KAWAIIPHYSICS_VALUE_SETTER(PropertyType, PropertyName) \
|
||||
{ \
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>( \
|
||||
TEXT("Set" #PropertyName), \
|
||||
[PropertyName](FAnimNode_KawaiiPhysics& InKawaiiPhysics) { \
|
||||
InKawaiiPhysics.PropertyName = PropertyName; \
|
||||
}); \
|
||||
return KawaiiPhysics; \
|
||||
}
|
||||
|
||||
#define KAWAIIPHYSICS_VALUE_GETTER(PropertyType, PropertyName) \
|
||||
{ \
|
||||
PropertyType Value; \
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>( \
|
||||
TEXT("Get" #PropertyName), \
|
||||
[&Value](FAnimNode_KawaiiPhysics& InKawaiiPhysics) { \
|
||||
Value = InKawaiiPhysics.PropertyName; \
|
||||
}); \
|
||||
return Value; \
|
||||
}
|
||||
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FKawaiiPhysicsReference : public FAnimNodeReference
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
using FInternalNodeType = FAnimNode_KawaiiPhysics;
|
||||
};
|
||||
|
||||
/**
|
||||
* Exposes operations to be performed on a blend space anim node.
|
||||
*/
|
||||
UCLASS()
|
||||
class KAWAIIPHYSICS_API UKawaiiPhysicsLibrary : public UBlueprintFunctionLibrary
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Get a KawaiiPhysics from an anim node */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta = (BlueprintThreadSafe, ExpandEnumAsExecs = "Result"))
|
||||
static FKawaiiPhysicsReference ConvertToKawaiiPhysics(const FAnimNodeReference& Node,
|
||||
EAnimNodeReferenceConversionResult& Result);
|
||||
|
||||
/** Get a KawaiiPhysics from an anim node (pure). */
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics",
|
||||
meta = (BlueprintThreadSafe, DisplayName = "Convert to Kawaii Physics (Pure)"))
|
||||
static void ConvertToKawaiiPhysicsPure(const FAnimNodeReference& Node, FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
bool& Result)
|
||||
{
|
||||
EAnimNodeReferenceConversionResult ConversionResult;
|
||||
KawaiiPhysics = ConvertToKawaiiPhysics(Node, ConversionResult);
|
||||
Result = (ConversionResult == EAnimNodeReferenceConversionResult::Succeeded);
|
||||
}
|
||||
|
||||
/** Collect KawaiiPhysics Node References from AnimInstance(ABP) */
|
||||
static bool CollectKawaiiPhysicsNodes(TArray<FKawaiiPhysicsReference>& Nodes,
|
||||
UAnimInstance* AnimInstance, const FGameplayTagContainer& FilterTags,
|
||||
bool bFilterExactMatch);
|
||||
|
||||
/** Collect KawaiiPhysics Node References from SkeletalMeshComponent */
|
||||
static bool CollectKawaiiPhysicsNodes(TArray<FKawaiiPhysicsReference>& Nodes,
|
||||
USkeletalMeshComponent* MeshComp, const FGameplayTagContainer& FilterTags,
|
||||
bool bFilterExactMatch);
|
||||
|
||||
/** ResetDynamics */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference ResetDynamics(const FKawaiiPhysicsReference& KawaiiPhysics);
|
||||
|
||||
/** Set RootBone */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetRootBoneName(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
UPARAM(ref) FName& RootBoneName);
|
||||
/** Get RootBone */
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FName GetRootBoneName(const FKawaiiPhysicsReference& KawaiiPhysics);
|
||||
|
||||
/** Set ExcludeBones */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetExcludeBoneNames(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
UPARAM(ref) TArray<FName>& ExcludeBoneNames);
|
||||
/** Get ExcludeBones */
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static TArray<FName> GetExcludeBoneNames(const FKawaiiPhysicsReference& KawaiiPhysics);
|
||||
|
||||
// PhysicsSettings
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetPhysicsSettings(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
UPARAM(ref) FKawaiiPhysicsSettings& PhysicsSettings)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(FKawaiiPhysicsSettings, PhysicsSettings);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsSettings GetPhysicsSettings(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(FKawaiiPhysicsSettings, PhysicsSettings);
|
||||
}
|
||||
|
||||
// DummyBoneLength
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetDummyBoneLength(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
float DummyBoneLength)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(float, DummyBoneLength);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static float GetDummyBoneLength(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(float, DummyBoneLength);
|
||||
}
|
||||
|
||||
/** TeleportDistanceThreshold */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetTeleportDistanceThreshold(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
float TeleportDistanceThreshold)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(float, TeleportDistanceThreshold);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static float GetTeleportDistanceThreshold(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(float, TeleportDistanceThreshold);
|
||||
}
|
||||
|
||||
/** TeleportRotationThreshold */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetTeleportRotationThreshold(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
float TeleportRotationThreshold)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(float, TeleportRotationThreshold);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static float GetTeleportRotationThreshold(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(float, TeleportRotationThreshold);
|
||||
}
|
||||
|
||||
/** Gravity */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetGravity(const FKawaiiPhysicsReference& KawaiiPhysics, FVector Gravity)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(FVector, Gravity);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FVector GetGravity(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(FVector, Gravity);
|
||||
}
|
||||
|
||||
/** EnableWind */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetEnableWind(const FKawaiiPhysicsReference& KawaiiPhysics, bool bEnableWind)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(bool, bEnableWind);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static bool GetEnableWind(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(bool, bEnableWind);
|
||||
}
|
||||
|
||||
/** WindScale */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetWindScale(const FKawaiiPhysicsReference& KawaiiPhysics, float WindScale)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(float, WindScale);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static float GetWindScale(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(float, WindScale);
|
||||
}
|
||||
|
||||
/** AllowWorldCollision */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetAllowWorldCollision(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
bool bAllowWorldCollision)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(bool, bAllowWorldCollision);
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static bool GetAllowWorldCollision(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(bool, bAllowWorldCollision);
|
||||
}
|
||||
|
||||
/** NeedWarmUp */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetNeedWarmUp(const FKawaiiPhysicsReference& KawaiiPhysics, bool bNeedWarmUp)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(bool, bNeedWarmUp);
|
||||
}
|
||||
|
||||
/** NeedWarmUp */
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static bool GetNeedWarmUp(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(bool, bNeedWarmUp);
|
||||
}
|
||||
|
||||
/** LimitsDataAsset */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static FKawaiiPhysicsReference SetLimitsDataAsset(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
UKawaiiPhysicsLimitsDataAsset* LimitsDataAsset)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_SETTER(TObjectPtr<UKawaiiPhysicsLimitsDataAsset>, LimitsDataAsset);
|
||||
}
|
||||
|
||||
/** LimitsDataAsset */
|
||||
UFUNCTION(BlueprintPure, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static UKawaiiPhysicsLimitsDataAsset* GetLimitsDataAsset(const FKawaiiPhysicsReference& KawaiiPhysics)
|
||||
{
|
||||
KAWAIIPHYSICS_VALUE_GETTER(TObjectPtr<UKawaiiPhysicsLimitsDataAsset>, LimitsDataAsset);
|
||||
}
|
||||
|
||||
/** Add ExternalForce With ExecResult */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference AddExternalForceWithExecResult(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
FInstancedStruct& ExternalForce, UObject* Owner);
|
||||
|
||||
/** Add ExternalForce */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static bool AddExternalForce(const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
FInstancedStruct& ExternalForce, UObject* Owner, bool bIsOneShot = false);
|
||||
|
||||
/** Add ExternalForces to SkeletalMeshComponent */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static bool AddExternalForcesToComponent(USkeletalMeshComponent* MeshComp,
|
||||
UPARAM(ref) TArray<FInstancedStruct>& ExternalForces, UObject* Owner,
|
||||
UPARAM(ref) FGameplayTagContainer& FilterTags,
|
||||
bool bFilterExactMatch = false,
|
||||
bool bIsOneShot = false);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics", meta=(BlueprintThreadSafe))
|
||||
static bool RemoveExternalForcesFromComponent(USkeletalMeshComponent* MeshComp, UObject* Owner,
|
||||
UPARAM(ref) FGameplayTagContainer& FilterTags,
|
||||
bool bFilterExactMatch = false);
|
||||
|
||||
|
||||
/** Set ExternalForceParameter template */
|
||||
template <typename ValueType, typename PropertyType>
|
||||
static FKawaiiPhysicsReference SetExternalForceProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
ValueType Value);
|
||||
/** Get ExternalForceParameter template */
|
||||
template <typename ValueType>
|
||||
static ValueType GetExternalForceProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName);
|
||||
|
||||
/** Set ExternalForceParameter template struct */
|
||||
template <typename ValueType>
|
||||
static FKawaiiPhysicsReference SetExternalForceStructProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
ValueType Value);
|
||||
/** Get ExternalForceParameter template struct */
|
||||
template <typename ValueType>
|
||||
static ValueType GetExternalForceStructProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex,
|
||||
FName PropertyName);
|
||||
|
||||
/** Set ExternalForceParameter bool */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference SetExternalForceBoolProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
bool Value)
|
||||
{
|
||||
return SetExternalForceProperty<bool, FBoolProperty>(ExecResult, KawaiiPhysics, ExternalForceIndex,
|
||||
PropertyName, Value);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter bool */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static bool GetExternalForceBoolProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName)
|
||||
{
|
||||
return GetExternalForceProperty<bool>(ExecResult, KawaiiPhysics, ExternalForceIndex, PropertyName);
|
||||
}
|
||||
|
||||
/** Set ExternalForceParameter int */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference SetExternalForceIntProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
int32 Value)
|
||||
{
|
||||
return SetExternalForceProperty<int32, FIntProperty>(ExecResult, KawaiiPhysics, ExternalForceIndex,
|
||||
PropertyName, Value);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter int */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static int32 GetExternalForceIntProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName)
|
||||
{
|
||||
return GetExternalForceProperty<int32>(ExecResult, KawaiiPhysics, ExternalForceIndex, PropertyName);
|
||||
}
|
||||
|
||||
/** Set ExternalForceParameter float */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference SetExternalForceFloatProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
float Value)
|
||||
{
|
||||
return SetExternalForceProperty<float, FFloatProperty>(ExecResult, KawaiiPhysics, ExternalForceIndex,
|
||||
PropertyName, Value);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter float */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static float GetExternalForceFloatProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName)
|
||||
{
|
||||
return GetExternalForceProperty<float>(ExecResult, KawaiiPhysics, ExternalForceIndex, PropertyName);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter Vector */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference SetExternalForceVectorProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
FVector Value)
|
||||
{
|
||||
return SetExternalForceStructProperty<FVector>(ExecResult, KawaiiPhysics, ExternalForceIndex,
|
||||
PropertyName, Value);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter Vector */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FVector GetExternalForceVectorProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName)
|
||||
{
|
||||
return GetExternalForceStructProperty<FVector>(ExecResult, KawaiiPhysics, ExternalForceIndex, PropertyName);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter Rotator */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference SetExternalForceRotatorProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
FRotator Value)
|
||||
{
|
||||
return SetExternalForceStructProperty<FRotator>(ExecResult, KawaiiPhysics, ExternalForceIndex,
|
||||
PropertyName, Value);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter Rotator */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FRotator GetExternalForceRotatorProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex,
|
||||
FName PropertyName)
|
||||
{
|
||||
return GetExternalForceStructProperty<FRotator>(ExecResult, KawaiiPhysics, ExternalForceIndex, PropertyName);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter Transform */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FKawaiiPhysicsReference SetExternalForceTransformProperty(
|
||||
EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName,
|
||||
FTransform Value)
|
||||
{
|
||||
return SetExternalForceStructProperty<FTransform>(ExecResult, KawaiiPhysics, ExternalForceIndex,
|
||||
PropertyName, Value);
|
||||
}
|
||||
|
||||
/** Get ExternalForceParameter Transform */
|
||||
UFUNCTION(BlueprintCallable, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult"))
|
||||
static FTransform GetExternalForceTransformProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex,
|
||||
FName PropertyName)
|
||||
{
|
||||
return GetExternalForceStructProperty<FTransform>(ExecResult, KawaiiPhysics, ExternalForceIndex, PropertyName);
|
||||
}
|
||||
|
||||
/** Set ExternalForceParameter Wildcard */
|
||||
UFUNCTION(BlueprintCallable, CustomThunk, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult", CustomStructureParam = "Value"))
|
||||
static void SetExternalForceWildcardProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName, const int32& Value)
|
||||
{
|
||||
checkNoEntry();
|
||||
}
|
||||
|
||||
|
||||
/** Get ExternalForceParameter Wildcard */
|
||||
UFUNCTION(BlueprintCallable, CustomThunk, Category = "Kawaii Physics",
|
||||
meta=(BlueprintThreadSafe, ExpandEnumAsExecs = "ExecResult", CustomStructureParam = "Value"))
|
||||
static void GetExternalForceWildcardProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics, int ExternalForceIndex,
|
||||
FName PropertyName, int32& Value)
|
||||
{
|
||||
checkNoEntry();
|
||||
}
|
||||
|
||||
private:
|
||||
DECLARE_FUNCTION(execSetExternalForceWildcardProperty);
|
||||
DECLARE_FUNCTION(execGetExternalForceWildcardProperty);
|
||||
};
|
||||
|
||||
template <typename ValueType, typename PropertyType>
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::SetExternalForceProperty(
|
||||
EKawaiiPhysicsAccessExternalForceResult& ExecResult, const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName, ValueType Value)
|
||||
{
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("SetExternalForceProperty"),
|
||||
[&ExecResult, &ExternalForceIndex, &PropertyName, &Value](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
if (InKawaiiPhysics.ExternalForces.IsValidIndex(ExternalForceIndex) &&
|
||||
InKawaiiPhysics.ExternalForces[ExternalForceIndex].IsValid())
|
||||
{
|
||||
const auto* ScriptStruct = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetScriptStruct();
|
||||
auto& Force = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetMutable<
|
||||
FKawaiiPhysics_ExternalForce>();
|
||||
|
||||
if (const PropertyType* Property = FindFProperty<PropertyType>(ScriptStruct, PropertyName))
|
||||
{
|
||||
if (void* ValuePtr = Property->template ContainerPtrToValuePtr<uint8>(&Force))
|
||||
{
|
||||
Property->SetPropertyValue(ValuePtr, Value);
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return KawaiiPhysics;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
ValueType UKawaiiPhysicsLibrary::GetExternalForceProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName)
|
||||
{
|
||||
ValueType Result;
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("GetExternalForceProperty"),
|
||||
[&Result, &ExecResult, &ExternalForceIndex, &PropertyName](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
if (InKawaiiPhysics.ExternalForces.IsValidIndex(ExternalForceIndex) &&
|
||||
InKawaiiPhysics.ExternalForces[ExternalForceIndex].IsValid())
|
||||
{
|
||||
const auto* ScriptStruct = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetScriptStruct();
|
||||
const auto& Force = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetMutable<
|
||||
FKawaiiPhysics_ExternalForce>();
|
||||
|
||||
if (const FProperty* Property = FindFProperty<FProperty>(ScriptStruct, PropertyName))
|
||||
{
|
||||
Result = *(Property->ContainerPtrToValuePtr<ValueType>(&Force));
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
FKawaiiPhysicsReference UKawaiiPhysicsLibrary::SetExternalForceStructProperty(
|
||||
EKawaiiPhysicsAccessExternalForceResult& ExecResult, const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName, ValueType Value)
|
||||
{
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("SetExternalForceStructProperty"),
|
||||
[&ExecResult, &ExternalForceIndex, &PropertyName, &Value](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
if (InKawaiiPhysics.ExternalForces.IsValidIndex(ExternalForceIndex) &&
|
||||
InKawaiiPhysics.ExternalForces[ExternalForceIndex].IsValid())
|
||||
{
|
||||
const auto* ScriptStruct = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetScriptStruct();
|
||||
auto& Force = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetMutable<
|
||||
FKawaiiPhysics_ExternalForce>();
|
||||
|
||||
if (const FStructProperty* StructProperty = FindFProperty<FStructProperty>(
|
||||
ScriptStruct, PropertyName))
|
||||
{
|
||||
if (StructProperty->Struct == TBaseStructure<ValueType>::Get())
|
||||
{
|
||||
if (void* ValuePtr = StructProperty->ContainerPtrToValuePtr<uint8>(&Force))
|
||||
{
|
||||
StructProperty->CopyCompleteValue(ValuePtr, &Value);
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return KawaiiPhysics;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
ValueType UKawaiiPhysicsLibrary::GetExternalForceStructProperty(EKawaiiPhysicsAccessExternalForceResult& ExecResult,
|
||||
const FKawaiiPhysicsReference& KawaiiPhysics,
|
||||
int ExternalForceIndex, FName PropertyName)
|
||||
{
|
||||
ValueType Result;
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::NotValid;
|
||||
|
||||
KawaiiPhysics.CallAnimNodeFunction<FAnimNode_KawaiiPhysics>(
|
||||
TEXT("GetExternalForceStructProperty"),
|
||||
[&Result, &ExecResult, &ExternalForceIndex, &PropertyName](FAnimNode_KawaiiPhysics& InKawaiiPhysics)
|
||||
{
|
||||
if (InKawaiiPhysics.ExternalForces.IsValidIndex(ExternalForceIndex) &&
|
||||
InKawaiiPhysics.ExternalForces[ExternalForceIndex].IsValid())
|
||||
{
|
||||
const auto* ScriptStruct = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetScriptStruct();
|
||||
const auto& Force = InKawaiiPhysics.ExternalForces[ExternalForceIndex].GetMutable<
|
||||
FKawaiiPhysics_ExternalForce>();
|
||||
|
||||
if (const FStructProperty* StructProperty = FindFProperty<FStructProperty>(
|
||||
ScriptStruct, PropertyName))
|
||||
{
|
||||
if (StructProperty->Struct == TBaseStructure<ValueType>::Get())
|
||||
{
|
||||
Result = *(StructProperty->ContainerPtrToValuePtr<ValueType>(&Force));
|
||||
ExecResult = EKawaiiPhysicsAccessExternalForceResult::Valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Result;
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "Engine/DataAsset.h"
|
||||
#include "Interfaces/Interface_BoneReferenceSkeletonProvider.h"
|
||||
#include "KawaiiPhysicsLimitsDataAsset.generated.h"
|
||||
|
||||
DECLARE_MULTICAST_DELEGATE_OneParam(FOnLimitsChanged, struct FPropertyChangedEvent&);
|
||||
|
||||
// Deprecated
|
||||
USTRUCT()
|
||||
struct FCollisionLimitDataBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FBoneReference DrivingBoneReference;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FName DrivingBoneName;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FVector OffsetLocation = FVector::ZeroVector;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FRotator OffsetRotation = FRotator::ZeroRotator;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FVector Location = FVector::ZeroVector;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FQuat Rotation = FQuat::Identity;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty, IgnoreForMemberInitializationTest))
|
||||
FGuid Guid = FGuid::NewGuid();
|
||||
|
||||
protected:
|
||||
void ConvertBase(FCollisionLimitBase& Limit) const
|
||||
{
|
||||
Limit.DrivingBone.BoneName = DrivingBoneReference.BoneName;
|
||||
Limit.OffsetLocation = OffsetLocation;
|
||||
Limit.OffsetRotation = OffsetRotation;
|
||||
Limit.Location = Location;
|
||||
Limit.Rotation = Rotation;
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
Limit.SourceType = ECollisionSourceType::DataAsset;
|
||||
Limit.Guid = Guid;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
USTRUCT()
|
||||
struct FSphericalLimitData : public FCollisionLimitDataBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
/** Radius of the sphere */
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
float Radius = 5.0f;
|
||||
|
||||
/** Whether to lock bodies inside or outside of the sphere */
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
ESphericalLimitType LimitType = ESphericalLimitType::Outer;
|
||||
|
||||
FSphericalLimit Convert() const
|
||||
{
|
||||
FSphericalLimit Limit;
|
||||
ConvertBase(Limit);
|
||||
Limit.Radius = Radius;
|
||||
Limit.LimitType = LimitType;
|
||||
|
||||
return Limit;
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
USTRUCT()
|
||||
struct FCapsuleLimitData : public FCollisionLimitDataBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
float Radius = 5.0f;
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
float Length = 10.0f;
|
||||
|
||||
FCapsuleLimit Convert() const
|
||||
{
|
||||
FCapsuleLimit Limit;
|
||||
ConvertBase(Limit);
|
||||
Limit.Radius = Radius;
|
||||
Limit.Length = Length;
|
||||
|
||||
return Limit;
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
USTRUCT()
|
||||
struct FBoxLimitData : public FCollisionLimitDataBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FVector Extent = FVector(5.0f, 5.0f, 5.0f);
|
||||
|
||||
FBoxLimit Convert() const
|
||||
{
|
||||
FBoxLimit Limit;
|
||||
ConvertBase(Limit);
|
||||
Limit.Extent = Extent;
|
||||
|
||||
return Limit;
|
||||
}
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
USTRUCT()
|
||||
struct FPlanarLimitData : public FCollisionLimitDataBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
FPlane Plane = FPlane(0, 0, 0, 0);
|
||||
|
||||
FPlanarLimit Convert() const
|
||||
{
|
||||
FPlanarLimit Limit;
|
||||
ConvertBase(Limit);
|
||||
Limit.Plane = Plane;
|
||||
|
||||
return Limit;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(Blueprintable)
|
||||
class KAWAIIPHYSICS_API UKawaiiPhysicsLimitsDataAsset : public UDataAsset, public IBoneReferenceSkeletonProvider
|
||||
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
#if WITH_EDITORONLY_DATA
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton")
|
||||
TObjectPtr<USkeleton> Skeleton;
|
||||
|
||||
// Deprecated
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
TArray<FSphericalLimitData> SphericalLimitsData;
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
TArray<FCapsuleLimitData> CapsuleLimitsData;
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
TArray<FBoxLimitData> BoxLimitsData;
|
||||
UPROPERTY(meta=(DeprecatedProperty))
|
||||
TArray<FPlanarLimitData> PlanarLimitsData;
|
||||
|
||||
#endif
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spherical Limits")
|
||||
TArray<FSphericalLimit> SphericalLimits;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Capsule Limits")
|
||||
TArray<FCapsuleLimit> CapsuleLimits;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Box Limits")
|
||||
TArray<FBoxLimit> BoxLimits;
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Planar Limits")
|
||||
TArray<FPlanarLimit> PlanarLimits;
|
||||
|
||||
// Begin UObject Interface.
|
||||
#if WITH_EDITORONLY_DATA
|
||||
virtual void Serialize(FStructuredArchiveRecord Record) override;
|
||||
#endif
|
||||
virtual void PostLoad() override;
|
||||
// End UObject Interface.
|
||||
|
||||
// IBoneReferenceSkeletonProvider interface
|
||||
virtual USkeleton* GetSkeleton(bool& bInvalidSkeletonIsError, const IPropertyHandle* PropertyHandle) override;
|
||||
|
||||
#if WITH_EDITOR
|
||||
void UpdateLimit(FCollisionLimitBase* Limit);
|
||||
|
||||
FOnLimitsChanged OnLimitsChanged;
|
||||
virtual void PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if WITH_EDITOR
|
||||
void Sync();
|
||||
#endif
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class KawaiiPhysicsEd : ModuleRules
|
||||
{
|
||||
public KawaiiPhysicsEd(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(new[]
|
||||
{
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"InputCore",
|
||||
"KawaiiPhysics",
|
||||
"AnimGraph",
|
||||
"BlueprintGraph",
|
||||
"Persona",
|
||||
"UnrealEd",
|
||||
"AnimGraphRuntime",
|
||||
"Slate",
|
||||
"SlateCore"
|
||||
});
|
||||
|
||||
if(Target.Version.MajorVersion >= 5)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("EditorFramework");
|
||||
if (Target.Version.MinorVersion >= 1)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("AnimationEditMode");
|
||||
}
|
||||
|
||||
// StructUtils plugin has been integrated into the engine starting from 5.5
|
||||
if (Target.Version.MinorVersion <= 4)
|
||||
{
|
||||
PrivateDependencyModuleNames.Add("StructUtils");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,667 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "AnimGraphNode_KawaiiPhysics.h"
|
||||
|
||||
#include "Subsystems/AssetEditorSubsystem.h"
|
||||
#include "AssetToolsModule.h"
|
||||
#include "DetailCategoryBuilder.h"
|
||||
#include "DetailLayoutBuilder.h"
|
||||
#include "DetailWidgetRow.h"
|
||||
#include "KawaiiPhysicsBoneConstraintsDataAsset.h"
|
||||
#include "KawaiiPhysicsLimitsDataAsset.h"
|
||||
#include "Widgets/Input/SButton.h"
|
||||
#include "Framework/Notifications/NotificationManager.h"
|
||||
#include "Selection.h"
|
||||
#include "Widgets/Text/STextBlock.h"
|
||||
#include "Widgets/Notifications/SNotificationList.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "Dialogs/DlgPickAssetPath.h"
|
||||
#include "Kismet2/CompilerResultsLog.h"
|
||||
#include "Widgets/Layout/SUniformGridPanel.h"
|
||||
|
||||
#include UE_INLINE_GENERATED_CPP_BY_NAME(AnimGraphNode_KawaiiPhysics)
|
||||
|
||||
#define LOCTEXT_NAMESPACE "KawaiiPhysics"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
UAnimGraphNode_KawaiiPhysics::UAnimGraphNode_KawaiiPhysics(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer)
|
||||
{
|
||||
}
|
||||
|
||||
FText UAnimGraphNode_KawaiiPhysics::GetControllerDescription() const
|
||||
{
|
||||
return LOCTEXT("Kawaii Physics", "Kawaii Physics");
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
FText UAnimGraphNode_KawaiiPhysics::GetNodeTitle(ENodeTitleType::Type TitleType) const
|
||||
{
|
||||
if ((TitleType == ENodeTitleType::ListView || TitleType == ENodeTitleType::MenuTitle))
|
||||
{
|
||||
return GetControllerDescription();
|
||||
}
|
||||
// @TODO: the bone can be altered in the property editor, so we have to
|
||||
// choose to mark this dirty when that happens for this to properly work
|
||||
//if (!CachedNodeTitles.IsTitleCached(TitleType, this))
|
||||
|
||||
FFormatNamedArguments Args;
|
||||
Args.Add(TEXT("ControllerDescription"), GetControllerDescription());
|
||||
Args.Add(TEXT("RootBoneName"), FText::FromName(Node.RootBone.BoneName));
|
||||
Args.Add(TEXT("Tag"), FText::FromString(Node.KawaiiPhysicsTag.ToString()));
|
||||
|
||||
// FText::Format() is slow, so we cache this to save on performance
|
||||
if (TitleType == ENodeTitleType::ListView || TitleType == ENodeTitleType::MenuTitle)
|
||||
{
|
||||
const FText Title = Node.KawaiiPhysicsTag.IsValid()
|
||||
? FText::Format(
|
||||
LOCTEXT("AnimGraphNode_KawaiiPhysics_ListTitle",
|
||||
"{ControllerDescription} - Root: {RootBoneName} - Tag: {Tag}"), Args)
|
||||
: FText::Format(
|
||||
LOCTEXT("AnimGraphNode_KawaiiPhysics_ListTitle",
|
||||
"{ControllerDescription} - Root: {RootBoneName}"), Args);
|
||||
|
||||
CachedNodeTitles.SetCachedTitle(TitleType, Title, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
const FText Title = Node.KawaiiPhysicsTag.IsValid()
|
||||
? FText::Format(
|
||||
LOCTEXT("AnimGraphNode_KawaiiPhysics_Title",
|
||||
"{ControllerDescription}\nRoot: {RootBoneName}\nTag: {Tag} "), Args)
|
||||
: FText::Format(
|
||||
LOCTEXT("AnimGraphNode_KawaiiPhysics_Title",
|
||||
"{ControllerDescription}\nRoot: {RootBoneName}"), Args);
|
||||
|
||||
CachedNodeTitles.SetCachedTitle(TitleType, Title, this);
|
||||
}
|
||||
return CachedNodeTitles[TitleType];
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
|
||||
{
|
||||
Super::PostEditChangeProperty(PropertyChangedEvent);
|
||||
|
||||
Node.ModifyBones.Empty();
|
||||
ReconstructNode();
|
||||
}
|
||||
|
||||
FEditorModeID UAnimGraphNode_KawaiiPhysics::GetEditorMode() const
|
||||
{
|
||||
return "AnimGraph.SkeletalControl.KawaiiPhysics";
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::ValidateAnimNodePostCompile(FCompilerResultsLog& MessageLog,
|
||||
UAnimBlueprintGeneratedClass* CompiledClass,
|
||||
int32 CompiledNodeIndex)
|
||||
{
|
||||
UAnimGraphNode_SkeletalControlBase::ValidateAnimNodePostCompile(MessageLog, CompiledClass, CompiledNodeIndex);
|
||||
|
||||
Node.RootBone.Initialize(CompiledClass->TargetSkeleton);
|
||||
if (Node.RootBone.BoneIndex >= 0)
|
||||
{
|
||||
if (Node.ExcludeBones.Contains(Node.RootBone))
|
||||
{
|
||||
MessageLog.Warning(TEXT("@@ ExcludeBones should NOT has RootBone."), this);
|
||||
}
|
||||
}
|
||||
// for template ABP
|
||||
else if (CompiledClass->TargetSkeleton)
|
||||
{
|
||||
MessageLog.Warning(TEXT("@@ RootBone is empty."), this);
|
||||
}
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::CopyNodeDataToPreviewNode(FAnimNode_Base* AnimNode)
|
||||
{
|
||||
FAnimNode_KawaiiPhysics* KawaiiPhysics = static_cast<FAnimNode_KawaiiPhysics*>(AnimNode);
|
||||
|
||||
// pushing properties to preview instance, for live editing
|
||||
// Default
|
||||
KawaiiPhysics->RootBone = Node.RootBone;
|
||||
KawaiiPhysics->ExcludeBones = Node.ExcludeBones;
|
||||
KawaiiPhysics->AdditionalRootBones = Node.AdditionalRootBones;
|
||||
KawaiiPhysics->TargetFramerate = Node.TargetFramerate;
|
||||
KawaiiPhysics->OverrideTargetFramerate = Node.OverrideTargetFramerate;
|
||||
|
||||
// Physics Settings
|
||||
KawaiiPhysics->PhysicsSettings = Node.PhysicsSettings;
|
||||
KawaiiPhysics->DampingCurveData = Node.DampingCurveData;
|
||||
KawaiiPhysics->WorldDampingLocationCurveData = Node.WorldDampingLocationCurveData;
|
||||
KawaiiPhysics->WorldDampingRotationCurveData = Node.WorldDampingRotationCurveData;
|
||||
KawaiiPhysics->StiffnessCurveData = Node.StiffnessCurveData;
|
||||
KawaiiPhysics->RadiusCurveData = Node.RadiusCurveData;
|
||||
KawaiiPhysics->LimitAngleCurveData = Node.LimitAngleCurveData;
|
||||
KawaiiPhysics->bUpdatePhysicsSettingsInGame = Node.bUpdatePhysicsSettingsInGame;
|
||||
KawaiiPhysics->PlanarConstraint = Node.PlanarConstraint;
|
||||
KawaiiPhysics->ResetBoneTransformWhenBoneNotFound = Node.ResetBoneTransformWhenBoneNotFound;
|
||||
|
||||
// DummyBone
|
||||
KawaiiPhysics->DummyBoneLength = Node.DummyBoneLength;
|
||||
KawaiiPhysics->BoneForwardAxis = Node.BoneForwardAxis;
|
||||
|
||||
// Limits
|
||||
KawaiiPhysics->SphericalLimits = Node.SphericalLimits;
|
||||
KawaiiPhysics->CapsuleLimits = Node.CapsuleLimits;
|
||||
KawaiiPhysics->BoxLimits = Node.BoxLimits;
|
||||
KawaiiPhysics->PlanarLimits = Node.PlanarLimits;
|
||||
KawaiiPhysics->LimitsDataAsset = Node.LimitsDataAsset;
|
||||
KawaiiPhysics->PhysicsAssetForLimits = Node.PhysicsAssetForLimits;
|
||||
|
||||
// ExternalForce
|
||||
KawaiiPhysics->Gravity = Node.Gravity;
|
||||
KawaiiPhysics->ExternalForces = Node.ExternalForces;
|
||||
KawaiiPhysics->CustomExternalForces = Node.CustomExternalForces;
|
||||
|
||||
// Wind
|
||||
KawaiiPhysics->bEnableWind = Node.bEnableWind;
|
||||
KawaiiPhysics->WindScale = Node.WindScale;
|
||||
|
||||
// BoneConstraint
|
||||
KawaiiPhysics->BoneConstraintGlobalComplianceType = Node.BoneConstraintGlobalComplianceType;
|
||||
KawaiiPhysics->BoneConstraintIterationCountBeforeCollision = Node.BoneConstraintIterationCountBeforeCollision;
|
||||
KawaiiPhysics->BoneConstraintIterationCountAfterCollision = Node.BoneConstraintIterationCountAfterCollision;
|
||||
KawaiiPhysics->bAutoAddChildDummyBoneConstraint = Node.bAutoAddChildDummyBoneConstraint;
|
||||
KawaiiPhysics->BoneConstraints = Node.BoneConstraints;
|
||||
KawaiiPhysics->BoneConstraintsDataAsset = Node.BoneConstraintsDataAsset;
|
||||
|
||||
// SimulationSpace
|
||||
KawaiiPhysics->SimulationSpace = Node.SimulationSpace;
|
||||
KawaiiPhysics->SimulationBaseBone = Node.SimulationBaseBone;
|
||||
|
||||
// Reset for sync without compile
|
||||
KawaiiPhysics->ModifyBones.Empty();
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::CustomizeDetailTools(IDetailLayoutBuilder& DetailBuilder)
|
||||
{
|
||||
IDetailCategoryBuilder& ViewportCategory = DetailBuilder.EditCategory(TEXT("Kawaii Physics Tools"));
|
||||
FDetailWidgetRow& WidgetRow = ViewportCategory.AddCustomRow(LOCTEXT("KawaiiPhysics", "KawaiiPhysicsTools"));
|
||||
|
||||
WidgetRow
|
||||
[
|
||||
SNew(SUniformGridPanel)
|
||||
.SlotPadding(FMargin(2, 0, 2, 0))
|
||||
+ SUniformGridPanel::Slot(0, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->ExportLimitsDataAsset();
|
||||
return FReply::Handled();
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(FText::FromString(TEXT("Export Limits")))
|
||||
]
|
||||
]
|
||||
+ SUniformGridPanel::Slot(1, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->ExportBoneConstraintsDataAsset();
|
||||
return FReply::Handled();
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(FText::FromString(TEXT("Export BoneConstraints")))
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::CustomizeDetailDebugVisualizations(IDetailLayoutBuilder& DetailBuilder)
|
||||
{
|
||||
IDetailCategoryBuilder& ViewportCategory = DetailBuilder.EditCategory(TEXT("Debug Visualization"));
|
||||
FDetailWidgetRow& WidgetRow = ViewportCategory.AddCustomRow(
|
||||
LOCTEXT("ToggleDebugVisualizationButtonRow", "DebugVisualization"));
|
||||
|
||||
WidgetRow
|
||||
[
|
||||
SNew(SUniformGridPanel)
|
||||
.SlotPadding(FMargin(2, 0, 2, 0))
|
||||
// Show/Hide Bones button.
|
||||
+ SUniformGridPanel::Slot(0, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawBone = !this->bEnableDebugDrawBone;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawBone
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowBoneText", "Bone"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide LengthRate button.
|
||||
+ SUniformGridPanel::Slot(1, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugBoneLengthRate = !this->bEnableDebugBoneLengthRate;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugBoneLengthRate
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowLengthRateText", "Length Rate"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide AngleLimit button.
|
||||
+ SUniformGridPanel::Slot(2, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawLimitAngle = !this->bEnableDebugDrawLimitAngle;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawLimitAngle
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowLimitAngleText", "Limit Angle"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide SphereLimit button.
|
||||
+ SUniformGridPanel::Slot(0, 1)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawSphereLimit = !this->bEnableDebugDrawSphereLimit;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawSphereLimit
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowSphereLimitText", "Sphere Limit"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide CapsuleLimit button.
|
||||
+ SUniformGridPanel::Slot(1, 1)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawCapsuleLimit = !this->bEnableDebugDrawCapsuleLimit;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawCapsuleLimit
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowCapsuleLimitText", "Capsule Limit"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide BoxLimit button.
|
||||
+ SUniformGridPanel::Slot(2, 1)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawBoxLimit = !this->bEnableDebugDrawBoxLimit;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawBoxLimit
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowBoxLimitText", "Box Limit"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide PlanerLimit button.
|
||||
+ SUniformGridPanel::Slot(0, 2)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawPlanerLimit = !this->bEnableDebugDrawPlanerLimit;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawPlanerLimit
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowPlanerLimitText", "Planer Limit"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide BoneConstraint button.
|
||||
+ SUniformGridPanel::Slot(1, 2)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawBoneConstraint = !this->bEnableDebugDrawBoneConstraint;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawBoneConstraint
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowBoneConstraintText", "Bone Constraint"); })
|
||||
]
|
||||
]
|
||||
// Show/Hide ExternalForce button.
|
||||
+ SUniformGridPanel::Slot(2, 2)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.VAlign(VAlign_Center)
|
||||
.OnClicked_Lambda([this]()
|
||||
{
|
||||
this->bEnableDebugDrawExternalForce = !this->bEnableDebugDrawExternalForce;
|
||||
return FReply::Handled();
|
||||
})
|
||||
.ButtonColorAndOpacity_Lambda([this]()
|
||||
{
|
||||
return this->bEnableDebugDrawExternalForce
|
||||
? FAppStyle::Get().GetSlateColor("Colors.AccentGreen")
|
||||
: FAppStyle::Get().GetSlateColor("Colors.AccentRed");
|
||||
})
|
||||
.Content()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text_Lambda([this]() { return LOCTEXT("ShowExternalForceText", "External Force"); })
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
||||
{
|
||||
Super::CustomizeDetails(DetailBuilder);
|
||||
|
||||
CustomizeDetailTools(DetailBuilder);
|
||||
CustomizeDetailDebugVisualizations(DetailBuilder);
|
||||
|
||||
// Force order of details panel categories - Must set order for all of them as any that are edited automatically move to the top.
|
||||
auto CategorySorter = [](const TMap<FName, IDetailCategoryBuilder*>& Categories)
|
||||
{
|
||||
int32 Order = 0;
|
||||
auto SafeSetOrder = [&Categories, &Order](const FName& CategoryName)
|
||||
{
|
||||
if (IDetailCategoryBuilder* const* Builder = Categories.Find(CategoryName))
|
||||
{
|
||||
(*Builder)->SetSortOrder(Order++);
|
||||
}
|
||||
};
|
||||
|
||||
// Tools, Debug
|
||||
SafeSetOrder(FName("Kawaii Physics Tools"));
|
||||
SafeSetOrder(FName("Debug Visualization"));
|
||||
SafeSetOrder(FName("Functions"));
|
||||
|
||||
// Basic
|
||||
SafeSetOrder(FName("Bones"));
|
||||
SafeSetOrder(FName("Physics Settings"));
|
||||
SafeSetOrder(FName("Physics Settings Advanced"));
|
||||
|
||||
// Limits
|
||||
SafeSetOrder(FName("Limits"));
|
||||
SafeSetOrder(FName("Bone Constraint (Experimental)"));
|
||||
|
||||
// Other
|
||||
SafeSetOrder(FName("World Collision"));
|
||||
SafeSetOrder(FName("ExternalForce"));
|
||||
|
||||
// AnimNode
|
||||
SafeSetOrder(FName("Tag"));
|
||||
SafeSetOrder(FName("Alpha"));
|
||||
};
|
||||
|
||||
DetailBuilder.SortCategories(CategorySorter);
|
||||
}
|
||||
|
||||
struct FKawaiiPhysicsVersion
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
BeforeCustomVersionWasAdded,
|
||||
UseRuntimeFloatCurve,
|
||||
// -----<new versions can be added above this line>-------------------------------------------------
|
||||
VersionPlusOne,
|
||||
LatestVersion = VersionPlusOne - 1
|
||||
};
|
||||
|
||||
// The GUID for this custom version number
|
||||
const static FGuid GUID;
|
||||
|
||||
private:
|
||||
FKawaiiPhysicsVersion()
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
const FGuid FKawaiiPhysicsVersion::GUID(0x4B2D3E25, 0xCD681D29, 0x2DB298D7, 0xAD3E55FA);
|
||||
|
||||
const FCustomVersionRegistration GRegisterKawaiiPhysCustomVersion(FKawaiiPhysicsVersion::GUID,
|
||||
FKawaiiPhysicsVersion::LatestVersion,
|
||||
TEXT("Kawaii-Phys"));
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::Serialize(FArchive& Ar)
|
||||
{
|
||||
Super::Serialize(Ar);
|
||||
|
||||
Ar.UsingCustomVersion(FKawaiiPhysicsVersion::GUID);
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::CreateExportDataAssetPath(FString& PackageName, const FString& DefaultSuffix) const
|
||||
{
|
||||
FString AssetName;
|
||||
const FString AnimBlueprintPath = GetAnimBlueprint()->GetPackage()->GetName();
|
||||
const FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools");
|
||||
AssetToolsModule.Get().CreateUniqueAssetName(AnimBlueprintPath, DefaultSuffix, PackageName, AssetName);
|
||||
}
|
||||
|
||||
UPackage* UAnimGraphNode_KawaiiPhysics::CreateDataAssetPackage(const FString& DialogTitle, const FString& DefaultSuffix,
|
||||
FString& AssetName) const
|
||||
{
|
||||
FString PackageName;
|
||||
CreateExportDataAssetPath(PackageName, DefaultSuffix);
|
||||
|
||||
const TSharedRef<SDlgPickAssetPath> NewAssetDlg =
|
||||
SNew(SDlgPickAssetPath)
|
||||
.Title(FText::FromString(DialogTitle))
|
||||
.DefaultAssetPath(FText::FromString(PackageName));
|
||||
|
||||
if (NewAssetDlg->ShowModal() == EAppReturnType::Cancel)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const FString PackagePath(NewAssetDlg->GetFullAssetPath().ToString());
|
||||
AssetName = NewAssetDlg->GetAssetName().ToString();
|
||||
|
||||
return CreatePackage(*PackagePath);
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::ShowExportAssetNotification(UObject* NewAsset,
|
||||
FText NotificationText)
|
||||
{
|
||||
FNotificationInfo NotificationInfo(NotificationText);
|
||||
NotificationInfo.ExpireDuration = 5.0f;
|
||||
NotificationInfo.Hyperlink = FSimpleDelegate::CreateLambda([NewAsset]()
|
||||
{
|
||||
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAsset(NewAsset);
|
||||
});
|
||||
NotificationInfo.HyperlinkText = LOCTEXT("OpenCreatedAsset", "Open Created Asset");
|
||||
|
||||
TSharedPtr<SNotificationItem> NotificationItem = FSlateNotificationManager::Get().AddNotification(
|
||||
NotificationInfo);
|
||||
NotificationItem->SetCompletionState(SNotificationItem::CS_Success);
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::ExportLimitsDataAsset()
|
||||
{
|
||||
FString AssetName;
|
||||
UPackage* Package = CreateDataAssetPackage(
|
||||
TEXT("Choose Location for Collision Data Asset"), TEXT("_Collision"), AssetName);
|
||||
if (!Package)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (UKawaiiPhysicsLimitsDataAsset* NewDataAsset =
|
||||
NewObject<UKawaiiPhysicsLimitsDataAsset>(Package, UKawaiiPhysicsLimitsDataAsset::StaticClass(),
|
||||
FName(AssetName), RF_Public | RF_Standalone))
|
||||
{
|
||||
// look for a valid component in the object being debugged,
|
||||
// we might be set to something other than the preview.
|
||||
if (UObject* ObjectBeingDebugged = GetAnimBlueprint()->GetObjectBeingDebugged())
|
||||
{
|
||||
if (const UAnimInstance* InstanceBeingDebugged = Cast<UAnimInstance>(ObjectBeingDebugged))
|
||||
{
|
||||
NewDataAsset->Skeleton = InstanceBeingDebugged->CurrentSkeleton;
|
||||
}
|
||||
}
|
||||
|
||||
// copy data
|
||||
auto CopyLimits = [&](auto& DataLimits, auto& SourceLimits)
|
||||
{
|
||||
DataLimits = SourceLimits;
|
||||
for (auto& DataLimit : DataLimits)
|
||||
{
|
||||
DataLimit.SourceType = ECollisionSourceType::DataAsset;
|
||||
}
|
||||
};
|
||||
CopyLimits(NewDataAsset->SphericalLimits, Node.SphericalLimits);
|
||||
CopyLimits(NewDataAsset->CapsuleLimits, Node.CapsuleLimits);
|
||||
CopyLimits(NewDataAsset->BoxLimits, Node.BoxLimits);
|
||||
CopyLimits(NewDataAsset->PlanarLimits, Node.PlanarLimits);
|
||||
|
||||
// select new asset
|
||||
USelection* SelectionSet = GEditor->GetSelectedObjects();
|
||||
SelectionSet->DeselectAll();
|
||||
SelectionSet->Select(NewDataAsset);
|
||||
|
||||
FAssetRegistryModule::AssetCreated(NewDataAsset);
|
||||
Package->MarkPackageDirty();
|
||||
|
||||
// Add Notification
|
||||
FText NotificationText = FText::Format(
|
||||
LOCTEXT("ExportedLimitsDataAsset", "Exposted Limits Data Asset: {0}"), FText::FromString(AssetName));
|
||||
ShowExportAssetNotification(NewDataAsset, NotificationText);
|
||||
}
|
||||
}
|
||||
|
||||
void UAnimGraphNode_KawaiiPhysics::ExportBoneConstraintsDataAsset()
|
||||
{
|
||||
FString AssetName;
|
||||
UPackage* Package = CreateDataAssetPackage(
|
||||
TEXT("Choose Location for BoneConstraints Data Asset"), TEXT("_BoneConstraint"), AssetName);
|
||||
if (!Package)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (UKawaiiPhysicsBoneConstraintsDataAsset* NewDataAsset =
|
||||
NewObject<UKawaiiPhysicsBoneConstraintsDataAsset>(
|
||||
Package, UKawaiiPhysicsBoneConstraintsDataAsset::StaticClass(),
|
||||
FName(AssetName), RF_Public | RF_Standalone))
|
||||
{
|
||||
// look for a valid component in the object being debugged,
|
||||
// we might be set to something other than the preview.
|
||||
if (UObject* ObjectBeingDebugged = GetAnimBlueprint()->GetObjectBeingDebugged())
|
||||
{
|
||||
if (const UAnimInstance* InstanceBeingDebugged = Cast<UAnimInstance>(ObjectBeingDebugged))
|
||||
{
|
||||
NewDataAsset->PreviewSkeleton = InstanceBeingDebugged->CurrentSkeleton;
|
||||
NewDataAsset->UpdatePreviewBoneList();
|
||||
}
|
||||
}
|
||||
|
||||
// copy data
|
||||
NewDataAsset->BoneConstraintsData.SetNum(Node.BoneConstraints.Num());
|
||||
for (int32 i = 0; i < Node.BoneConstraints.Num(); i++)
|
||||
{
|
||||
NewDataAsset->BoneConstraintsData[i].Update(Node.BoneConstraints[i]);
|
||||
}
|
||||
|
||||
// select new asset
|
||||
USelection* SelectionSet = GEditor->GetSelectedObjects();
|
||||
SelectionSet->DeselectAll();
|
||||
SelectionSet->Select(NewDataAsset);
|
||||
|
||||
FAssetRegistryModule::AssetCreated(NewDataAsset);
|
||||
Package->MarkPackageDirty();
|
||||
|
||||
// Add Notification
|
||||
FText NotificationText = FText::Format(
|
||||
LOCTEXT("ExportedBoneConstraintsDataAsset", "Exposted BoneConstraints Data Asset: {0}"),
|
||||
FText::FromString(AssetName));
|
||||
ShowExportAssetNotification(NewDataAsset, NotificationText);
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
@@ -0,0 +1,27 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#include "KawaiiPhysicsEd.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "Textures/SlateIcon.h"
|
||||
#include "KawaiiPhysicsEditMode.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FKawaiiPhysicsModuleEd"
|
||||
|
||||
|
||||
void FKawaiiPhysicsEdModule::StartupModule()
|
||||
{
|
||||
FEditorModeRegistry::Get().RegisterMode<FKawaiiPhysicsEditMode>("AnimGraph.SkeletalControl.KawaiiPhysics",
|
||||
LOCTEXT("FKawaiiPhysicsEditMode", "Kawaii Physics"),
|
||||
FSlateIcon(), false);
|
||||
}
|
||||
|
||||
|
||||
void FKawaiiPhysicsEdModule::ShutdownModule()
|
||||
{
|
||||
FEditorModeRegistry::Get().UnregisterMode("AnimGraph.SkeletalControl.KawaiiPhysics");
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FKawaiiPhysicsEdModule, KawaiiPhysicsEd)
|
||||
//IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, KawaiiPhysicsEd, "KawaiiPhysicsEd" );
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,106 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnimGraphNode_Base.h"
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
#include "AnimGraphNode_SkeletalControlBase.h"
|
||||
#include "EdGraph/EdGraphNodeUtils.h"
|
||||
|
||||
#include "AnimGraphNode_KawaiiPhysics.generated.h"
|
||||
|
||||
class FCompilerResultsLog;
|
||||
|
||||
UCLASS()
|
||||
class UAnimGraphNode_KawaiiPhysics : public UAnimGraphNode_SkeletalControlBase
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
UPROPERTY(EditAnywhere, Category = Settings)
|
||||
FAnimNode_KawaiiPhysics Node;
|
||||
|
||||
virtual FText GetNodeTitle(ENodeTitleType::Type TitleType) const override;
|
||||
|
||||
// UObject interface
|
||||
virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override;
|
||||
|
||||
protected:
|
||||
// UAnimGraphNode_Base interface
|
||||
virtual FEditorModeID GetEditorMode() const override;
|
||||
virtual void ValidateAnimNodePostCompile(FCompilerResultsLog& MessageLog,
|
||||
UAnimBlueprintGeneratedClass* CompiledClass,
|
||||
int32 CompiledNodeIndex) override;
|
||||
virtual void CopyNodeDataToPreviewNode(FAnimNode_Base* AnimNode) override;
|
||||
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
|
||||
// End of UAnimGraphNode_Base interface
|
||||
|
||||
//virtual FText GetControllerDescription() const override;
|
||||
virtual FText GetControllerDescription() const override;
|
||||
virtual const FAnimNode_SkeletalControlBase* GetNode() const override { return &Node; }
|
||||
// End of UAnimGraphNode_SkeletalControlBase interface
|
||||
|
||||
// UObject interface
|
||||
virtual void Serialize(FArchive& Ar) override;
|
||||
|
||||
// End of UObject interface
|
||||
|
||||
virtual void CustomizeDetailTools(IDetailLayoutBuilder& DetailBuilder);
|
||||
virtual void CustomizeDetailDebugVisualizations(IDetailLayoutBuilder& DetailBuilder);
|
||||
|
||||
private:
|
||||
/** Creates the export data asset path. */
|
||||
void CreateExportDataAssetPath(FString& PackageName, const FString& DefaultSuffix) const;
|
||||
|
||||
/** Creates the data asset package. */
|
||||
UPackage* CreateDataAssetPackage(const FString& DialogTitle, const FString& DefaultSuffix,
|
||||
FString& AssetName) const;
|
||||
|
||||
/** Shows the export asset notification. */
|
||||
void ShowExportAssetNotification(UObject* NewAsset, FText NotificationText);
|
||||
|
||||
/** Exports the limits data asset. */
|
||||
void ExportLimitsDataAsset();
|
||||
|
||||
/** Exports the bone constraints data asset. */
|
||||
void ExportBoneConstraintsDataAsset();
|
||||
|
||||
public:
|
||||
/** Enables or disables debug drawing for bones. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawBone = true;
|
||||
|
||||
/** Enables or disables debug drawing for bone length rate. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugBoneLengthRate = true;
|
||||
|
||||
/** Enables or disables debug drawing for limit angles. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawLimitAngle = true;
|
||||
|
||||
/** Enables or disables debug drawing for spherical limits. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawSphereLimit = true;
|
||||
|
||||
/** Enables or disables debug drawing for capsule limits. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawCapsuleLimit = true;
|
||||
|
||||
/** Enables or disables debug drawing for box limits. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawBoxLimit = true;
|
||||
|
||||
/** Enables or disables debug drawing for planar limits. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawPlanerLimit = true;
|
||||
|
||||
/** Enables or disables debug drawing for bone constraints. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawBoneConstraint = true;
|
||||
|
||||
/** Enables or disables debug drawing for external forces. */
|
||||
UPROPERTY()
|
||||
bool bEnableDebugDrawExternalForce = true;
|
||||
|
||||
private:
|
||||
/** Constructing FText strings can be costly, so we cache the node's title */
|
||||
FNodeTitleTextTable CachedNodeTitles;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
class FKawaiiPhysicsEdModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
// KawaiiPhysics : Copyright (c) 2019-2024 pafuhana1213, MIT License
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "AnimNodeEditMode.h"
|
||||
#include "AnimGraphNode_KawaiiPhysics.h"
|
||||
#include "AnimNode_KawaiiPhysics.h"
|
||||
|
||||
#define UE_WIDGET UE::Widget
|
||||
|
||||
class FEditorViewportClient;
|
||||
class FPrimitiveDrawInterface;
|
||||
class USkeletalMeshComponent;
|
||||
struct FViewportClick;
|
||||
|
||||
class FKawaiiPhysicsEditMode : public FAnimNodeEditMode
|
||||
{
|
||||
public:
|
||||
FKawaiiPhysicsEditMode();
|
||||
|
||||
/** IAnimNodeEditMode interface */
|
||||
virtual void EnterMode(class UAnimGraphNode_Base* InEditorNode, struct FAnimNode_Base* InRuntimeNode) override;
|
||||
virtual void ExitMode() override;
|
||||
virtual FVector GetWidgetLocation() const override;
|
||||
virtual UE_WIDGET::EWidgetMode GetWidgetMode() const override;
|
||||
virtual ECoordSystem GetWidgetCoordinateSystem() const override;
|
||||
virtual void DoTranslation(FVector& InTranslation) override;
|
||||
virtual void DoRotation(FRotator& InRotation) override;
|
||||
virtual void DoScale(FVector& InScale) override;
|
||||
|
||||
/** FEdMode interface */
|
||||
virtual void Render(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI) override;
|
||||
virtual bool HandleClick(FEditorViewportClient* InViewportClient, HHitProxy* HitProxy,
|
||||
const FViewportClick& Click) override;
|
||||
virtual bool GetCustomDrawingCoordinateSystem(FMatrix& InMatrix, void* InData) override;
|
||||
virtual bool InputKey(FEditorViewportClient* InViewportClient, FViewport* InViewport, FKey InKey,
|
||||
EInputEvent InEvent) override;
|
||||
virtual bool ShouldDrawWidget() const override;
|
||||
virtual void DrawHUD(FEditorViewportClient* ViewportClient, FViewport* Viewport, const FSceneView* View,
|
||||
FCanvas* Canvas) override;
|
||||
|
||||
protected:
|
||||
void OnExternalNodePropertyChange(FPropertyChangedEvent& InPropertyEvent);
|
||||
FDelegateHandle NodePropertyDelegateHandle;
|
||||
|
||||
void OnLimitDataAssetPropertyChange(FPropertyChangedEvent& InPropertyEvent);
|
||||
bool IsSelectAnimNodeCollision() const;
|
||||
FDelegateHandle LimitsDataAssetPropertyDelegateHandle;
|
||||
|
||||
private:
|
||||
void RenderModifyBones(FPrimitiveDrawInterface* PDI) const;
|
||||
void RenderLimitAngle(FPrimitiveDrawInterface* PDI) const;
|
||||
|
||||
/** Render each collisions */
|
||||
void RenderSphericalLimits(FPrimitiveDrawInterface* PDI) const;
|
||||
void RenderCapsuleLimit(FPrimitiveDrawInterface* PDI) const;
|
||||
void RenderBoxLimit(FPrimitiveDrawInterface* PDI) const;
|
||||
void RenderPlanerLimit(FPrimitiveDrawInterface* PDI);
|
||||
|
||||
void RenderBoneConstraint(FPrimitiveDrawInterface* PDI) const;
|
||||
void RenderExternalForces(FPrimitiveDrawInterface* PDI) const;
|
||||
|
||||
/** Helper function for GetWidgetLocation() and joint rendering */
|
||||
FVector GetWidgetLocation(ECollisionLimitType CollisionType, int32 Index) const;
|
||||
|
||||
// methods to find a valid widget mode for gizmo because doesn't need to show gizmo when the mode is "Ignore"
|
||||
UE_WIDGET::EWidgetMode FindValidWidgetMode(UE_WIDGET::EWidgetMode InWidgetMode) const;
|
||||
|
||||
/** Checking if a collision is selected and the collision is valid */
|
||||
bool IsValidSelectCollision() const;
|
||||
|
||||
// Get Select Colliison Info
|
||||
FCollisionLimitBase* GetSelectCollisionLimitRuntime() const;
|
||||
FCollisionLimitBase* GetSelectCollisionLimitGraph() const;
|
||||
|
||||
/** Draw text func for DrawHUD */
|
||||
void DrawTextItem(const FText& Text, FCanvas* Canvas, float X, float& Y, float FontHeight);
|
||||
void Draw3DTextItem(const FText& Text, FCanvas* Canvas, const FSceneView* View, const FViewport* Viewport,
|
||||
FVector Location);
|
||||
|
||||
/** Cache the typed nodes */
|
||||
struct FAnimNode_KawaiiPhysics* RuntimeNode;
|
||||
UAnimGraphNode_KawaiiPhysics* GraphNode;
|
||||
|
||||
/** The current bone selection mode */
|
||||
ECollisionLimitType SelectCollisionType = ECollisionLimitType::None;
|
||||
int32 SelectCollisionIndex = -1;
|
||||
ECollisionSourceType SelectCollisionSourceType = ECollisionSourceType::AnimNode;
|
||||
|
||||
// storing current widget mode
|
||||
mutable UE_WIDGET::EWidgetMode CurWidgetMode;
|
||||
|
||||
// physics asset body material
|
||||
TObjectPtr<UMaterialInstanceDynamic> PhysicsAssetBodyMaterial;
|
||||
};
|
||||
Reference in New Issue
Block a user