Projectile collides with Character when shooting upwards!

Gameplay design-wise I wouldn’t spawn it directly at the cameras position, because everytime you shoot the entire missiles thruster glow and smoke trail would be in the players face and blocking the players view. As a player i would find this very irritating and annoying and a bit cheap.
If you want to go for realism/immersion you should spawn slow projectiles like missiles, grenades, etc at the weapons muzzle location.
If you don’t want to use the muzzles location, at least put a slight offset relative to the players camera for spawning missiles or grenades so they don’t block the players view.

If your concern is still this

then my code suggestion should fix that problem. If you use the trace hit point under your crosshair as your target location and your muzzle location as your start location then my suggestion should for hitting that target location (unless there is an obstacle between the cursor and the muzzle, of course).

Many Arena games I know actually spawn the Rockets from the camera. Look at this, for instance!

image_76286.jpg

The rocket gets out of the player’s head, not weapon!

I might be wrong, but what you’re saying here is basically what I already did: find the blocking hit, spawn the projectile from the muzzle and make it travel towards the hit result.

How does your implementation differ from mine?

Firing from the Camera seems like the simplest solution, add a forward offset and put a delay before activating the trail particles if they are annoying. A muzzle flash will hide the fake spawn.

Spawning from the weapon; If you don’t get a hit from the trace, what end position should you use for the calculations?

In that case you can use “Camera location + (camera forward vector * some large number)” to get a point forward but way, waaay in the distance.

FrostyElkArne StefanHohnwald

I think that shooting from the Camera not only is simpler, but also more correct:

123.jpg

That is a huge problem if you think about it. Still I can’t understand whether some games actually spawn projectiles from the Weapon Muzzle and, if yes, how they explain this horrible issue.

Half Life 1 for example launches its rockets from the weapon, not the players eyes.
Pretty much all space action games (Freespace, Wing Commander, X-Series, No Mans Sky etc) also launch their projectiles from the spaceships muzzles.
Many third person games like Dead Space do the same.

And yes, if there is an obstacle in the way, the projectiles will hit that obstacle. Yes, it can be an issue, mostly when the obstacle is right on front of the player character but you try to shoot over that obstacle to an enemy. It can be a negative thing (“if i point my mouse at it, i should hit it”) or a positive thing (“instead of just pointing and clicking, the player is rewarded for being more aware of his surroundings and projectile behavior”) and a realistic thing (if i hold a minigun at knee height, have a shoulder height wall in front of me, it’s realistic that the bullets hit the wall instead of what i’m looking at")…

It all comes down to whether you want to make it realistic/immersive (spawn from muzzle) or more action/arcade-like (spawn from players eyes).

That being said, Dead Space handles this problem really well by having a visible laser sight ray pointing forward for each weapons muzzle, so the player can see if any of the weapons muzzles is obstructed by obstacles.You can take a look at this video for examples:

Apologies, I glanced over that one. Of course by spawning from the emission point, you’re going to have a different trajectory than if you fire it from the camera. However, how big of a deal is it for you or the player? Assuming you’re doing a third person shooter, this shouldn’t be a real problem for the player. Most third person shooters do have the problem of a wall being in the way of weapon fire, however when has this affected gameplay? The effect of this quirk diminishes quickly the farther the target you are aiming at is.

If you were to shoot projectiles from the camera, this would look weird. The projectile would potentially block the camera for a moment depending on the projectile speed (unless you made it invisible at a certain angle).

An idea I propose is to shoot a projectile from the weapon that ignores any wall it goes through that is not in the way of the camera. Since the weapon and camera traces are not too far apart, a fast projectile going through the wall would most likely not be noticed except by the most observant of players. As pointed out, you have the choice between realistic shooting (weapon) and arcade shooting (camera). My proposal kind of merges the two.

Ultimately, it’s not about what makes the most sense; it’s about what feels good to the player. Perhaps the reason why many shooters use warnings instead of fixing the obstacle discrepancy between camera and weapon is because it’s what players feel is the best compromise. example of Dead Space is perfect in this case.

@Lexeon thanks for the detailed explanation… I think I’ll end up spawning the projectiles from the camera. After all, all Arena FPS games I know of do it this way… it’s a fast action arcade game…

I tried this way as you suggested;



void APAWeapon_Projectile::ServerFireProjectile_Implementation(FVector Origin, FVector ShootDir)
{
    FVector SocketLocation = MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket")));

    FVector Origin = SocketLocation;
    FVector ShootDir = UKismetMathLibrary::FindLookAtRotation(Origin, Impact.Location).Vector();

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

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

    if (Projectile)
    {
        Projectile->Instigator = Instigator;
        Projectile->SetOwner(this);
        Projectile->InitVelocity(ShootDir);        // here we set the direction of our projectile

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


But the issue is the same: the rocket hits the wall BEFORE aligning with the crosshair!

image_146055.jpg

(the red dot is the crosshair, the white ball is the rocket)

That’s quite odd, provided that you disabled the priojectiles gravity and get the correct location from the hit result it should work. I’m using a similar method in my projects and it works without any problems. Where and how did you calculate the “Impact” data? Are you sure that the crosshair is in the same spot as the location you’re getting the trace hit result from?

You could draw a debug line from Origin to Impact.Location and see where the line is to see if it’s the trace results fault or anything else.

But if you decided to spawn it from the camera it doesn’t matter anyway. I’m just curious. :slight_smile:

It was better if you never said that: **the result is quite awkward

**

Wherever I shoot, that white line trace starts from my head and goes straight to THAT point. It’s always THAT point!

This is how I handle the trace:



    APACharacter* MyOwner = Cast<APACharacter>(GetOwner());
    FVector SocketLocation = MyOwner->GetMesh()->GetSocketLocation((FName("WeaponSocket")));
    FVector SocketRotation = MyOwner->GetMesh()->GetSocketRotation((FName("WeaponSocket"))).Vector();
    FVector CameraLoc;
    FRotator CameraRot;
    MyOwner->GetActorEyesViewPoint(CameraLoc, CameraRot);

    FVector Origin = SocketLocation;
    FVector ShootDir = CameraRot.Vector();    

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

    //ShowTrace(StartTrace, EndTrace, FColor::Cyan);

    // and adjust directions to hit that actor
    if (Impact.bBlockingHit)
    {
        const FVector AdjustedDir = (Impact.ImpactPoint - Origin).GetSafeNormal();
        bool bWeaponPenetration = false;

        const float DirectionDot = FVector::DotProduct(AdjustedDir, ShootDir);
        if (DirectionDot < 0.0f)
        {
            // shooting backwards = weapon is penetrating
            bWeaponPenetration = true;
        }

        else if (DirectionDot < 0.5f)
        {
            // check for weapon penetration if angle difference is big enough
            // raycast along weapon mesh to check if there's blocking hit
            FVector MuzzleStartTrace = Origin - SocketRotation * 150.0f;
            FVector MuzzleEndTrace = Origin;
            FHitResult MuzzleImpact = WeaponTrace(MuzzleStartTrace, MuzzleEndTrace);

            if (MuzzleImpact.bBlockingHit)
            {
                bWeaponPenetration = true;
            }
        }

        if (bWeaponPenetration)
        {
            // spawn at crosshair position
            Origin = Impact.ImpactPoint - ShootDir * 10.0f;
        }
        else
        {
            // adjust direction to hit
            ShootDir = AdjustedDir;
        }
    }

    // suggested by you = any previous change of this variable is lost due to this assignment
    ShootDir = UKismetMathLibrary::FindLookAtRotation(Origin, Impact.Location).Vector();    

    DrawDebugLine(GetWorld(), Origin, ShootDir, FColor::White, true, 0, 0, 0.7f);


That line gives you only the vector (x,y,z directions) that points from one point to another. That vector only represents a direction, not a meaningful location.
Instead of drawing the debug line from Origin to ShootDir, you should draw it from Origin to Impact.Location. :slight_smile:

Also, if the line trace has no result, the Impact.Location will be FVector(0, 0, 0).
If your debug line always points to 0,0,0, then your trace has no valid result (aka nothing “hitable” is detected by your trace).

Lets try it with some debug messages to check if your trace is actually hitting anything AND which point it is hitting… i also corrected the DrawDebugLine parameters: (You can take the debug messages out when you’re done with the code)



    // and adjust directions to hit that actor
    if (Impact.bBlockingHit)
    {
        if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, FString("Trace hit result:")); }
        if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Green, Impact.Location.ToString()); }


        ... rest is the same ...]
    }
    else
    {
        if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::Red, FString("No valid trace blocking hit")); }
    }

    // suggested by you = any previous change of this variable is lost due to this assignment
    ShootDir = UKismetMathLibrary::FindLookAtRotation(Origin, Impact.Location).Vector();    

    if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 1.f, FColor::White, ShootDir.ToString()); }

    DrawDebugLine(GetWorld(), Origin, Impact.Location, FColor::White, true, 0, 0, 0.7f);


The goal is that the debugline is drawn from your weapons socket to whatever is under your crosshair.
Then you know FindLookAtRotation(Origin, Impact.Location) gives you the correct direction.

I used Impact.Location before using ShootDir, Both have the same behaviour.

Anyways: this is when I shoot at a wall

And this is when I shoot in the sky (it should say “No valid trace blocking hit”)

Totally forgot about this thread until I came upon the same thing here. My guess is a bug, as the same parameters in blueprints works perfect. My line traces keep hitting everything, even within the air. If I set the trace in the middle of nowhere a million units from any object, it will still say it hits most frames. I’m going to put up a bug report and get back here.

That’s really weird.
Also, how could such an elementary thing even be a bug?

By the way, I’ll wait for news!

I forgot to mention that I was using a custom trace channel instead of the predefined ones such as “visibility”. The engine channels work fine for me at least, however using custom channels in C++ just causes the trace to return true half of the time. I do know that it is not my setting up of the channel as blueprints work flawlessly.

I took a closer look at your code. I did see you used a function “WeaponTrace” to set your hit result “Impact” instead of a one-liner trace. Could you post the WeaponTrace function here as well as your current weapon code if it’s different than your OP. If you’re using anything other than a trace by channel for a weapon, I suggest you try that out if you have not already as well.

I’m using a custom line trace channel too.



FHitResult APAWeapon::WeaponTrace(const FVector& StartPlug, const FVector& EndPlug, const TArray<AActor*>& IgnoreActors) const
{
    static FName WeaponFireTag = FName(TEXT("WeaponTrace"));

    // Perform trace to retrieve hit info
    FCollisionQueryParams TraceParams(WeaponFireTag, true, Instigator);
    TraceParams.bTraceAsyncScene = true;
    TraceParams.bReturnPhysicalMaterial = true;
    TraceParams.AddIgnoredActors(IgnoreActors);

    FHitResult Hit(ForceInit);
    GetWorld()->LineTraceSingleByChannel(Hit, StartPlug, EndPlug, COLLISION_WEAPON, TraceParams);

    return Hit;
}


Are there things that the weapon should not hit at all? Until this is resolved, I say you could just do a trace with the visibility channel (I know for sure works) and give enemies a tag, and when a collision occurs you check if the object has the enemy tag to identify it. You could also cast the hit object to an enemy, but casting is a bit expensive in large quantities and I don’t know how often your projectile will be fired.

I also just tested the above function on my end and I’m seeing the same thing: hits where there should be nothing. I’ve put in a bug report already and am waiting to hear back. I’m gonna ask around and see if anyone else has this problem; I searched it up but I can’t seem to find anyone else with this. If I find anything, I’ll let you know! :cool:

Edit: Forgot to mention that I set the definition of COLLISION_WEAPON to different custom trace channels each run.

The solution for me was moving the muzzle on rpg further in front than expected. This isn’t noticeable on fps view but this creates a problem when shooting down. Somehow I think the best solution would be a variable muzzle lengt that adjust on user rotation.

If there is another implementation let me know.