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).
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...
....
}
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.
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”.
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.
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.
And I found it as an interesting question as well, since I never made a shooter game
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
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.