Character class spawns multiple actors with different behavior

This has me baffled. I had this working in blueprints but decided I wanted this core structure in C++, but I’m experiencing some very weird behavior. Basic principal is this: I have a Character class called SuspectCharacter (that will not be human controlled) that has a basic skeletal mesh. In the editor, I added two sockets: LeftEyeSocket and RightEyeSocket. I have another class called DynamicEye that contains some code in the overridden Tick function to calculate a rotation to look at the human character’s head, so the eyes always look at the player 0 as he/she runs around. In my SuspectCharacter class, I create two DynamicEyes and attach them to the LeftEyeSocket and RightEyeSocket. Here is my code:

Not sure if they DynamicEye code is important, but here it is for reference:

ADynamicEye::ADynamicEye(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	this->SetActorTickEnabled(true);
	PrimaryActorTick.bCanEverTick = true;

	SceneComponent = PCIP.CreateDefaultSubobject<USceneComponent>(this, TEXT("SceneComp"));
	RootComponent = SceneComponent;

	MeshComponent = PCIP.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("MeshComp"));
	MeshComponent->AttachParent = RootComponent;
	
	static ConstructorHelpers::FObjectFinder<UStaticMesh> EyeMesh(TEXT("StaticMesh'/Game/Eye/cone.Cone'"));
	
	MeshComponent->SetStaticMesh(EyeMesh.Object);
	MeshComponent->SetRelativeScale3D(FVector(2.0f, 2.0f, 2.0f));
}

void ADynamicEye::Tick(float DeltaSeconds) {
	Super::Tick(DeltaSeconds);

		// Get the location of the human player's head
		const FVector HeadLocation = Cast<AFPSCharacter>(UGameplayStatics::GetPlayerPawn(this, 0))->Mesh->GetBoneLocation("head");
		
		// Get the location of this eye instance
		FVector EyeLocation = MeshComponent->GetComponentLocation();

		// Calculate the difference in the two vectors
		FVector Forward = (HeadLocation - EyeLocation);

		// Make rotation matrix from x-axis.  this means the Y and Z axis will rotate around X
		FRotator EyeRotation = FRotationMatrix::MakeFromX(Forward).Rotator();
		
		// Rotate this eye relative to the socket it's in
		MeshComponent->SetRelativeRotation(EyeRotation, true);
}

And here is my SuspectCharacter class:

ASuspectCharacter::ASuspectCharacter(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	static ConstructorHelpers::FObjectFinder<USkeletalMesh> SkelMeshOb_AW1(TEXT("SkeletalMesh'/Game/GenericMale.GenericMale'"));
	Mesh->SetSkeletalMesh(SkelMeshOb_AW1.Object);
	Mesh->SetRelativeTransform(FTransform(FVector(0, 0, -90.0f)));
	
	UWorld* const World = GetWorld();
	if (World) {
		FActorSpawnParameters SpawnParams;
		SpawnParams.Owner = this;
		SpawnParams.Instigator = Instigator;
		RightEye = World->SpawnActor<ADynamicEye>(Mesh->GetSocketLocation("RightEyeSocket"), FRotator::ZeroRotator, SpawnParams);
		LeftEye = World->SpawnActor<ADynamicEye>(Mesh->GetSocketLocation("LeftEyeSocket"), FRotator::ZeroRotator, SpawnParams);
		LeftEye->AttachRootComponentTo(Mesh, "LeftEyeSocket", EAttachLocation::SnapToTarget);
		RightEye->AttachRootComponentTo(Mesh, "RightEyeSocket", EAttachLocation::SnapToTarget);
	}
}

In the editor, I create a blueprint of SuspectCharacter called “BP_SuspectCharacter2”. When I drag a copy of it into my level, it instantly (before I release the mouse) spawns two eyes near the origin of the level. Once I start playing, two more eyes are spawned on my character’s eye sockets (Note, I’m not an artist at all, so for now I just created a cone in Maya that lays on it’s side… the normal of the bottom flat part of the code is what should be following the player).

So here’s the odd part. The eyes that spawned behave exactly as I want. As I move around the level, they track my head everywhere I go. The eyes that spawn on the SuspectCharacter start pointing straight up, then move around, but they don’t track me at all.

12685-ue+debugging.jpg

One of the floating eyes that tracks me properly is clipping through the floor, so you can only see one. It took me quite a while to even find these guys spawning under my level! Anyway, when I delete my SuspectCharacter in the level, it leaves behind the eyes and I have to remove them manually from the Scene Outliner.

I tried moving the code that spawns the DynamicEyes out of the SuspectCharacter’s constructor and into an overridden BeginPlay function, but all that does is destroy the free-floating eyes that work properly and keep the ones in the socket locations that don’t.

I FEEL like the proper place to really have this is BeginPlay and not in the constructor. Also, when they eyes get instantiated in BeginPlay, they automatically get deleted when I delete The SuspectCharacter. It’s almost like the socket is rotating the entire coordinate system of my DynamicEye. Can anybody please offer me some help?

Well, of course I spend hours and hours on this and the minute after I post the question, I get it working. It seems that the socket itself does have a rotation, and my code to control they eye sets the relative location instead of the world rotation.

I just changed the last line in DynamicEye to:

MeshComponent->SetWorldRotation(EyeRotation, true);

Can you control the rotation at which a socket attaches to a bone? Or is it completely based on the orientation of the bone? Is my solution the right solution – the socket could be oriented in a different vector, so just use world rotation?