How can i shoot at the center of my crosshair? C++

Hey! So, i’m getting in a little trouble in my shooting system. I did the Unreal tutorial (crosshair) to add a crosshair in the center of the screen. But when i’m shooting, is not going at the center. I know thats because have a difference between my weapon muzzle and my center of the camera. How can i setup that? so far, i have 2 line traces that i use for shooting (as usual).

const FVector AimDir = WeaponMesh->GetSocketRotation("MF").Vector();
	const FVector StartTrace = WeaponMesh->GetSocketLocation("MF");
	const FVector ShootDir = AimDir;
	const FVector EndTrace = StartTrace + ShootDir * WeaponConfig.WeaponRange;
	const FHitResult Impact = WeaponTrace(StartTrace, EndTrace);
	const FRotator AimRot = WeaponMesh->GetSocketRotation("MF");
	const FVector EndPoint = Impact.GetActor() ? Impact.ImpactPoint : EndTrace;

	FActorSpawnParameters SpawnParams;
	SpawnParams.Owner = this;
	
	UWorld* World = GetWorld();

	AWeaponBullet* Projectile = World->SpawnActor<AWeaponBullet>(ProjectileClass, StartTrace, AimRot, SpawnParams);

How can i move my crosshair to my impact point? (I don’t want change my shoot direction D:)

I’m not sure exactly how you want it to work, but if you don’t want to change your shooting direction, you will have to constantly do a trace in your aim direction (this will get complicated if your projectile has gravity applied) until you find a hit, then reproject that world location back to the screen, get the 2D coordinates and draw your crosshair at that location. Be aware that your crosshair will jump around on the screen as you’re effectively introducing a depth parameter. You can have a look at GameplayStatics::ProjectWorldToScreen(…).

Update: Here’s some code.

void APWNCharacter::TestShoot()
{
	// Declare some required params
	const float traceDistance = 5000.f;
	const bool drawDebugLine = true;
	const float calibarionDistance = 3000.f;
	const float projectileSpeed = 4000.f;

	// Get ViewRotation & Viewpoint	
	// I don't know what your setup is but I'm using a custom camera. You require the current world rotation of the active camera. You could try "Cast<APlayerController>(Controller)->PlayerCameraManager->GetCameraRotation().Vector()"
	FVector viewDir = Camera->GetComponentRotation().Vector();
	viewDir.Normalize();
	// I don't know what your setup is. I'm using a custom camera, but you require the center of the screen's world location. You could try "Cast<APlayerController>(Controller)->PlayerCameraManager->GetCameraLocation();"
	FVector traceStart = Camera->GetComponentLocation();
	FVector traceEnd = traceStart + viewDir * traceDistance;
		
	// Set up trace params
	FCollisionQueryParams RV_TraceParams = FCollisionQueryParams(FName(TEXT("RV_Trace")), true, this);
	RV_TraceParams.bTraceComplex = true;
	RV_TraceParams.bTraceAsyncScene = true;
	RV_TraceParams.bReturnPhysicalMaterial = false;
	RV_TraceParams.AddIgnoredActor(this->GetUniqueID());

	//Re-initialize hit info
	FHitResult RV_Hit(ForceInit);

	// Trace from center of screen in direction of aim
	GetWorld()->LineTraceSingleByChannel(
		RV_Hit,        //result
		traceStart,    //start
		traceEnd, //end
		ECC_Visibility, //collision channel
		RV_TraceParams
	);

	// Requires include: #include "Runtime/Engine/Public/DrawDebugHelpers.h"
	if (drawDebugLine)
		DrawDebugLine(GetWorld(), traceStart, traceEnd, FColor::Green, true);

	// Get the muzzle location
	FVector muzzleLoc = CurrentWeapon->WeaponMesh->GetSocketLocation("MF");

	// The required direction of the projectile
	FVector locationToSendProjectileTo;

	// If we've hit something with the trace, let's send the projectile there.
	if (RV_Hit.bBlockingHit)
	{
		locationToSendProjectileTo = RV_Hit.ImpactPoint;
	}
	// Otherwise we use a "calibration distance". The distance from us at which the bullet should intersect the crosshair line
	else 
	{
		locationToSendProjectileTo = traceStart + viewDir * calibarionDistance;
	}

	// Calculate bullet velocity
	FVector bulletVelocity = locationToSendProjectileTo - muzzleLoc;
	bulletVelocity.Normalize();
	bulletVelocity *= projectileSpeed;

	// Draw debug line to show where bullet will go
	if (drawDebugLine)
		DrawDebugLine(GetWorld(), muzzleLoc, locationToSendProjectileTo, FColor::Red, true);

	// Spawn projectile at muzzle location and set its velocity...	
        ....
}

Just need to be like that

Yeap, have gravity but the player have to handle this himself, i just need that my projectile (at least on the first seconds, before start losing altitude) goes on the center of the crosshair. I have made one using traces, but on traces, you can set the End.

Ok - I think what’s happening in that video is:

  • When shot is fired, trace from the center of screen in the camera view direction until the first hit is found
  • Spawn the projectile at the gun muzzle location
  • Calculate the projectile direction as the vector that would connect the gun muzzle and the hit location of the trace (HitLoc - MuzzleLoc)

The other possibility is:

  • Decide beforehand on a “calibration distance”
  • When shot is fired, find the point determined by moving from the center of the screen in the camera view direction for “calibration distance” units. Let’s call this point “Calibration point”.
  • Calculate the projectile direction as the vector that would connect gun muzzle and calibration point.

Which approach to follow depends on what you want the subtle behaviour to be, but neither of these retain the weapon model’s “true aim direction”.

Why not just to use deproject screen location to world - which will give the normalized direction angle - and then woalla you shoot at that angle ?

If you need a line trace then - use the deprojected point as a line trace start then use the direction vector miltiplied by a projectile max distance and add it to the deprojected point and you will get the line trace end point.

Yes, all that i need is the rotation

So, how can i get my “WorldLocation and WorldLocation”? I was looking for that function and discovered that uses your controller, but in the controller class “GetActorLocation or Rotation” are restrict.

Oh now I see the whole problem :-).
Use AHUD class to deproject the the position (center of the screen) to the world location and position (AHUD::Deproject | Unreal Engine Documentation)

Then line trace from the deproject location lets call it A you will also get the direction from this function lets call it B.

Now you want to line trace from A to A + B * shoot range.
Now you want to shoot from Muzzle location to your destination location returned by a hit result.

To find the rotation:
(Destination - muzzle)
then normalize it and get rotation.

staticvoidlol Yes exactly, I overthink it a bit it’s 4am though :-).
your answer is correct - I just trying to explain it :slight_smile:

Yes I deleted em priorly to your post - realizing that same thing u posted now

Probably seeing the triangle in the picture killed my logic :slight_smile:
though it would work, but extrimrly inefficient

And I found it as an interesting question as well, since I never made a shooter game :slight_smile:
Didn’t even know such problem exists :-).

The funniest thing is - I served in army and shot a lot from fire arms - but this is something that human brain calculates and resolves without noticing too much :slight_smile:

The point of the approaches suggested in my first comment is to work in 3 dimensions instead of resorting to approximate trigonometry. Whether you use deprojection from the HUD into the world or a trace in the camera direction is immaterial. You need 3 things:

  • The world location where you want the shot to go based on your camera view direction
  • The muzzle location
  • The vector that “completes” this triangle (Viewpoint, Muzzle, HitLocation) in 3 dimensions (regardless of the orientation of this triangle) is your projectile direction, which you must obviously normalize and you then apply your bullet speed to that to get the required velocity of your projectile to reach that point.

Not sure where my last comment went - I assume ColdSteel48 deleted their last comment and added a new one instead. In any case, the point is that you need 3 items:

  • The world location of where you want the projectile to go (constrained by the view/camera direction)
  • The muzzle location
  • The vector that connects these two points, which is the projectile velocity (after normalizing and applying the required velocity)

Sure no worries :). Your comments did introduce me to the Deproject function on the HUD which seems very useful. I usually just think in simpler terms with simple steps because I can’t keep it all in my head at once (need more RAM I think).

Yes, i made my whole game with a lot of mechanics, I left it at last thinking it was the simplest, and now here i am, breaking the head. I will try all the things that you guys said, thank you very much to try helping me!

Yeah - totally understood (similarly I’ve never really worked in 3rd person either lol), and at the risk of going off-topic here, in my personal little opinion I’ve found that attempting to answer questions here is a great way of forcing myself to try and solve a problem out of my comfort zone, which is in turn tricking myself into learning more :P.

Thats totally true - in general answering question is quite good way to learn by yourself :-).

You are welcome! :slight_smile:

Which is quite useless, you can’t even make a bounty here (Or can I ? )