Projectiles in 3rd person shooting game.

Hello I have been working on a little project and I tried implementing projectiles following the fps tutorial in the documentation. When I build the code and run the game I press the left mouse button and the amount of objects does not go up which implies that my character is not shooting. I will send here the code for my character and the projectile. A little insight would be much apreciated.

WeaponProjectile.h


#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Components/SphereComponent.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "WeaponProjectile.generated.h"

UCLASS()
class HUNTERTOWER_API AWeaponProjectile : public AActor
{
GENERATED_BODY()



public:
// Sets default values for this actor's properties
AWeaponProjectile();

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

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

//Sphere Collision component
UPROPERTY(VisibleAnywhere, Category = Projectile)
USphereComponent* CollisionComponent;

//Projectile movement component
UPROPERTY(VisibleAnywhere, Category = Movement)
UProjectileMovementComponent* ProjectileMovementComponent;

//Projectile mesh
UPROPERTY(VisibleAnywhere, Category = Projectile)
UStaticMeshComponent* ProjectileMeshComponent;

//Projectile material
UPROPERTY(VisibleAnywhere, Category = Movement)
UMaterialInstanceDynamic* ProjectileMaterialInstance;

//Function that initializes the projectile's velocity in the shoot direction
//Function is responsible for launching the projectile
void FireInDirection(const FVector& ShootDirection);

};


WeaponProjectile.cpp


#include "WeaponProjectile.h"

// Sets default values
AWeaponProjectile::AWeaponProjectile()
{
// 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;

if (!RootComponent)
{
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("ProjectileSceneComponent"));
}

if (!CollisionComponent)
{
//Use a sphere as a simple collision representation
CollisionComponent = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComponent"));
//Set sphere collision radius
CollisionComponent->InitSphereRadius(15.0f);
//Set the root component to be the collision component
RootComponent = CollisionComponent;
}

if (!ProjectileMovementComponent)
{
//Use this component to drive this projectile's movement
//check documentation for definition of these components
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovementComponent"));
ProjectileMovementComponent->SetUpdatedComponent(CollisionComponent);
ProjectileMovementComponent->InitialSpeed = 3000.0f;
ProjectileMovementComponent->MaxSpeed = 3000.0f;
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->bShouldBounce = true;
ProjectileMovementComponent->Bounciness = 0.3f;
ProjectileMovementComponent->ProjectileGravityScale = 0.0f;
}

if (!ProjectileMeshComponent)
{
//make sure to remove the type of the reference of the mesh
ProjectileMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ProjectileMeshComponent"));
static ConstructorHelpers::FObjectFinder<UStaticMesh>Mesh(TEXT("'/Game/OtherMeshes/Sphere.Sphere'"));

if (Mesh.Succeeded())
{
ProjectileMeshComponent->SetStaticMesh(Mesh.Object);
}

static ConstructorHelpers::FObjectFinder<UMaterial>Material(TEXT("'/Game/OtherMeshes/SphereMaterial.SphereMaterial'"));
if (Material.Succeeded())
{
ProjectileMaterialInstance = UMaterialInstanceDynamic::Create(Material.Object, ProjectileMeshComponent);
}

ProjectileMeshComponent->SetMaterial(0, ProjectileMaterialInstance);
ProjectileMeshComponent->SetRelativeScale3D(FVector(0.09f, 0.09f, 0.09f));
ProjectileMeshComponent->SetupAttachment(RootComponent);
}
}

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

}

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

}

void AWeaponProjectile::FireInDirection(const FVector& ShootDirection)
{
//You only needed to supply a launch direction because the projectile's speed is defined by (ProjectileMovementConmponent)
ProjectileMovementComponent->Velocity = ShootDirection * ProjectileMovementComponent->InitialSpeed;
}

here is the fire function I put in the Hunter.cpp (my character)


void AHunter::Fire()
{
//attempt to fire a projectile
if (ProjectileClass)
{
//get the camera transform
FVector CameraLocation;
FRotator CameraRotation;
GetActorEyesViewPoint(CameraLocation, CameraRotation);

//Set MuzzleOffset to spawn projectiles at a certain point in front of the camera
MuzzleOffset.Set(300.0f, 0.0f, 0.0f);

//Transform MuzzleOffset from camera space to world space
FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);

//Skew the aim to be slightly upwards
FRotator MuzzleRotation = CameraRotation;
MuzzleRotation.Pitch += 10.0f;

UWorld* World = GetWorld();

if (World)
{
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
SpawnParams.Instigator = GetInstigator();

//Spawn the projectile at the muzzle
AWeaponProjectile* Projectile = World->SpawnActor<AWeaponProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);

if (Projectile)
{
//set the projectile's initial trajectory
FVector LaunchDirection = MuzzleRotation.Vector();
Projectile->FireInDirection(LaunchDirection);
}
}

}
}

and this was added to Hunter.h (my character)


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

//Projectile class to spawn
UPROPERTY(EditDefaultsOnly, Category = Projectile)
TSubclassOf<class AWeaponProjectile> ProjectileClass;

public:
// Called every frame
virtual void Tick(float DeltaTime) override;

// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

//Function that handles firing projectiles.
UFUNCTION()
void Fire();

//Gun muzzle offset from the camera location
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
FVector MuzzleOffset;

};

Sorry for the long post and than you so much for the help. I’m rather new to the engine and I still have much to learn.

You could try to Change SpawnParams by allowing it to Always Spawn.



SpawnParameters.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;


plus it will be better to put another else statement in case if(ProjectileClass is nullptr) so you can see what is missing.

Documentation has been updated somewhat recently with a new page about spawning projectiles and dealing damage using c++ you can check it out here Multiplayer Programming Quick Start | Unreal Engine Documentation