PlayerController -> SceneComponent -> Trying to select something

I’ve created a custom C++ PlayerController. On that player controller, I attach a custom C++ USceneComponent (although not customized yet). I attach the USceneComponent to the PlayerController in the latter’s constructor thusly:

	SelectorComponent = CreateDefaultSubobject<USelector>("Player 1 Selector");
	if (SelectorComponent)
		SelectorComponent->SetupAttachment(GetRootComponent(), FName(TEXT("Selecty Bit")));

… having read the documentation, this should default to the attachment in the relative mode. Later, I’m trying to select another SceneComponent and to understand that, I’ve pulled some of the debut code out of the engine … which, at the bottom, runs DrawDebugCapsule().

Now… I could detail the arguments for that, but they’re based on calls to GetComponentLocation(), GetComponentRotation() and a float added to those for the far end.

When I test this, it seems that the DrawDebugCapsule() is stuck with where the PlayerController spawnned (where it was when I hit the Unreal “Start” button) and not the current position of the camera it affords.

Questions:

Do I need to just take the relative location of the camera (boom) ?

Does the player controller move, or is my attachment wrong?

Isn’t the PlayerController an Actor? I’ve seen examples of this type of attachment on an Actor or Character (also an Actor), but I don’t want any of the Character behaviour.

Do I need another Actor in addition to the PlayerController for this purpose?

To clarify, the “player” is etherial here — no body, no hands, etc. They are controlling items (thus the need to select). The camera movement I’ve gotten from the PlayerController by itself is excellent (almost identical to, say, subnautica … wasd + c (down) and (up) + mouse look when buttons pressed. Perfect. Now just need to select an move pieces. I feel like I’m close.

The player controller does not move. More specifically, it only changes rotation, never location. This is likely the source of your problem.

Try to get the location from the player controller’s ViewTarget actor and see if it works as you expect.

Thank-you. Very helpful. PlayerController is very large and I hadn’t found or tried ViewTarget yet.

Coding this up in the constructor, tho, seems a no-go. ViewTarget does not yet exist (null) and thus I can’t take the GetRootComponent() of the ViewTarget.

Now… I’m going to assume that I can do this from within BeginPlay(). I assume that also means that I should be using the AttachToComponent(). The only concern I have for the group is that dynamically adding components is said (somewhere in the documentation I read) to have lower performance.

If you want to do yourself a favor, do not ever use the C++ constructor for any code that goes beyond initializing default components and properties. Anything that needs to be setup while the game is already running, BeginPlay and OnConstruction are better candidates for that.

Also, don’t assume you have a valid view target on BeginPlay. Use the proper functions for that, specifically APlayerController::SetViewTarget, which gets called whenever the PC’s view target changes. Override that function for custom behavior.

With regards to performance, how many times per second do you plan on attaching a component? If the answer is anything below 1, this is not the place to worry about performance.

Rgr-that on the attaching component performance, thanks.

So… at least right now, for testing, GetViewTarget() returns a valid AActor*. If I attach to the GetRootComponent() of that (need a component), my test drawing moves around (yay)… but doesn’t rotate. To be clear now, I have code like this:

In Begin Play:

auto const MyViewComponent = GetViewTarget()->GetRootComponent();
FAttachmentTransformRules const AttachRule(EAttachmentRule::KeepRelative, false);
SelectorComponent->AttachToComponent(MyViewComponent, AttachRule, NAME_None);

And the debug draw does:
MyDrawDebugSphere(World, GetSelectorLocation(), GetMaxSelectionDistance(), 10.0, FColor::Green, true, 100.0, 100);

and my little helper functions are:

FVector ATablePlayerController::GetMaxSelectionDistance() const
{
	return SelectorComponent->GetComponentLocation() + SelectorComponent->GetComponentRotation().Vector() + MaxSelectionDistance;
}

FVector ATablePlayerController::GetSelectorLocation() const
{
	return SelectorComponent->GetComponentLocation() + SelectorComponent->GetComponentRotation().Vector();
}

static void MyDrawDebugSphere(const UWorld* InWorld, FVector const& Start, FVector const& End, float Radius, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority)
{
	FVector const TraceVec = End - Start;
	float const Dist = TraceVec.Size();
	FVector const Center = Start + TraceVec * 0.5f;
	float const HalfHeight = (Dist * 0.5f) + 10.0;
	FQuat const CapsuleRot = FRotationMatrix::MakeFromZ(TraceVec).ToQuat();

	::DrawDebugCapsule(InWorld, Center, HalfHeight, Radius, CapsuleRot, Color, bPersistentLines, LifeTime, DepthPriority);
}