Best way to handle projectiles


Hey all, super noob here.

I am learning UE5 and C++ and a couple of friends and I are working on a simple 3rd person shooter. I am looking for the best way to handle projectiles for this. Currently, I have a seperate class for the projectiles themselves and everything seems to work okay, except for when my character fires, the projectiles don’t go straight, but actually fire at a slight down angle causing them to not go very far and into the floor. Since the AI (the robot pictured in the screenshot) seems to have no issue with this and is a child of the same class I use for my character, I’m thinking it’s because of the angle of the camera for the player character (Alien guy).

I would like for the projectiles to go straight out from the characters weapon. I will also be using particle effects for the projectiles when my friend finishes making them.

Is there a solution for my current setup, or should I just use a line trace instead?

Again, I am a total newbie basically so I apologize if I am not explaining this very well and I will be happy to share any other info that may help someone help me.

Thanks in advance!

1 Like

Sounds like it. What are you using to orient the projectiles?

1 Like

Hey! Thanks for the quick reply

So I have my character class, gun class and projectile class. I created the static mesh and projectile movement component within the projectile class as well as setting initial speed and max speed. I then have a “Pull trigger” function and a “gun trace” function in the gun class which spawns the projectile and adds damage. I then have a “fire” function within the character class that calls the “pull trigger” function. I’ll leave some code here so that it hopefully makes sense, because I know I’m not the best at explaining/describing things haha

for the projectile:

AProjectile::AProjectile()
{

PrimaryActorTick.bCanEverTick = true;

ProjectileMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Projectile Mesh"));
RootComponent = ProjectileMesh;

ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("Projectile Movement Component"));	
ProjectileMovementComponent->MaxSpeed = 5000;
ProjectileMovementComponent->InitialSpeed = 3000;

}

// Called when the game starts or when spawned
void AProjectile::BeginPlay()
{
Super::BeginPlay();

ProjectileMesh->OnComponentHit.AddDynamic(this, &AProjectile::OnHit);

}

// Called every frame
void AProjectile::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

void AProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
AActor* MyOwner = GetOwner();
if (MyOwner == nullptr)
{
return;
}

AController* MyOwnerInstigator = MyOwner->GetInstigatorController();
UClass* DamageTypeClass = UDamageType::StaticClass();

if (OtherActor && OtherActor != this && OtherActor != MyOwner)
{
	UGameplayStatics::ApplyDamage(OtherActor, Damage, MyOwnerInstigator, this, DamageTypeClass);
	Destroy();
}

}

for the gun:

AGun::AGun()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don’t need it.
PrimaryActorTick.bCanEverTick = true;

Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
SetRootComponent(Root);

Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
Mesh->SetupAttachment(Root);

ProjectileSpawnPoint = CreateDefaultSubobject<USceneComponent>(TEXT("Spawn Point"));
ProjectileSpawnPoint->SetupAttachment(Mesh);

}

// Called when the game starts or when spawned
void AGun::BeginPlay()
{
Super::BeginPlay();
}

// Called every frame
void AGun::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

void AGun::PullTrigger()
{
UGameplayStatics::SpawnEmitterAttached(MuzzleFlash, Mesh, TEXT(“MuzzleFlashSocket”));

FVector ProjectileLocation = ProjectileSpawnPoint->GetComponentLocation();
FRotator ProjectileRotation =  ProjectileSpawnPoint->GetComponentRotation();
AProjectile* Projectile = GetWorld()->SpawnActor<AProjectile>(ProjectileClass, ProjectileLocation, ProjectileRotation);		Projectile->SetOwner(this);
UGameplayStatics::SpawnEmitterAttached(ProjectileBeam, ProjectileSpawnPoint, TEXT("ProjectileBeamSocket"));

FHitResult Hit;
FVector ShotDirection;
bool bSuccess = GunTrace(Hit, ShotDirection);
if(bSuccess)
{
//	UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.Location, ShotDirection.Rotation());
//	UGameplayStatics::PlaySoundAtLocation(GetWorld(), ImpactSound, Hit.Location);
	
	AActor* HitActor = Hit.GetActor();
	if (HitActor != nullptr)
	{
		FPointDamageEvent DamageEvent(Damage, Hit, ShotDirection, nullptr);
		AController* OwnerController = GetOwnerController();
		HitActor->TakeDamage(DamageAmount, DamageEvent, OwnerController, this);
	}
}

Let me know if this helps or if I need to share anything else, and thanks again!

Edit: Forgot to add that I set my projectile spawn point at the gun barrel in Unreal Editor

I don’t see it here but you should be using something like:

const FRotator SpawnRotation = GetOwner()->GetActorRotation();

Rather than camera’s or camera manager’s rotation (which can be the same thing).

1 Like

(post deleted by author)

Wow, dude. Two replies and one line of code and that problem is fixed. Thank you so much! You’re a beast.