Download

Projectile doesn't go towards crosshair's direction!

Hello.

I have a class for Projectiles: when the Left Mouse Button is clicked the Projectile spawns and (should) go towards the crosshair’s direction.

Instead, in my case, it goes down a bit:

Here’s the code:


/* Called on LEFT MOUSE BUTTON click */
void AWeapon_Projectile::FireWeapon()
{
	// Get shoot direction (GetBaseAimRotation)
        // MyOwner is an ACharacter
	FVector ShootDir = MyOwner->GetBaseAimRotation().Vector();
	
	// Spawn projectile at WeaponSocket on the [SERVER]
	ServerFireProjectile(ShootDir);
}

void AWeapon_Projectile::ServerFireProjectile_Implementation(FVector ShootDir)
{
	/*****************/
	/****** BUG ****** ---> The projectile spawns on the WeaponSocket, and its direction IS NOT the Crosshair direction! 
	/*****************/	

        // Here we say that the Projectile must spawn at a given SocketLocation
	FTransform SpawnTM(MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket"))));	

	AProjectile* Projectile = Cast<AProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ProjectileClass, SpawnTM));
	
	if (Projectile)
	{		
		Projectile->Instigator = Instigator;
		Projectile->SetOwner(this);

                // Here, in the InitVelocity, I pass the ShootDir variable
		Projectile->InitVelocity(ShootDir);

		UGameplayStatics::FinishSpawningActor(Projectile, SpawnTM);
	}
}

/* And here is the InitVelocity() function of the Projectile class */
void AProjectile::InitVelocity(FVector& ShootDirection)
{ 
        // Setting the speed
	MovementComp->InitialSpeed = 5.0f;
	MovementComp->MaxSpeed = 5.0f;

        // HERE WE USE THE ShootDirection
	MovementComp->Velocity = ShootDirection * MovementComp->InitialSpeed;
}

What am I doing wrong?

Thanks in advance!

Everything is fine in your code, however, how do you display the crosshair and where is the camera?
Either the facing direction of your camera equals the facing direction of your weapon muzzle, or you will end up wih this scenario:
685d3caed28eb1a4c0bb96bddc531b7680f5a1e7.png
When the Camera and the Muzzle directions and locations are not equal, they’re vectors will only intersect at one location.
answer2.PNG
Here you see the problem third person aiming concludes: You have to guess where the player is aiming, most likely with a line trace and find the impact location, here: the enemy person. But theoretically, he could
have also tried to aim at this imaginary point closer to him that I tried to visualize with this pink circle. In that case, you see by the red line, he actually would have to hold his gun in a different angle, and the bullet would hit the container on the right, even though the aimed point (the crosshair) was on the same location on the screen.

So, either you align Camera and Muzzle, or you have to check what your player is aiming at, to visualize crosshairs :slight_smile:

In your special case I assume that either you have the weapon on a lower loaction than the camera (camera position doesnt equal Muzzle Location), or very simple: Your bullets have gravity enabled (which is default in the ProjectileMovementComponent)

The crosshair is displayed through a HUD Blueprint, I centered an Image and put a red dot on it.

The first case is my case:

ad958b533b7e907544ae658dfcbecf5ea792b840.jpeg

(wtf? what’s that minigun model doing right there? weird…)

The weapon muzzle changes depending on the weapon. It can be a bit more up, a bit more down.
It changes.
And whenever I switch weapon, I will see the camera brusquely change its facing direction.

I need a mechanism that makes the Projectile go where the camera is looking at, not where the Muzzle is looking at.

In fact, ShootDir is defined as:


FVector ShootDir = MyOwner->GetBaseAimRotation().Vector();

Which SHOULD return the facing Vector of the Camera (not the muzzle).

When I spawn the Projectile (whatever it is, missile… grenade…) it must spawn at Muzzle position and go towards Camera facing direction.

Yes, but think of it. Your character is perfectly looking forward, not slightely to the side and not slightely up or down. What is “his” (the cameras" direction vector? (1,0,0).
Now, when your weapon shoots in the direction of (1,0,0), it just shoots straigh forward, parallel to the camera, but not at the same location.

I recommend you reading through this article :slight_smile: Technical Game Design: Aim systems in First Person Shooters

Best Wishes,
OmaManfred

Yes, I got that.

But I want my projectiles to go towards the center of the screen WHATEVER the spawn-point is (muzzle)!!!

Here’s an image I made quickly for you:

00471eaf8874fa0cbc5af89a20a1d8f810f591a5.jpeg

As you can see (and as you pointed out) the Camera and Muzzle vectors are parallel > they share the same direction and orientation.

Unfortunately, none of them is right.
The center of the screen isn’t reached by none of the two.

I’m looking for the way to say to my projectiles:

“Hey man (projectile). I let you spawn here, in this position of the muzzle flash. But then, once spawned, please go towards the center of the screen, ok? Right…”

I thought I could do this with GetBaseAimRotation (which is what I used to do in this line)


FVector ShootDir = MyOwner->GetBaseAimRotation().Vector(); 

But it doesn’t work.

Maybe the GetBaseAimRotation() is just a forward vector, nothing more.

I need to know what to assign to the ShootDir variable, so that the projectile goes to the CENTER OF THE SCREEN.

There is one thing you didn’t understand yet.

The center of your screen is not one fixed location. In fact, the center of your screen covers infinite possible positions for your weapon to shoot at. Your screen-center is no 3D-World location. You can imagine the crosshair being an infinite pipe going through the world in the center of your screen, but you only see the top of it, as the “crosshair dot”. Now when you want to say your weapon: Shoot at the crosshair… It will respond. Dude… Where is that? It can be that triangle right in front of you, if can be the cube behind it or the sphere all the way in the background.

Actually, the center of the screen also is right between the eyes of your character. The only way, you can shoot a weapon and can assure the projectile will always impact under the crosshair, is when Location AND rotation of both Camera and Muzzle are identical, OR you implement the technique I explained: Line trace from the Center of Screen, get the first blocking hit, and find the HitLocation. Then calculate the angle between this hitLocation and the Projectile Muzzle and set this as it’s roation / Initial Velocity


LineTraceSingleByChannel(ScreenWorldLocation, ScreenWorldLocation + (LookingDirection * MaxTraceLength), DesirdAimChannel, HitResult);
if(HitResult.bBlockingHit){
   TargetedLocation = Hit.Location;
   AimDir= targetedLocation - MuzzleLocation);
   AimDir.Normalize();
   Projectile->SetInitialVelocity(BaseVelocity*AimDir);
}

That was a hint.

I stored the location and rotation of the center of the screen (recall the last pic I showed you?) in two vectors:


FVector CameraLoc;
FRotator CameraRot;
MyOwner->GetActorEyesViewPoint(CameraLoc, CameraRot);

Then I set the Muzzle location as the **Socket **location (see pic number 1 in post number #3).

The Muzzle rotation is just the rotation of CameraRot


FVector MuzzleLocation = MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket")));
FRotator MuzzleRotation = CameraRot;

Okay.

Now I define a SpawnTransformation for my Projectile


	FTransform SpawnTM(MuzzleLocation);

	AProjectile* Projectile = Cast<AProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ProjectileClass, SpawnTM));

That’s where the projectile is gonna spawn. It’s gonna spawn in Muzzle Location (thus, Socket location) and Muzzle Rotation (thus, camera rotation, where the crosshair is)

And now let’s finalize the spawn


if (Projectile)
{
	Projectile->Instigator = Instigator;
	Projectile->SetOwner(this);

	FVector LaunchDirection = MuzzleRotation.Vector();
	Projectile->InitVelocity(LaunchDirection);

	UGameplayStatics::FinishSpawningActor(Projectile, SpawnTM);
}

Unfortunately, the projectile doesn’t go towards crosshair direction (hence, center of the screen).

It goes… like… on my left

(if that can be useful, I’m following this guide: A new, community-hosted Unreal Engine Wiki - Announcements and Releases - Unreal Engine Forums )

Yes, because y your Muzzle Location is still no multiple of your View-Location-Direction. (Your muzzle location has to be under the crosshair).
Set the muzzle Location to CameraLoc, then it will work. As I said, Location AND(!!) Rotation have to be identical, or well for location it only has be on the view-plane (can be moved in the viewing direction)

Further Reading

I can’t set the Muzzle of the Weapon to the same location of the Camera!!!

For this reason I’d choose to go for a LineTrace


	FVector CameraLoc;
	FRotator CameraRot;
	MyOwner->GetActorEyesViewPoint(CameraLoc, CameraRot);

	FHitResult Hit;
	GetWorld()->LineTraceSingleByChannel(Hit, CameraLoc, CameraLoc + (CameraRot.Vector() * 1000), COLLISION_WEAPON);

	FVector AimDir;

	if (Hit.bBlockingHit)
	{
		AimDir = Hit.Location - MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket")));
		AimDir.Normalize();
	}

	FTransform SpawnTM(MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket"))));

	AProjectile* Projectile = Cast<AProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ProjectileClass, SpawnTM));

	if (Projectile)
	{
		Projectile->Instigator = Instigator;
		Projectile->SetOwner(this);
		Projectile->InitVelocity(AimDir);

		UGameplayStatics::FinishSpawningActor(Projectile, SpawnTM);
	}

For some reason, the projectile goes toward the **OPPOSITE **of my Crosshair.

For which reason?

AimDir is undefined when you don’t hit anything, so the behaviour is unpredictable. And CameraRot.Vector() * 1000 is 1000cm, so 10 meters. You sure you aimed at something less than 10 meters away?

I hit something yes, and that ‘something’ wasn’t farther than 10meters. Same problem.

Anyway, I don’t want these kind of limitations. My projectile must spawn-and-go regardless if the LineTrace hits something or not, regardless of the distance!

I’m afraid that this is mathematicallly not possible then.

It isnt too hard to imagine the situation, you can’t fire a projectile with a spawn location different location and pass infinite points on a different line, your crosshair line. It is not possible, not just programmatically, mathematically.

Just imagine a cube in front of your character directly in the center. Now walk 1000m back. The cube will still be under your crosshair. But your weapon would have to aim differently to hit it.

Aaaaaalright but there are thousands of shooters out there. One can say every game is a shooter game.

How can I implement a damned shooting system?

Just like I said the past 5-6 responses. I also linked you 2 webpages, that you didn’t read apparently.

You just simply don’t fire your projectile from your muzzle but from your camera. That’s it. Seperate FX and actual projectile physics.

If you want to see a working example, download the C++ Shooter Example, it features both aimed and hip fire with crosshairs.
Maybe I am stupid and there indeed is another way. At least, I looked into the Shooter Example source and didn’t see projectiles being shot from the CameraLocation, so chances are there might be some other way I don’t know of, just look into it :slight_smile:

Tell me… if you play a game with a friend, and your friend shoots a Missile… and you see the Missile coming out FROM YOUR FRIEND’S EYES rather than your friend’s weapon… what would you say? **That the game sucks? Yes, me too.
**
I know a game where this happens, here’s a screenshot:

738553fe0ea5c7aa53ea8b5ac31be4e3929fb454.jpeg

Oh my gosh, where’s the Rocket coming from? From the player’s eyes! That’s horrible!

What if it were a grenade? Oh, it would look like the player just throws away one of his eyes… XD please, that’s horrible.

It would have been way more beautiful to see the Rocket come out from the MuzzleFlash of the weapon.
AND every weapon has its OWN MuzzleFlash.

I mean, the Muzzle isn’t a FIXED Socket. I may have a Shotgun long half a meter, and I may have another shotgun long 1 meter.

Each of those has a **DIFFERENT **Muzzle Socket position.

What do they have in common?

The damned center of the screen:


    FVector CameraLoc;
    FRotator CameraRot;
    MyOwner->GetActorEyesViewPoint(CameraLoc, CameraRot);

Uh hey, I already did it :cool:

There’s a good start with the ShooterExample code. Apparently, he seems to do what I wanted to do since the beginning…

ShooterWeapon_Projectile::FireWeapon() ]


// ShootDir contains the center of the screen. GetAdjustedAim() just returns the equivalent of my CameraRot.Vector()
FVector ShootDir = GetAdjustedAim();

// Origin is the MuzzleFlash of the Current weapon
FVector Origin = GetMuzzleLocation();

Okay, that was the first step that I did too.

The second step:


// trace from camera to check what's under crosshair ### WHY? ###
const float ProjectileAdjustRange = 10000.0f;
const FVector StartTrace = GetCameraDamageStartLocation(ShootDir);
const FVector EndTrace = StartTrace + ShootDir * ProjectileAdjustRange;
FHitResult Impact = WeaponTrace(StartTrace, EndTrace);

Okay. Super question: why this? What are they trying to do with that?

If I AM IN POSSESSION of the CameraRotation (thus, the center of the screen) stored inside the ShootDir variable… why do I need to LineTrace?

Maybe for the reason you described in post #6?

My head is gone…

Why are you so passive agressive, it’s not my fault that what you are trying to do is mathematically impossible.

I can just repeat myself: Seperate Physics and Visuals. Do you even read my messages? Battlefield 4 Visual Recoil, it's all in your head! - YouTube
Watch it until at least 3:50. Please. Actually watch it this time :wink:
If you only have one minute, watch it from 3:20… 4:10 is the magic sentence :wink:

Edit: And before you say that the annotations say “This issue has been fixed”, it means just that the visuals impact now the same on local and external client, not the system itself.

Agressive? Never been agressive against someone who’s spending his time to help me =)

Look at this part of the video: https://youtu.be/cPr5K23Xk4c?t=4m9s

Why can’t I do something like this, using another FVector?

696d997ac28dfa9747f79dd26c9ad9ac96dac38c.jpeg

Is it mathematically impossible?.. seems incredible to believe… it’s just a third-part vector…

Yes it’s impossible. Please think about it… The red line and the yellow line. Where do they intersect? Right, at ONE location. That means that only at ONE location your bullet would actually impact under your crosshair. In all the other infinite other points of your yellow line that represents the camera view and thus also the red dot, the bullet would NOT impact under it.

As I said already, the center of your screen is no point in the world.

However, this basically is the second half of the LineTrace Method, where you determine what your Character is aiming at by that lineTrace and then you can draw this yellow line from your muzzle to your desired impact location. However, considering travel speed, it might happen that due to dynamic environment changes the bullet can still impact not under your crosshair, when for example a cube spawns in front of what you aimed at.

Oh I finally got that. So the intersection point between the yellow and red line is always the same. I got it.

Okay now that I got that, I can go further.

This is the code I made, following my logic AND your suggestions



	FVector CameraLoc;
	FRotator CameraRot;
	MyOwner->GetActorEyesViewPoint(CameraLoc, CameraRot);

	FHitResult Hit;
	GetWorld()->LineTraceSingleByChannel(Hit, CameraLoc, CameraLoc + (CameraRot.Vector() * 9000), COLLISION_WEAPON);

	FVector AimDir;

	if (Hit.bBlockingHit)
	{
		AimDir = Hit.Location - MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket")));
		AimDir.Normalize();
	}

        else
        {
             // in this case, AimDir is undefined!
        }

	FTransform SpawnTM(MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket"))));

	AProjectile* Projectile = Cast<AProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ProjectileClass, SpawnTM));

	if (Projectile)
	{
		Projectile->Instigator = Instigator;
		Projectile->SetOwner(this);
		Projectile->InitVelocity(AimDir);

		UGameplayStatics::FinishSpawningActor(Projectile, SpawnTM);
	}


**
What’s the problem with this code?**

#1
The projectile doesn’t go forward. It goes backwards, in the opposite direction rather than where I aimed!

Yes, I made sure I shot something within 9000 centimeters…

#2 - (this is secondary for now, the bug num#1 is the most intimidating for now!)
AimDir, as you said, CAN be undefined if nothing is hit by the LineTrace. How do I make my projectile start and go towards my crosshair, even if I aimed at the sky?

In the Projectile Movement Component Class there is a boolean that is named “Initial Velocity in World Space”. Make sure that is checked.