Adjusting aim direction to crosshair position

The problem is in concept very simple.
I have and Crosshair. By default is drawed exactly in center of the screen.
I moved crosshair 50 pixels to the bottom.

Now is the tricky part. How to make trace, so it will end exactly at the crosshair position ?

So far I have been using this:

FVector Origin = GetCastingLocation();
const FVector ShootDir = GetCameraAim();
const FVector StartTrace = GetCameraDamageStarLocation(ShootDir);// - AdjustVec;
//const FVector StartTrace = Origin;

const FVector WeapRange = FVector(10000.0f, 10000.0f, 10000.0f);
const FVector EndTrace = (StartTrace + ShootDir * WeapRange);//- AdjustVec * 1.0f;
FHitResult Impact = AbilityTrace(StartTrace, EndTrace);
DrawDebugLine(Instigator->GetWorld(), StartTrace, EndTrace, FColor::Black, true, 10.0f, 0.0f, 1.0f);
if(Impact.GetActor())
{

	
	//0-1 range
	const FVector AdjustedDir = (Impact.ImpactPoint - Origin).SafeNormal();
	DrawDebugLine(Instigator->GetWorld(), Origin, Impact.ImpactPoint, FColor::Red, true, 10.0f, 0.0f, 1.0f);
     }



FVector ARPGAbility::GetCastingLocation()
{
	USkeletalMeshComponent* UseMesh = GetWeaponMesh();
	return UseMesh->GetSocketLocation("WeaponPoint");
}


FVector ARPGAbility::GetCameraDamageStarLocation(const FVector& AimDir) const
{
	ARPGPlayerController* PC = (MyPawn != NULL) ? Cast(MyPawn->Controller) : NULL;
	FVector OutStartTrace = FVector::ZeroVector;

	if(PC)
	{
		FRotator UnusedRot;
		PC->GetPlayerViewPoint(OutStartTrace, UnusedRot);
		OutStartTrace = OutStartTrace + AimDir * ((Instigator->GetActorLocation() - OutStartTrace) | AimDir);
	}
	return OutStartTrace;
}

It’s more or less the code from shooter example. It works perfectly fine if I leave crosshair in center of the screen. But adjusting vectors so they will end up exactly at new crosshair position proved to be far more tricky than I first thought.

If anyone have any idea or direction, where I should start looking to solve it it would be very much appreciated.

If anyone wonder “Why the hell this guy want to move crosshair to random spot on screen, instead of leaving in center”. The answer is that by default my TPP camera is, quite high (as in comparison to other TPP games at least), and while for now it’s doing it’s job it’s not that accurate on closer distances.

Dear Lukasz,

I am more than happy to assist and have implemented a move-the-crosshair-anywhere system in my game so I do think I can help

but from your code I’m not getting some things

  1. what is your crosshair and where is it’s position determined, and where is the crosshair drawn
  2. what is the Damage Star?

FVector ARPGAbility::GetCameraDamageStarLocation(const FVector& AimDir) const

Could you show the code in HUD or wherever for where and when exactly your crosshair itself as a material or Tile is being drawn.

:slight_smile:

Code for HUD is actually very basic at this point:

void ARPGHUD::DrawHUD()
{
	Super::DrawHUD();

	// find center of the screen/Canvas
	const FVector2D Center(Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f);

	const FVector2D CrosshairDrawPosition(Center.X - (CrosshairTex->GetSurfaceWidth()*0.5f), (Center.Y - (CrosshairTex->GetSurfaceHeight()*0.5f) + 50.0f ));

	FCanvasTileItem TileItem (CrosshairDrawPosition, CrosshairTex->Resource, FLinearColor::White);
	TileItem.BlendMode = SE_BLEND_Translucent;
	Canvas->DrawItem(TileItem);
}
  1. Damage Star ? You mean Start ? Hm, this currently do not do any damage, only draw debug lines. This one DebugDraw that is really important:

    DrawDebugLine(Instigator->GetWorld(), Origin, Impact.ImpactPoint, FColor::Red, true, 10.0f, 0.0f, 1.0f);

As it is drawed from actual weapon position to impact point.

Ahhh, your HUD code was what I needed

I’ve written you new code for your HUD to store a global variable which is the 3D space deprojected position of your crosshair at any given time, moved out into 3D space your chosen distance (I default to 20000)

I explain the rest in the code.

My reasoning:

if you wanted to move your crosshair around a lot, or even manually aim with the crosshair, you will need it’s 3d space deprojected position.

But deproject comes from canvas, which is only valid in DrawHUD

so you must do the calcs in HUD

and store global variable for rest of game code to access whenever they want it

the data itself is updated every tick in DrawHUD

ARPGHUD.h

//public so can be accessed by playercontroller / character
public:
	
//global so can be accessed outside of drawHUD,
//		if ever you wanted to know where the cross hair was, elsewhere in game code
FVector2D CrossHairCenter;

//3D Position of cross hair as if aiming at AIM_DISTANCE ahead
FVector	CrossHair3DPos;

protected:  //should only call from drawHUD as it uses canvas
void Get3DCrossHairPos();

//.cpp

#define AIM_DISTANCE 20000

void ARPGHUD::Get3DCrossHairPos()
{
	//Always Check Pointers
	if (!Canvas) return;
	
	FVector WorldDirectionOfCrossHair2D; 
	Canvas->Deproject(CrossHairCenter, CrossHair3DPos, WorldDirectionOfCrossHair2D);
	
	//moves the cursor pos into full 3D, your chosen distance ahead of player
	CrossHair3DPos += WorldDirectionOfCrossHair2D * AIM_DISTANCE;
}

void ARPGHUD::DrawHUD()
{
    Super::DrawHUD();

    // find center of the screen/Canvas
    const FVector2D Center(Canvas->ClipX * 0.5f, Canvas->ClipY * 0.5f);

	//Center of Cross Hair
	CrossHairCenter = Center;
	CrossHairCenter.Y += 50;
	
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	//Get and Store the 3D position of Crosshair
	//		done here since must use Deproject, from Canvas,
	//		and Canvas only valid inside DrawHUD.
	
	//	The value is stored globally each tick for use with rest of game code.
	Get3DCrossHairPos();
	//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	
	if (CrosshairTex && Canvas)
	{
		FVector2D CrosshairDrawStart(CrossHairCenter);
		CrosshairDrawStart.X -= CrosshairTex->GetSurfaceWidth() * 0.5f;
		CrosshairDrawStart.Y -= CrosshairTex->GetSurfaceHeight() * 0.5f;
		
		FCanvasTileItem TileItem (CrosshairDrawPosition, CrosshairTex->Resource, FLinearColor::White);
		TileItem.BlendMode = SE_BLEND_Translucent;
		Canvas->DrawItem(TileItem);
	}
}


//in player controller you can now obtain the 3D position of the cross hair from HUD class, 
//getting deprojected value OUTSIDE of drawhud / canvas validity loop
ARPGHUD* RPGHUD = Cast(GetHUD());
if(!RPGHUD) return;

//now aim your trace end point at this
RPGHUD->CrossHair3DPos


//from a Character directly:
	
//I store global references to things like the HUD and the PC so it does not look this weird
ARPGHUD * RPGHUD = 	Cast < ARPGHUD > (Cast < APlayerController > (GetController())->GetHUD());
if(!RPGHUD) return;

//now aim your trace end point at this
RPGHUD->CrossHair3DPos

:slight_smile:

#If This Answers Your Question

If this resolves your issue please checkmark this post so others know this solved the issue for you

Thanks. It’s working!
It’s still bit inaccurate, but now at least I’m aware of something like reprojection, that I had no idea existed :D.