Creating Proximity Trigger and UI Widget
AZCInteractable
Actor representing items in the world that can be picked up but could be extended to anything that can be interacted with (pickup items, environment prompts, effect activations...etc).
Keeps track of when actors enter or exit range (based off a proximity trigger).
Has a UWidgetComponent who's visibility is turned on or off
Proximity Trigger
Define a USphereComponent and set collision to only notify on Overlap
.h
// ZCInteractable.h
// Proximity trigger to allow interaction (widget popup) or not
UPROPERTY(EditAnywhere, BlueprintReadOnly++)
class USphereComponent* ProximityTrigger = nullptr;
.cpp
// ZCInteractable.cpp
AZCInteractable::AZCInteractable()
{
//...
ProximityTrigger = CreateDefaultSubobject<USphereComponent>(TEXT("ProximityTrigger"));
ProximityTrigger->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
ProximityTrigger->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
//...
}
Bind to Overlap events
Bind custom UFUNCTION()s to the USphereComponent OnComponentBeginOverlap and OnComponentEndOverlap event delegates
.h
// ZCInteractable.h
UFUNCTION()
void OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
NOTE: Ensure the functions are marked as UFUNCTION() otherwise they will not allow binding to the dynamic delegates
.cpp
// ZCInteractable.cpp
AZCInteractable::BeginPlay()
{
//...
ProximityTrigger->OnComponentBeginOverlap.AddDynamic(this, &AcInteractable::OnBeginOverlap);
ProximityTrigger->OnComponentEndOverlap.AddDynamic(this, &AInteractable::OnEndOverlap);
//...
}
Notify objects entering/exiting proximity
Inform the actor entering or exiting that they are doing so by accessing their InteractableManagerComponent
.cpp
// ZCInteractable.cpp
void AInteractable::OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
if (OtherActor)
{
// Only actors with this component need to care about being in range or not
UZCInteractableManager* InteractManager = Char->FindComponentByClass<UZCInteractableManager>();
if (InteractManager)
{
InteractManager->ItemEnteredRange(this);
}
}
}
void AInteractable::OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
if (OtherActor)
{
// Only actors with this component need to care about being in range or not
UZCInteractableManager* InteractManager = Char->FindComponentByClass<UZCInteractableManager>();
if (InteractManager)
{
InteractManager->ItemExitedRange(this);
}
}
}
Widget Popup
Define a UWidgetComponent and create public visibility setter
.h
// ZCInteractable.h
// UI Widget that shows the player when they are within range of and looking at
UPROPERTY(EditAnywhere, BlueprintReadOnly)
class UWidgetComponent* PopupWidget = nullptr;
.cpp
// ZCInteractable.cpp
AZCInteractable::AZCInteractable()
{
//...
PopupWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("PopupWidget"));
PopupWidget->SetupAttachment(GetRootComponent());
//...
}
Visibility Toggle
Need to provide a way for external sources to tell us to turn 'on' or 'off'
.h
// ZCInteractable.h
public:
// Toggles the popup visibility
void SetPopupVisibility(bool bVisible);
.cpp
// ZCInteractable.cpp
void AZCInteractable::SetPopupVisibility(bool bVisible)
{
if (PopupWidget)
{
PopupWidget->SetVisibility(bVisible);
}
}
Blueprint Implementation
Create a Blueprint class using ZCInteractableItem as the base. Make sure to expand the All Classes dropdown to type for our custom class

Assign custom Widget Blueprint class and specify the draw dimensions.
Note: Draw Size is specifying dimensions for the widget on the screen, not world size

Last updated