No way to ignore specific actor instances in "Get Hit Result Under Cursor"?

Pretty much what the title says. Alternatively I’m interested in some pointers on the way on how to manually build an equivalent function that allows for actor exclusion.

Basically I have set up my player in the style of certain MMOs that allow both direct movement inputs and automatic movement via NavMesh via a proxy, and shows the player in a third person view. The simplified version:

  • Player Controller does not possess anything but spawns the following: An AI Controller and a Character (these are cached as variables in Player Controller).
  • AI Controller possesses Character.
  • If the player presses any of the WASD-keys the Player Controller triggers events in the Character directly that uses the “Add Movement Input” nodes.
  • If the player clicks anywhere in the game world with the left mouse button the Player Controller it triggers events in the AI Controller that uses “Move to Location”/“Move to Actor” nodes.

This all works fine except for one thing… the last point; if you click an area of the screen that is occupied by the player character, the trace from the “Get Hit Result Under Cursor by Channel” will hit the player’s Character and end there. Unfortunately, changing the collision settings will cause further problems, as the same Character blueprint will be used for other players which it does indeed need to collide with. I can fake an invalid result by checking what actor it hits, but the trace won’t go through the character.

Am I missing something or is there no way to control excluded actors from the “Get Hit Result Under Cursor” functions? I see that the regular trace functions (like “Line Trace by Channel”) does indeed allow for exclusion, but I’d have to figure a way to manually do the trace in the correct way from the mouse cursor. Any tips on how to get this done correctly? I’m not sure how to get and convert the mouse location into a world location to get the start of the trace. As for the end of the trace I would assume I have to get the forward vector of the active camera, multiply by desired trace length and add this to the start location for the trace, am I right? Other than that, since this trace is performed by the Player Controller (which isn’t actually in direct possession of the Character), Ignore Self is essentially useless, so I’d have to add a reference to the player’s Character to the Actors to Ignore array. Am I missing anything else at that point?


Also, still need input on a different issue not entirely sure about this topic as well: Possible to tick custom events (or “inject” them into tick)?

I’m sure this is a long shot 5 years later, I have ran into the same issue… did you ever find a work around ?

1 Like

A c++ solution as function library. I copied and extended the original APlayerController::GetHitResultUnderCursorByChannel implementation.

Header

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "ControllerHelperLibrary.generated.h"

UCLASS()
class PROJECT_API UControllerHelperLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

	/** Performs a collision query under the mouse cursor, looking on a trace channel. With optional actors to ignore. */
	UFUNCTION(BlueprintCallable, BlueprintPure, Category="Game|Player", meta=(bTraceComplex=true))
	static bool GetHitResultUnderCursorByChannelAdvanced(const APlayerController* PlayerController, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, FHitResult& HitResult);
};

Implementation

#include "ControllerHelperLibrary.h"

bool UControllerHelperLibrary::GetHitResultUnderCursorByChannelAdvanced(const APlayerController* PlayerController, ETraceTypeQuery TraceChannel, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, FHitResult& HitResult)
{
	ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player);
	bool bHit = false;
	if (LocalPlayer && LocalPlayer->ViewportClient)
	{
		FVector2D MousePosition;
		if (LocalPlayer->ViewportClient->GetMousePosition(MousePosition))
		{
			FCollisionQueryParams Params = FCollisionQueryParams();
			Params.bTraceComplex = bTraceComplex;
			Params.AddIgnoredActors(ActorsToIgnore);
			bHit = PlayerController->GetHitResultAtScreenPosition(MousePosition, UEngineTypes::ConvertToCollisionChannel(TraceChannel), Params, HitResult);
		}
	}

	if(!bHit)	//If there was no hit we reset the results. This is redundant but helps Blueprint users
	{
		HitResult = FHitResult();
	}

	return bHit;
}