I have made a shotgun function which works wrong, help pls

My code makes my gun shoot in weird pattern.

In one direction


90 degrees of direction on previous picture.
https://forums.unrealengine.com/core/image/gif;base64
​​​

Code of it:

Shotgun.cpp





#include "Shotgun.h"
#include "Kismet/GameplayStatics.h"
#include "Components/SceneComponent.h"
#include "DrawDebugHelpers.h"
#include "Math/UnrealMathUtility.h"

// Called when the game starts or when spawned
void AShotgun::BeginPlay()
{
Super::BeginPlay();
BulletAngle = StartingBulletAngle;
Radius = tan(BulletAngle) * MaxRange;
}


void AShotgun::PullTrigger()
{
Super::PullTrigger();

FHitResult Hit;
FVector ShotDirection;

for (int i = 1; i <= PelletsCount; i++)
{
bool bSucces = GunTrace(Hit, ShotDirection);
if (bSucces)
{

UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), Impact, Hit.Location, ShotDirection.Rotation());
UGameplayStatics::PlaySoundAtLocation(GetWorld(), HitSound, Hit.Location);

AActor* HitActor = Hit.GetActor();
if (HitActor != nullptr)
{
FPointDamageEvent DamageEvent(Damage, Hit, ShotDirection, nullptr);
AController* OwnerController = GetOwnerController();
HitActor->TakeDamage(Damage, DamageEvent, OwnerController, this);
}
}
}
}


FVector2D AShotgun::RandomPoint(float &X, float &Y)
{
float Angle = FMath::RandRange(0.0f, 360.0f);
float DistanceFromCenter = FMath::RandRange(0.0f, Radius);
X = DistanceFromCenter * cos(Angle);
Y = DistanceFromCenter * sin(Angle);
FVector2D XY = FVector2D(X, Y);
return XY;
}


bool AShotgun::GunTrace(FHitResult& Hit, FVector& ShotDirection)
{
AController* OwnerController = GetOwnerController();
if (OwnerController == nullptr) { return false; }
float X = 0;
float Y = 0;

RandomPoint(X, Y);

FVector Location;
FRotator Rotation;
OwnerController->GetPlayerViewPoint(Location, Rotation);
ShotDirection = -Rotation.Vector();
FVector End = Location + Rotation.Vector() * MaxRange + Rotation.Vector().RightVector * X + Rotation.Vector().UpVector * Y;

DrawDebugPoint(GetWorld(), Hit.Location, 20, FColor::Red, true);
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);
Params.AddIgnoredActor(GetOwner());
return GetWorld()->LineTraceSingleByChannel(Hit, Location, End, ECollisionChannel::ECC_GameTraceChannel1, Params);
}

Shotgun.h


#pragma once

#include "CoreMinimal.h"
#include "Gun.h"
#include "Shotgun.generated.h"

/**
*
*/
UCLASS()
class SIMPLESHITPOST_API AShotgun : public AGun
{
GENERATED_BODY()

public:

// Called when the game starts or when spawned
virtual void BeginPlay() override;

virtual void PullTrigger() override;

private:
bool GunTrace(FHitResult& Hit, FVector& ShotDirection);



UPROPERTY(EditAnywhere)
float StartingBulletAngle = 5;

UPROPERTY(EditAnywhere)
float MaxRange = 1000000;
UPROPERTY(EditAnywhere)
int PelletsCount = 12;
UPROPERTY(EditAnywhere)
int Damage = 10;
UPROPERTY(EditAnywhere)
USoundBase* HitSound;
UPROPERTY(EditAnywhere)
UParticleSystem* Impact;
UPROPERTY(EditAnywhere)

float Radius;
float BulletAngle;

FVector2D RandomPoint(float &X, float &Y);
};

Sorry for Lightning

This code is wrong:

Rotation.Vector().RightVector * X + Rotation.Vector().UpVector

The right and up vector from here are static variables that return 0,1,0 and 0,0,1 respectively. What you actually need to do is a CrossProduct. Cross the rotation vector with UpVector in order to get your right vector and cross that resulting right vector with the rotation vector and that will give you your true up vector. It’s been awhile since I’ve had to actually write code like this, so I might be a little off on the details.

Alternatively, you can get the quaternion from the rotator and that has functions to grab the right and up vectors.

Sorry but I am newbie in programing so could you explain this to me better? I know what Im doing wrong, but I don’t know how to fix it.
Thanks for help.

Sure, I’ll do my best. First, static member variables are variables that are owned by the class and not by individual objects of that class. This means that there is only one copy of that variable that is shared with everything. I would suggest doing some reading on static variables as it’s a super important concept to understand in C++.

As for your specific issue, I haven’t tested or compiled this, but this should be roughly what you’re looking for. I would also suggest doing some reading on cross products and vector math in general. You’re going to need a very strong understand of vectors if you want to make video games, particularly 3D games.


FVector Location;
FRotator Rotation;
OwnerController->GetPlayerViewPoint(Location, Rotation);
ShotDirection = Rotation.Vector();
FVector rightVector = ShotDirection.CrossProduct(FVector::UpVector); //Assuming here that we can never aim straight up. If you can aim straight up, the cross product will be weird
FVector upVector = ShotDirection.CrossProduct(rightVector);
FVector End = Location + (ShotDirection * MaxRange) + (rightVector * X) + (upVector * Y);

With all that said, I just want to point out that this is probably not going to do quite what you want. What this code will do is basically project out a plane in front of the player and randomize the location on the plane. Basic trigonometry tells us that this means is that bullets technically travel farther the farther they are from center.
shot.png

This image is roughly what your algorithm will do. The lines on the outside are longer than the one in the middle. Instead, you should rotate your aiming vector and project out from there. I’ll leave it to you to figure out how to do that on your own.

Thank You very much.