
Just quickly popping in here, to let people know that using GetOverlappingActors in BeginPlay may not be reliable. Let’s have a quick look at the behaviour I have observed and how to get around it.
Engine Version: Unreal Engine 5.4.4
Setup
I have a basic actor class and call GetOverlappingActors in BeginPlay. Afterwards actors or a specific class get added to a array.
void APJCustomActor::BeginPlay()
{
Super::BeginPlay();
TArray<AActor*> AlreadyOverlappingActors;
GetOverlappingActors(AlreadyOverlappingActors);
for (AActor* ItemActor : AlreadyOverlappingActors)
{
if (APJBaseItem* OverlappingItem = Cast<APJBaseItem>(ItemActor))
{
AllTrackedItems.Add(OverlappingItem);
}
}
}
The same class also tracks Begin and End Overlap Events.
void APJCustomActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
if (APJBaseItem* OverlappingItem = Cast<APJBaseItem>(OtherActor))
{
AllTrackedItems.Add(OverlappingItem);
}
}
void APJCustomActor::NotifyActorEndOverlap(AActor* OtherActor)
{
Super::NotifyActorEndOverlap(OtherActor);
if (APJBaseItem* OverlappingItem = Cast<APJBaseItem>(OtherActor))
{
if (AllTrackedItems.Contains(OverlappingItem))
{
AllTrackedItems.Remove(OverlappingItem);
}
}
}
Also all actors in question have the correct collision settings and GenerateOverlapEvents ticked.
Behaviour
Now, the problem is that the array of actors this function returns is not always fully populated by the time BeginPlay is called. It seems to be an order of execution/timing issue, so sometimes it might work, and sometimes it does not.
Especially in Play in Editor, it might work more often than in a packaged and cooked build—causing a potentially nasty surprise the next time you package your game and run it.
It’s important to mention that the actors do not trigger the Begin Overlap Event after they have been missed in the Begin Play call.
Possible Fixes
Fix A
What might be the problem is that overlap events are not generated during level streaming. To determine if that is the issue and to get around it, simply enable ‘GenerateOverlapEventSDuringLevelStreaming‘ on your affected actors.

Fix B
The easiest and quickest way to get around this, without any engine changes, is to move the initial gathering of overlapping actors into the first tick call of the actor.
Simply add a bool flag to your class (e.g. bHasBeenInitialized), to make sure you only do this once, and then check for it in tick.
void APJCustomActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (!bIsInitalised)
{
bIsInitalised = true;
TArray<AActor*> AlreadyOverlappingActors;
GetOverlappingActors(AlreadyOverlappingActors);
for (AActor* ItemActor : AlreadyOverlappingActors)
{
if (APJBaseItem* OverlappingItem = Cast<APJBaseItem>(ItemActor))
{
AllTrackedItems.Add(OverlappingItem);
}
}
}
}
Make sure your actors can tick by having it enabled in the constructor and also ensuring the Blueprint does not disable it.
APJCustomActor::APJCustomActor()
{
PrimaryActorTick.bCanEverTick = true;
}

Now, you might not want this actor to tick, to save on some performance, for example, but still need to get overlapping actors (as it is the case for my use case). What you can do is turn off the ability to tick once you have gathered your actors.
You can achieve this behavior easily by calling PrimaryActorTick.SetTickFunctionEnabled(false) after the first tick that gathers the overlapping actors.
void APJCustomActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
if (!bIsInitalised)
{
bIsInitalised = true;
TArray<AActor*> AlreadyOverlappingActors;
GetOverlappingActors(AlreadyOverlappingActors);
for (AActor* ItemActor : AlreadyOverlappingActors)
{
if (APJBaseItem* OverlappingItem = Cast<APJBaseItem>(ItemActor))
{
AllTrackedItems.Add(OverlappingItem);
}
}
PrimaryActorTick.SetTickFunctionEnable(false);
}
}
I hope this is helpful to anyone out there, and good luck with your game project.☺️

Leave a comment. (Email and Name are not required to be filled in)