Skip to content

Added new option on the widget infos of the interactable component to use an instanced object to get the scene component #394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 );
Expand All @@ -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() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 )
Expand Down
Original file line number Diff line number Diff line change
@@ -1,117 +1,132 @@
#include "UI/IndicatorSystem/GBFIndicatorDescriptor.h"

#include "Interaction/GBFInteractionOption.h"
#include "UI/IndicatorSystem/GBFIndicatorManagerComponent.h"

#include <Engine/LocalPlayer.h>
#include <SceneView.h>

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;
}
}

Expand Down
13 changes: 13 additions & 0 deletions Source/GameBaseFramework/Public/Interaction/GBFInteractionOption.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "GBFIndicatorDescriptor.generated.h"

class UGBFInteractionWidgetComponentSelector;
class UMVVMViewModelBase;
class SWidget;
class UGBFIndicatorDescriptor;
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -281,6 +306,9 @@ class GAMEBASEFRAMEWORK_API UGBFIndicatorDescriptor : public UObject
UPROPERTY()
TObjectPtr< UObject > DataObject;

UPROPERTY()
TObjectPtr< AActor > Instigator;

UPROPERTY()
TObjectPtr< UMVVMViewModelBase > ViewModel;

Expand All @@ -293,6 +321,9 @@ class GAMEBASEFRAMEWORK_API UGBFIndicatorDescriptor : public UObject
UPROPERTY()
TSoftClassPtr< UUserWidget > IndicatorWidgetClass;

UPROPERTY()
TObjectPtr< UGBFInteractionWidgetComponentSelector > ComponentSelector;

UPROPERTY()
TWeakObjectPtr< UGBFIndicatorManagerComponent > ManagerPtr;

Expand Down
Loading