diff --git a/Source/GameBaseFramework/Private/Interaction/Abilities/GBFGameplayAbility_Interact.cpp b/Source/GameBaseFramework/Private/Interaction/Abilities/GBFGameplayAbility_Interact.cpp index df4c6651..792937b2 100644 --- a/Source/GameBaseFramework/Private/Interaction/Abilities/GBFGameplayAbility_Interact.cpp +++ b/Source/GameBaseFramework/Private/Interaction/Abilities/GBFGameplayAbility_Interact.cpp @@ -204,6 +204,7 @@ void UGBFGameplayAbility_Interact::UpdateIndicators() auto * interactable_target_actor = interactable_component->GetOwner(); auto * indicator = NewObject< UGBFIndicatorDescriptor >(); + indicator->SetInstigator( GetAvatarActorFromActorInfo() ); indicator->SetDataObject( interactable_target_actor ); indicator->SetSceneComponent( interactable_target_actor->GetRootComponent() ); indicator->SetComponentSocketName( widget_infos.SocketName ); @@ -212,6 +213,7 @@ void UGBFGameplayAbility_Interact::UpdateIndicators() indicator->SetScreenSpaceOffset( widget_infos.InteractionWidgetOffset ); indicator->SetProjectionMode( widget_infos.ProjectionMode ); indicator->SetBoundingBoxAnchor( widget_infos.BoundingBoxAnchor ); + indicator->SetSceneComponentSelector( widget_infos.WidgetComponentSelector ); TArray< FGBFInteractionOption > interaction_options; interaction_options.Reserve( options.Num() ); diff --git a/Source/GameBaseFramework/Private/Interaction/GBFInteractionOption.cpp b/Source/GameBaseFramework/Private/Interaction/GBFInteractionOption.cpp index 50018e6f..b2215d13 100644 --- a/Source/GameBaseFramework/Private/Interaction/GBFInteractionOption.cpp +++ b/Source/GameBaseFramework/Private/Interaction/GBFInteractionOption.cpp @@ -2,7 +2,13 @@ #include "DVEDataValidator.h" +USceneComponent * UGBFInteractionWidgetComponentSelector::GetSceneComponent_Implementation( const UGBFIndicatorDescriptor * ) const +{ + return nullptr; +} + #if WITH_EDITOR + EDataValidationResult FGBFInteractionWidgetInfos::IsDataValid( FDataValidationContext & context ) const { return FDVEDataValidator( context ) diff --git a/Source/GameBaseFramework/Private/UI/IndicatorSystem/GBFIndicatorDescriptor.cpp b/Source/GameBaseFramework/Private/UI/IndicatorSystem/GBFIndicatorDescriptor.cpp index 6fe5bf5f..18de735a 100644 --- a/Source/GameBaseFramework/Private/UI/IndicatorSystem/GBFIndicatorDescriptor.cpp +++ b/Source/GameBaseFramework/Private/UI/IndicatorSystem/GBFIndicatorDescriptor.cpp @@ -1,5 +1,6 @@ #include "UI/IndicatorSystem/GBFIndicatorDescriptor.h" +#include "Interaction/GBFInteractionOption.h" #include "UI/IndicatorSystem/GBFIndicatorManagerComponent.h" #include @@ -7,111 +8,125 @@ bool FGBFIndicatorProjection::Project( const UGBFIndicatorDescriptor & indicator_descriptor, const FSceneViewProjectionData & projection_data, const FVector2f & screen_size, FVector & out_screen_position_with_depth ) { - if ( auto component = indicator_descriptor.GetSceneComponent() ) + USceneComponent * component = nullptr; + + if ( auto * component_selector = indicator_descriptor.GetSceneComponentSelector() ) { - TOptional< FVector > world_location; - if ( indicator_descriptor.GetComponentSocketName() != NAME_None ) - { - world_location = component->GetSocketLocation( indicator_descriptor.GetComponentSocketName() ); - } - else - { - world_location = component->GetComponentLocation(); - } + component = component_selector->GetSceneComponent( &indicator_descriptor ); + } + + if ( component == nullptr ) + { + component = indicator_descriptor.GetSceneComponent(); + } + + if ( component == nullptr ) + { + return false; + } + + TOptional< FVector > world_location; + if ( indicator_descriptor.GetComponentSocketName() != NAME_None ) + { + world_location = component->GetSocketLocation( indicator_descriptor.GetComponentSocketName() ); + } + else + { + world_location = component->GetComponentLocation(); + } - const auto project_world_location = world_location.GetValue() + indicator_descriptor.GetWorldPositionOffset(); + const auto project_world_location = world_location.GetValue() + indicator_descriptor.GetWorldPositionOffset(); - switch ( const auto projection_mode = indicator_descriptor.GetProjectionMode() ) + switch ( const auto projection_mode = indicator_descriptor.GetProjectionMode() ) + { + case EGBFActorCanvasProjectionMode::ComponentPoint: { - case EGBFActorCanvasProjectionMode::ComponentPoint: + if ( world_location.IsSet() ) { - if ( world_location.IsSet() ) - { - FVector2D out_screen_space_position; - const auto in_front_of_camera = ULocalPlayer::GetPixelPoint( projection_data, project_world_location, out_screen_space_position, &screen_size ); + FVector2D out_screen_space_position; + const auto in_front_of_camera = ULocalPlayer::GetPixelPoint( projection_data, project_world_location, out_screen_space_position, &screen_size ); - out_screen_space_position.X += indicator_descriptor.GetScreenSpaceOffset().X * ( in_front_of_camera ? 1 : -1 ); - out_screen_space_position.Y += indicator_descriptor.GetScreenSpaceOffset().Y; + out_screen_space_position.X += indicator_descriptor.GetScreenSpaceOffset().X * ( in_front_of_camera ? 1 : -1 ); + out_screen_space_position.Y += indicator_descriptor.GetScreenSpaceOffset().Y; - if ( !in_front_of_camera && FBox2f( FVector2f::Zero(), screen_size ).IsInside( static_cast< FVector2f >( out_screen_space_position ) ) ) - { - const auto center_to_position = ( FVector2f( out_screen_space_position ) - ( screen_size / 2 ) ).GetSafeNormal(); - out_screen_space_position = FVector2D( ( screen_size / 2 ) + center_to_position * screen_size ); - } + if ( !in_front_of_camera && FBox2f( FVector2f::Zero(), screen_size ).IsInside( static_cast< FVector2f >( out_screen_space_position ) ) ) + { + const auto center_to_position = ( FVector2f( out_screen_space_position ) - ( screen_size / 2 ) ).GetSafeNormal(); + out_screen_space_position = FVector2D( ( screen_size / 2 ) + center_to_position * screen_size ); + } - out_screen_position_with_depth = FVector( out_screen_space_position.X, out_screen_space_position.Y, FVector::Dist( projection_data.ViewOrigin, project_world_location ) ); + out_screen_position_with_depth = FVector( out_screen_space_position.X, out_screen_space_position.Y, FVector::Dist( projection_data.ViewOrigin, project_world_location ) ); - return true; - } + return true; + } - return false; + return false; + } + case EGBFActorCanvasProjectionMode::ComponentScreenBoundingBox: + case EGBFActorCanvasProjectionMode::ActorScreenBoundingBox: + { + FBox indicator_box; + if ( projection_mode == EGBFActorCanvasProjectionMode::ActorScreenBoundingBox ) + { + indicator_box = component->GetOwner()->GetComponentsBoundingBox(); } - case EGBFActorCanvasProjectionMode::ComponentScreenBoundingBox: - case EGBFActorCanvasProjectionMode::ActorScreenBoundingBox: + else { - FBox indicator_box; - if ( projection_mode == EGBFActorCanvasProjectionMode::ActorScreenBoundingBox ) - { - indicator_box = component->GetOwner()->GetComponentsBoundingBox(); - } - else - { - indicator_box = component->Bounds.GetBox(); - } + indicator_box = component->Bounds.GetBox(); + } - FVector2D ll, ur; - const auto in_front_of_camera = ULocalPlayer::GetPixelBoundingBox( projection_data, indicator_box, ll, ur, &screen_size ); + FVector2D ll, ur; + const auto in_front_of_camera = ULocalPlayer::GetPixelBoundingBox( projection_data, indicator_box, ll, ur, &screen_size ); - const auto & bounding_box_anchor = indicator_descriptor.GetBoundingBoxAnchor(); - const auto & screen_space_offset = indicator_descriptor.GetScreenSpaceOffset(); + const auto & bounding_box_anchor = indicator_descriptor.GetBoundingBoxAnchor(); + const auto & screen_space_offset = indicator_descriptor.GetScreenSpaceOffset(); - FVector screen_position_with_depth; - screen_position_with_depth.X = FMath::Lerp( ll.X, ur.X, bounding_box_anchor.X ) + screen_space_offset.X * ( in_front_of_camera ? 1 : -1 ); - screen_position_with_depth.Y = FMath::Lerp( ll.Y, ur.Y, bounding_box_anchor.Y ) + screen_space_offset.Y; - screen_position_with_depth.Z = FVector::Dist( projection_data.ViewOrigin, project_world_location ); + FVector screen_position_with_depth; + screen_position_with_depth.X = FMath::Lerp( ll.X, ur.X, bounding_box_anchor.X ) + screen_space_offset.X * ( in_front_of_camera ? 1 : -1 ); + screen_position_with_depth.Y = FMath::Lerp( ll.Y, ur.Y, bounding_box_anchor.Y ) + screen_space_offset.Y; + screen_position_with_depth.Z = FVector::Dist( projection_data.ViewOrigin, project_world_location ); - const auto screen_space_position = FVector2f( FVector2D( screen_position_with_depth ) ); - if ( !in_front_of_camera && FBox2f( FVector2f::Zero(), screen_size ).IsInside( screen_space_position ) ) - { - const auto center_to_position = ( screen_space_position - ( screen_size / 2 ) ).GetSafeNormal(); - const auto screen_position_from_behind = ( screen_size / 2 ) + center_to_position * screen_size; - screen_position_with_depth.X = screen_position_from_behind.X; - screen_position_with_depth.Y = screen_position_from_behind.Y; - } + const auto screen_space_position = FVector2f( FVector2D( screen_position_with_depth ) ); + if ( !in_front_of_camera && FBox2f( FVector2f::Zero(), screen_size ).IsInside( screen_space_position ) ) + { + const auto center_to_position = ( screen_space_position - ( screen_size / 2 ) ).GetSafeNormal(); + const auto screen_position_from_behind = ( screen_size / 2 ) + center_to_position * screen_size; + screen_position_with_depth.X = screen_position_from_behind.X; + screen_position_with_depth.Y = screen_position_from_behind.Y; + } - out_screen_position_with_depth = screen_position_with_depth; - return true; + out_screen_position_with_depth = screen_position_with_depth; + return true; + } + case EGBFActorCanvasProjectionMode::ActorBoundingBox: + case EGBFActorCanvasProjectionMode::ComponentBoundingBox: + { + FBox indicator_box; + if ( projection_mode == EGBFActorCanvasProjectionMode::ActorBoundingBox ) + { + indicator_box = component->GetOwner()->GetComponentsBoundingBox(); } - case EGBFActorCanvasProjectionMode::ActorBoundingBox: - case EGBFActorCanvasProjectionMode::ComponentBoundingBox: + else { - FBox indicator_box; - if ( projection_mode == EGBFActorCanvasProjectionMode::ActorBoundingBox ) - { - indicator_box = component->GetOwner()->GetComponentsBoundingBox(); - } - else - { - indicator_box = component->Bounds.GetBox(); - } + indicator_box = component->Bounds.GetBox(); + } - const auto project_box_point = indicator_box.GetCenter() + ( indicator_box.GetSize() * ( indicator_descriptor.GetBoundingBoxAnchor() - FVector( 0.5 ) ) ); + const auto project_box_point = indicator_box.GetCenter() + ( indicator_box.GetSize() * ( indicator_descriptor.GetBoundingBoxAnchor() - FVector( 0.5 ) ) ); - FVector2D out_screen_space_position; - const auto in_front_of_camera = ULocalPlayer::GetPixelPoint( projection_data, project_box_point, out_screen_space_position, &screen_size ); - out_screen_space_position.X += indicator_descriptor.GetScreenSpaceOffset().X * ( in_front_of_camera ? 1 : -1 ); - out_screen_space_position.Y += indicator_descriptor.GetScreenSpaceOffset().Y; + FVector2D out_screen_space_position; + const auto in_front_of_camera = ULocalPlayer::GetPixelPoint( projection_data, project_box_point, out_screen_space_position, &screen_size ); + out_screen_space_position.X += indicator_descriptor.GetScreenSpaceOffset().X * ( in_front_of_camera ? 1 : -1 ); + out_screen_space_position.Y += indicator_descriptor.GetScreenSpaceOffset().Y; - if ( !in_front_of_camera && FBox2f( FVector2f::Zero(), screen_size ).IsInside( static_cast< FVector2f >( out_screen_space_position ) ) ) - { - const auto center_to_position = ( FVector2f( out_screen_space_position ) - ( screen_size / 2 ) ).GetSafeNormal(); - out_screen_space_position = FVector2D( ( screen_size / 2 ) + center_to_position * screen_size ); - } + if ( !in_front_of_camera && FBox2f( FVector2f::Zero(), screen_size ).IsInside( static_cast< FVector2f >( out_screen_space_position ) ) ) + { + const auto center_to_position = ( FVector2f( out_screen_space_position ) - ( screen_size / 2 ) ).GetSafeNormal(); + out_screen_space_position = FVector2D( ( screen_size / 2 ) + center_to_position * screen_size ); + } - out_screen_position_with_depth = FVector( out_screen_space_position.X, out_screen_space_position.Y, FVector::Dist( projection_data.ViewOrigin, project_box_point ) ); + out_screen_position_with_depth = FVector( out_screen_space_position.X, out_screen_space_position.Y, FVector::Dist( projection_data.ViewOrigin, project_box_point ) ); - return true; - } + return true; } } diff --git a/Source/GameBaseFramework/Public/Interaction/GBFInteractionOption.h b/Source/GameBaseFramework/Public/Interaction/GBFInteractionOption.h index 89bae3ad..0419935e 100644 --- a/Source/GameBaseFramework/Public/Interaction/GBFInteractionOption.h +++ b/Source/GameBaseFramework/Public/Interaction/GBFInteractionOption.h @@ -14,6 +14,16 @@ class UUserWidget; class UAbilitySystemComponent; class IGBFInteractableTarget; +UCLASS( Abstract, Blueprintable, DefaultToInstanced, EditInlineNew ) +class GAMEBASEFRAMEWORK_API UGBFInteractionWidgetComponentSelector : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION( BlueprintNativeEvent ) + USceneComponent * GetSceneComponent( const UGBFIndicatorDescriptor * indicator_description ) const; +}; + USTRUCT( BlueprintType ) struct FGBFInteractionWidgetInfos { @@ -42,6 +52,9 @@ struct FGBFInteractionWidgetInfos UPROPERTY( EditDefaultsOnly, BlueprintReadWrite ) FName SocketName; + UPROPERTY( EditDefaultsOnly, Instanced, meta = ( EditCondition = "ProjectionMode == EGBFActorCanvasProjectionMode::ComponentPoint || ProjectionMode == EGBFActorCanvasProjectionMode::ComponentBoundingBox || ProjectionMode == EGBFActorCanvasProjectionMode::ComponentScreenBoundingBox" ) ) + TObjectPtr< UGBFInteractionWidgetComponentSelector > WidgetComponentSelector; + bool operator==( const FGBFInteractionWidgetInfos & other ) const; }; diff --git a/Source/GameBaseFramework/Public/UI/IndicatorSystem/GBFIndicatorDescriptor.h b/Source/GameBaseFramework/Public/UI/IndicatorSystem/GBFIndicatorDescriptor.h index c665fccf..195fbf42 100644 --- a/Source/GameBaseFramework/Public/UI/IndicatorSystem/GBFIndicatorDescriptor.h +++ b/Source/GameBaseFramework/Public/UI/IndicatorSystem/GBFIndicatorDescriptor.h @@ -5,6 +5,7 @@ #include "GBFIndicatorDescriptor.generated.h" +class UGBFInteractionWidgetComponentSelector; class UMVVMViewModelBase; class SWidget; class UGBFIndicatorDescriptor; @@ -52,6 +53,18 @@ class GAMEBASEFRAMEWORK_API UGBFIndicatorDescriptor : public UObject DataObject = data_object; } + UFUNCTION( BlueprintCallable ) + AActor * GetInstigator() const + { + return Instigator; + } + + UFUNCTION( BlueprintCallable ) + void SetInstigator( AActor * instigator ) + { + Instigator = instigator; + } + UFUNCTION( BlueprintCallable ) UMVVMViewModelBase * GetViewModel() const { @@ -225,6 +238,18 @@ class GAMEBASEFRAMEWORK_API UGBFIndicatorDescriptor : public UObject BoundingBoxAnchor = bounding_box_anchor; } + UFUNCTION( BlueprintCallable ) + void SetSceneComponentSelector( UGBFInteractionWidgetComponentSelector * selector ) + { + ComponentSelector = selector; + } + + UFUNCTION( BlueprintPure ) + UGBFInteractionWidgetComponentSelector * GetSceneComponentSelector() const + { + return ComponentSelector; + } + UFUNCTION( BlueprintCallable ) int32 GetPriority() const { @@ -281,6 +306,9 @@ class GAMEBASEFRAMEWORK_API UGBFIndicatorDescriptor : public UObject UPROPERTY() TObjectPtr< UObject > DataObject; + UPROPERTY() + TObjectPtr< AActor > Instigator; + UPROPERTY() TObjectPtr< UMVVMViewModelBase > ViewModel; @@ -293,6 +321,9 @@ class GAMEBASEFRAMEWORK_API UGBFIndicatorDescriptor : public UObject UPROPERTY() TSoftClassPtr< UUserWidget > IndicatorWidgetClass; + UPROPERTY() + TObjectPtr< UGBFInteractionWidgetComponentSelector > ComponentSelector; + UPROPERTY() TWeakObjectPtr< UGBFIndicatorManagerComponent > ManagerPtr;