diff --git a/spine-ue4/Content/Maps/example.umap b/spine-ue4/Content/Maps/example.umap index 0b166ffdb..0ca8fd340 100644 Binary files a/spine-ue4/Content/Maps/example.umap and b/spine-ue4/Content/Maps/example.umap differ diff --git a/spine-ue4/Content/SpineBoy/Spineboy_Blueprint.uasset b/spine-ue4/Content/SpineBoy/Spineboy_Blueprint.uasset index f594e2abf..0cb7d8eda 100644 Binary files a/spine-ue4/Content/SpineBoy/Spineboy_Blueprint.uasset and b/spine-ue4/Content/SpineBoy/Spineboy_Blueprint.uasset differ diff --git a/spine-ue4/Content/Vine/Textures/vine.uasset b/spine-ue4/Content/Vine/Textures/vine.uasset new file mode 100644 index 000000000..6873f971f Binary files /dev/null and b/spine-ue4/Content/Vine/Textures/vine.uasset differ diff --git a/spine-ue4/Content/Vine/Vine_Blueprint.uasset b/spine-ue4/Content/Vine/Vine_Blueprint.uasset new file mode 100644 index 000000000..bd03d1726 Binary files /dev/null and b/spine-ue4/Content/Vine/Vine_Blueprint.uasset differ diff --git a/spine-ue4/Content/Vine/vine.uasset b/spine-ue4/Content/Vine/vine.uasset new file mode 100644 index 000000000..73c52ee86 Binary files /dev/null and b/spine-ue4/Content/Vine/vine.uasset differ diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineBoneFollowerComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineBoneFollowerComponent.cpp new file mode 100644 index 000000000..30136279b --- /dev/null +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineBoneFollowerComponent.cpp @@ -0,0 +1,29 @@ +#include "SpinePluginPrivatePCH.h" + +USpineBoneFollowerComponent::USpineBoneFollowerComponent () { + bWantsBeginPlay = true; + PrimaryComponentTick.bCanEverTick = true; + bTickInEditor = true; + bAutoActivate = true; +} + +void USpineBoneFollowerComponent::BeginPlay () { + Super::BeginPlay(); +} + + +void USpineBoneFollowerComponent::TickComponent ( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) { + Super::TickComponent( DeltaTime, TickType, ThisTickFunction ); + + AActor* owner = GetOwner(); + if (Target && owner) { + USpineSkeletonComponent* skeleton = static_cast(Target->GetComponentByClass(USpineSkeletonComponent::StaticClass())); + if (skeleton) { + FTransform transform = skeleton->GetBoneWorldTransform(BoneName); + if (UsePosition) owner->SetActorLocation(transform.GetLocation()); + if (UseRotation) owner->SetActorRotation(transform.GetRotation()); + if (UseScale) owner->SetActorScale3D(transform.GetScale3D()); + } + } +} + diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePluginPrivatePCH.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePluginPrivatePCH.h index f734fdd9c..0dc9a2be0 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePluginPrivatePCH.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePluginPrivatePCH.h @@ -9,3 +9,4 @@ #include "SpineSkeletonComponent.h" #include "SpineSkeletonAnimationComponent.h" #include "SpineSkeletonRendererComponent.h" +#include "SpineBoneFollowerComponent.h" diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonComponent.cpp index 3fa17f599..9242af4e5 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonComponent.cpp @@ -24,18 +24,19 @@ bool USpineSkeletonComponent::setAttachment (const FString& slotName, const FStr FTransform USpineSkeletonComponent::GetBoneWorldTransform (const FString& BoneName) { CheckState(); if (skeleton) { - spBone* bone = spSkeleton_findBone(skeleton, TCHAR_TO_UTF8(*BoneName)); - if (!bone->appliedValid) this->InternalTick(0); + spBone* bone = spSkeleton_findBone(skeleton, TCHAR_TO_UTF8(*BoneName)); if (!bone) return FTransform(); + if (!bone->appliedValid) this->InternalTick(0); // Need to fetch the renderer component to get world transform of actor plus - // offset by renderer component and its parent component(s). - // FIXME add overloaded method that takes a base world transform? + // offset by renderer component and its parent component(s). If no renderer + // component is found, this components owner's transform is used as a fallback FTransform baseTransform; AActor* owner = GetOwner(); if (owner) { USpineSkeletonRendererComponent* rendererComponent = static_cast(owner->GetComponentByClass(USpineSkeletonRendererComponent::StaticClass())); if (rendererComponent) baseTransform = rendererComponent->GetComponentTransform(); + else baseTransform = owner->GetActorTransform(); } FVector position(bone->worldX, 0, bone->worldY); @@ -53,8 +54,36 @@ FTransform USpineSkeletonComponent::GetBoneWorldTransform (const FString& BoneNa return FTransform(); } -FTransform USpineSkeletonComponent::GetBoneLocalTransform (const FString& BoneName) { - return FTransform(); +void USpineSkeletonComponent::SetBoneWorldPosition (const FString& BoneName, const FVector& position) { + CheckState(); + if (skeleton) { + spBone* bone = spSkeleton_findBone(skeleton, TCHAR_TO_UTF8(*BoneName)); + + // Need to fetch the renderer component to get world transform of actor plus + // offset by renderer component and its parent component(s). If no renderer + // component is found, this components owner's transform is used as a fallback + FTransform baseTransform; + AActor* owner = GetOwner(); + if (owner) { + USpineSkeletonRendererComponent* rendererComponent = static_cast(owner->GetComponentByClass(USpineSkeletonRendererComponent::StaticClass())); + if (rendererComponent) baseTransform = rendererComponent->GetComponentTransform(); + else baseTransform = owner->GetActorTransform(); + } + + baseTransform = baseTransform.Inverse(); + baseTransform.TransformVector(position); + float localX = 0, localY = 0; + spBone_worldToLocal(bone, position.X, position.Z, &localX, &localY); + bone->x = localX; + bone->y = localY; + } +} + +void USpineSkeletonComponent::UpdateWorldTransform() { + CheckState(); + if (skeleton) { + spSkeleton_updateWorldTransform(skeleton); + } } void USpineSkeletonComponent::SetToSetupPose () { @@ -72,6 +101,28 @@ void USpineSkeletonComponent::SetSlotsToSetupPose () { if (skeleton) spSkeleton_setSlotsToSetupPose(skeleton); } +void USpineSkeletonComponent::SetFlipX (bool flipX) { + CheckState(); + if (skeleton) skeleton->flipX = flipX ? 1 : 0; +} + +bool USpineSkeletonComponent::GetFlipX() { + CheckState(); + if (skeleton) return skeleton->flipX != 0; + return false; +} + +void USpineSkeletonComponent::SetFlipY(bool flipY) { + CheckState(); + if (skeleton) skeleton->flipY = flipY ? 1 : 0; +} + +bool USpineSkeletonComponent::GetFlipY() { + CheckState(); + if (skeleton) return skeleton->flipY != 0; + return false; +} + void USpineSkeletonComponent::BeginPlay() { Super::BeginPlay(); } diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineBoneFollowerComponent.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineBoneFollowerComponent.h new file mode 100644 index 000000000..7a54afef6 --- /dev/null +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineBoneFollowerComponent.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Components/ActorComponent.h" +#include "SpineBoneFollowerComponent.generated.h" + + +UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent)) +class SPINEPLUGIN_API USpineBoneFollowerComponent : public UActorComponent { + GENERATED_BODY() + +public: + UPROPERTY(EditAnywhere, BlueprintReadWrite) + AActor* Target = 0; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + FString BoneName; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool UsePosition = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool UseRotation = true; + + UPROPERTY(EditAnywhere, BlueprintReadWrite) + bool UseScale = true; + + USpineBoneFollowerComponent (); + + virtual void BeginPlay () override; + + virtual void TickComponent (float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; +}; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonComponent.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonComponent.h index 2a20fb93e..5448d38cd 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonComponent.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpineSkeletonComponent.h @@ -35,16 +35,31 @@ public: FTransform GetBoneWorldTransform (const FString& BoneName); UFUNCTION(BlueprintCallable, Category = "Components|Spine") - FTransform GetBoneLocalTransform (const FString& BoneName); + void SetBoneWorldPosition (const FString& BoneName, const FVector& position); UFUNCTION(BlueprintCallable, Category = "Components|Spine") void SetToSetupPose (); UFUNCTION(BlueprintCallable, Category = "Components|Spine") void SetBonesToSetupPose (); + + UFUNCTION(BlueprintCallable, Category = "Components|Spine") + void UpdateWorldTransform (); UFUNCTION(BlueprintCallable, Category = "Components|Spine") void SetSlotsToSetupPose (); + + UFUNCTION(BlueprintCallable, Category = "Components|Spine") + void SetFlipX(bool flipX); + + UFUNCTION(BlueprintCallable, Category = "Components|Spine") + bool GetFlipX(); + + UFUNCTION(BlueprintCallable, Category = "Components|Spine") + void SetFlipY(bool flipY); + + UFUNCTION(BlueprintCallable, Category = "Components|Spine") + bool GetFlipY(); UPROPERTY(BlueprintAssignable, Category = "Components|Spine") FSpineBeforeUpdateWorldTransformDelegate BeforeUpdateWorldTransform;