ComponentBeginOverlap called twice in UE4.9

I have a simple inventory system using the Overlap event in C++. Walking over an item gives a copy to the player, and the original item disables its collision and goes to sleep. This worked as expected in 4.8

After upgrading the 4.9, the Overlap event was getting fired twice upon walking over the item. The stack trace, all parameters (OtherActor, OtherComponent, OtherBodyIndex, bFromSweep, and SweepResult) and this were all identical in both calls, so it’s not a matter of two different components belonging to the same actor overlapping. This happens despite the overlap event disabling collision.

I added a simple fix by checking to see if collision is enabled, and aborting the event execution if not. This does solve the problem, but it’s odd that the event is triggered twice all of a sudden.

Was this a deliberate change in behavior, or indeed a bug in the new release?

Hey -

How are you setting you your overlap function in code? I tried to reproduce this with a simple actor where I setup the constructor:

MyScene = CreateDefaultSubobject<USceneComponent>(TEXT("MyScene"));
	MyMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MyMesh"));
	MySphere = CreateDefaultSubobject<USphereComponent>(TEXT("MySphere"));

	RootComponent = MyScene;
	MyMesh->AttachTo(MyScene);
	MySphere->AttachTo(MyMesh);
	MyMesh->bGenerateOverlapEvents = true;
	MySphere->bGenerateOverlapEvents = true;

And overrode the NotifyActorBeginOverlap function:

void AMyActor::NotifyActorBeginOverlap(AActor* OtherActor)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Magenta, TEXT("Hello"));
	}
	Super::NotifyActorBeginOverlap(OtherActor);
}

In both 4.8.3 and 4.9 walking into the sphere component only printed “Hello” once.

Let me know if your setup looks different or if this setup gives you the result you’re looking for.

Cheers

I’m using OnComponentBeginOverlap. I believe I had trouble getting NotifyActorBeginOverlap to work at all when I first started.

The colliding component is “pickupViewMesh”:

pickupViewMesh = ObjectInitializer.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("InventoryPickupMesh"));
pickupViewMesh->OnComponentBeginOverlap.AddDynamic(this, &AInventory::OnOverlapBegin);

Then the overlap function:

void AInventory::OnOverlapBegin(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	bool col = pickupViewMesh->IsCollisionEnabled();

	//This is the condition put in to prevent the 2nd call. A breakpoint is set here, which shows 'col' as true the first time, false the second.
	if (!col)
		return;

	//Macro for printing to the screen. The class name was being printed twice.
	MSG(GetClass()->GetName());

	//GiveTo .....

	//This function will disable the collision
	TriggerRespawn();
}

Collision is disabled as a result of TriggerRespawn() as follows:

    	pickupViewMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
    	pickupViewMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);

This is completed by the time the 2nd overlap event is trigger, so I don’t think it’s any kind of threading issue.

Hey -

I changed the end of my constructor and added a function to match your setup as such:

//added at the end of the constructor
MySphere->OnComponentBeginOverlap.AddDynamic(this, &AMyActor::CallOnOverlap);

}

void AMyActor::CallOnOverlap(class AActor* OtherActor, class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	if (GEngine)
	{
		GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT("NotHello"));
	}
}

With this setup it printed my message to the screen once in 4.8 as well as after upgrading the project to 4.9. If you are seeing your message print twice then it seems your dynamic function call is being made twice. Could you post the code class where this method is being used or send a copy of your project to test directly?

What’s a good way to send a copy of my project? I do have a git repo, but I’m not 100% positive it’s set up correctly, since I’m the only user.

If you upload the project to dropbox you can send me a private message on the forums with a link to download the project.

Hey -

Looking through the code it seems that OnOverlapBegin() calls TriggerResapwn(). TriggerRespawn() then makes a call to BecomeHidden(). Adding a return just before the call to BecomeHidden() caused the OnOverlapBegin to only trigger once. Putting a return after BecomeHidden() caused the double call effect to occur. You may want to look into how BecomeHidden() behaves to find why the OnOverlapBegin() is being called twice.

Cheers

I’ve looked into it. First, I copied BecomeHidden() into a new, identical function so I could modify the call from TriggerRespawn() and not any other source.

Currently, I have these three lines:

pickupViewMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
pickupViewMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
pickupViewMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);

Commenting out all 3 of these and no other changes is enough to remove the extra OnOverlapBegin call. Leaving one or more uncommented triggers the extra call.

In other words, disabling collision is triggering a collision response. This certainly seems like a bug, and it was not happening in 4.8.

Hey -

I was able to confirm that setting collision to No Collision inside an overlap event cases the overlap to trigger twice. I have entered a bug report (UE-20848) to investigate this behavior.

Cheers