AttachRootComponentTo doesn't work properly

I’m making a hockey game and I want to attach the puck to a player when a trigger attached to the player overlaps with the puck. I have it set up to respond to the OnOverlapBegin event, which seems to be working, but the attachment code… seems like it should work, but doesn’t, quite.

I set up the callback for OnOverlapBegin here (stickZone is just a sphere collision component set up as a trigger that only interacts with the puck):

void APlayer::BeginPlay()
{
	Super::BeginPlay();
	
	stickZone->OnComponentBeginOverlap.AddDynamic(this, &APlayer::onBeginOverlap);
}

And here is the actual callback:

void APlayer::onBeginOverlap(AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult &SweepResult)
{
	if (OtherActor->IsA<APuck>())
	{
		if (OtherActor->GetAttachParentActor() == nullptr)
		{
			UStaticMeshComponent* otherActorStaticMeshComponent = Cast<UStaticMeshComponent>(OtherActor->GetComponentByClass(UStaticMeshComponent::StaticClass()));
			if (otherActorStaticMeshComponent != nullptr)
			{
				otherActorStaticMeshComponent->SetSimulatePhysics(false);
				OtherActor->AttachRootComponentTo(GetRootComponent(), TEXT("puckSocket"), EAttachLocation::SnapToTarget, true);
			}
		}
	}
}

What actually happens is that it runs through the callback, seemingly without error, and in the World Outliner, the Puck becomes a child of the Player that ran over the puck, but the puck doesn’t move with the Player. That is, until I click on the Puck in the World Outliner. Then it decides it is actually attached and starts following the Player at whatever offset it was at when I clicked it in the Outliner. I’m obviously confused why this doesn’t work properly and baffled why clicking the Puck in the Outliner should change anything, so any help would be appreciated.

I figured it out. I moved the attach code to the Puck, but in the way it’s written above, you’d want to use otherActorStaticMeshComponent->AttachTo() instead of OtherActor->AttachRootComponentTo(), then find and pass the Player’s SkeletalMeshComponent as the first argument to AttachTo().

There’s some weird behavior if OtherActor (the Puck) has a SceneComponent as the RootComponent, though.

  1. If you attach the root SceneComponent, the child StaticMeshComponent doesn’t behave as if it is attached until you click on it in the WorldOutliner, and even then it won’t be attached to the socket you want it on.
  2. If you attach the child StaticMeshComponent, the mesh itself will be where it should and it follows the Player properly, but the Actor doesn’t appear as a child of the Player in the World Outliner and the SceneComponent stays where ever it was when your attach code executed.
  3. If you attach both the SceneComponent and the StaticMeshComponent, then they both follow the Player, but what is the point of having a parent/child system if you have to treat them as entirely separate objects?

I didn’t need the SceneComponent, so I got rid of it and everything works fine for now, but this doesn’t feel like it is working the way you would expect it to.

Wow, I have been fighting with trying to attach a simple ‘weapon’ to a character socket for days now. Even today in 4.19, this attaching method is still the same. I had the weapon as a child to the Scene. I originally didn’t want the scene, but I was unable to adjust the transformation of the weapon without it seemed, so that was the only reason why I added it. Sure enough, as soon as I made the static-mesh the Parent of the BP, attaching method finally worked as expected.

I’m really baffled as to why this hasn’t been something brought up many time long before? Unless there is some documentation regarding the scene component and attaching child objects we’re not aware of…