Language:
Page Info
Skill Level:
Engine Version:

3.2 - Implementing Shooting

During this step, we're going to implement the OnFire function so that our character can start firing projectiles.

Implementing the OnFire Function

  1. Locate the FPSCharacter class CPP file in the Solution Explorer and open FPSCharacter.cpp.

  2. Add the following #include at the top of FPSCharacter.cpp.

    #include "FPSProjectile.h"
  3. Add the following Fire function definition to FPSCharacter.cpp:

    void AFPSCharacter::Fire()
    {
        // Attempt to fire a projectile.
        if (ProjectileClass)
        {
            // Get the camera transform.
            FVector CameraLocation;
            FRotator CameraRotation;
            GetActorEyesViewPoint(CameraLocation, CameraRotation);
    
            // Transform MuzzleOffset from camera space to world space.
            FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);
            FRotator MuzzleRotation = CameraRotation;
            // Skew the aim to be slightly upwards.
            MuzzleRotation.Pitch += 10.0f;
            UWorld* World = GetWorld();
            if (World)
            {
                FActorSpawnParameters SpawnParams;
                SpawnParams.Owner = this;
                SpawnParams.Instigator = Instigator;
                // Spawn the projectile at the muzzle.
                AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
                if (Projectile)
                {
                    // Set the projectile's initial trajectory.
                    FVector LaunchDirection = MuzzleRotation.Vector();
                    Projectile->FireInDirection(LaunchDirection);
                }
            }
        }
    }
  4. FPSCharacter.cpp should now look like the following:

    // Fill out your copyright notice in the Description page of Project Settings.
    
    #include "FPSProject.h"
    #include "FPSCharacter.h"
    #include "FPSProjectile.h"
    
    // Sets default values
    AFPSCharacter::AFPSCharacter()
    {
        // Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
        PrimaryActorTick.bCanEverTick = true;
    
        // Create a first person camera component.
        FPSCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
        // Attach the camera component to our capsule component.
        FPSCameraComponent->AttachTo(GetCapsuleComponent());
        // Position the camera slightly above the eyes.
        FPSCameraComponent->SetRelativeLocation(FVector(0.0f, 0.0f, 50.0f + BaseEyeHeight));
        // Allow the pawn to control camera rotation.
        FPSCameraComponent->bUsePawnControlRotation = true;
    
        // Create a first person mesh component for the owning player.
        FPSMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("FirstPersonMesh"));
        // Only the owning player sees this mesh.
        FPSMesh->SetOnlyOwnerSee(true);
        // Attach the FPS mesh to the FPS camera.
        FPSMesh->AttachTo(FPSCameraComponent);
        // Disable some environmental shadowing to preserve the illusion of having a single mesh.
        FPSMesh->bCastDynamicShadow = false;
        FPSMesh->CastShadow = false;
    
        // The owning player doesn't see the regular (third-person) body mesh.
        GetMesh()->SetOwnerNoSee(true);
    }
    
    // Called when the game starts or when spawned
    void AFPSCharacter::BeginPlay()
    {
        Super::BeginPlay();
    
        if (GEngine)
        {
            // Put up a debug message for five seconds. The -1 "Key" value (first argument) indicates that we will never need to update or refresh this message.
            GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::Red, TEXT("We are using FPSCharacter."));
        }
    }
    
    // Called every frame
    void AFPSCharacter::Tick( float DeltaTime )
    {
        Super::Tick( DeltaTime );
    
    }
    
    // Called to bind functionality to input
    void AFPSCharacter::SetupPlayerInputComponent(class UInputComponent* InputComponent)
    {
        Super::SetupPlayerInputComponent(InputComponent);
    
        // Set up "movement" bindings.
        InputComponent->BindAxis("MoveForward", this, &AFPSCharacter::MoveForward);
        InputComponent->BindAxis("MoveRight", this, &AFPSCharacter::MoveRight);
    
        // Set up "look" bindings.
        InputComponent->BindAxis("Turn", this, &AFPSCharacter::AddControllerYawInput);
        InputComponent->BindAxis("LookUp", this, &AFPSCharacter::AddControllerPitchInput);
    
        // Set up "action" bindings.
        InputComponent->BindAction("Jump", IE_Pressed, this, &AFPSCharacter::StartJump);
        InputComponent->BindAction("Jump", IE_Released, this, &AFPSCharacter::StopJump);
        InputComponent->BindAction("Fire", IE_Pressed, this, &AFPSCharacter::Fire);
    }
    
    void AFPSCharacter::MoveForward(float Value)
    {
        // Find out which way is "forward" and record that the player wants to move that way.
        FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::X);
        AddMovementInput(Direction, Value);
    }
    
    void AFPSCharacter::MoveRight(float Value)
    {
        // Find out which way is "right" and record that the player wants to move that way.
        FVector Direction = FRotationMatrix(Controller->GetControlRotation()).GetScaledAxis(EAxis::Y);
        AddMovementInput(Direction, Value);
    }
    
    void AFPSCharacter::StartJump()
    {
        bPressedJump = true;
    }
    
    void AFPSCharacter::StopJump()
    {
        bPressedJump = false;
    }
    
    void AFPSCharacter::Fire()
    {
        // Attempt to fire a projectile.
        if (ProjectileClass)
        {
            // Get the camera transform.
            FVector CameraLocation;
            FRotator CameraRotation;
            GetActorEyesViewPoint(CameraLocation, CameraRotation);
    
            // Transform MuzzleOffset from camera space to world space.
            FVector MuzzleLocation = CameraLocation + FTransform(CameraRotation).TransformVector(MuzzleOffset);
            FRotator MuzzleRotation = CameraRotation;
            // Skew the aim to be slightly upwards.
            MuzzleRotation.Pitch += 10.0f;
            UWorld* World = GetWorld();
            if (World)
            {
                FActorSpawnParameters SpawnParams;
                SpawnParams.Owner = this;
                SpawnParams.Instigator = Instigator;
                // Spawn the projectile at the muzzle.
                AFPSProjectile* Projectile = World->SpawnActor<AFPSProjectile>(ProjectileClass, MuzzleLocation, MuzzleRotation, SpawnParams);
                if (Projectile)
                {
                    // Set the projectile's initial trajectory.
                    FVector LaunchDirection = MuzzleRotation.Vector();
                    Projectile->FireInDirection(LaunchDirection);
                }
            }
        }
    }
  5. Save FPSCharacter.cpp in Visual Studio.

  6. Locate FPSProject in the Solution Explorer.

  7. Right-click on FPSProject and select Build to compile your project.

    BuildFPSProject.png

Building the Projectile Blueprint

Before continuing, download and extract our sample mesh from the following link: "Projectile Mesh"

  1. Right-click inside the Content Browser's file box to open the Import Asset dialog box

  2. Click 'Import to /Game...' to open the Import dialog box.

    RightClickImport.png

  3. Locate and select the Sphere.fbx mesh file.

  4. Click Open to begin importing the mesh to your project.

  5. In the Content Browser, the FBX Import Options dialog box appears. Clicking Import adds your mesh to the Project.

    Disregard the following error regarding smoothing groups: FBXWarning.png
    This mesh still illustrates the first person mesh set-up and it will work with the animations you'll set-up in a later section.

  6. Click the Save button to save your imported static mesh.

  7. Navigate back to the Blueprints folder in the Content Browser.

  8. Click the Add New button and select Blueprint Class.

  9. Expand the All Classes dropdown menu and type "FPSProjectile" into the search box.

    AddNewBPClass.png

  10. Click on the FPSProjectile and click the Select button.

  11. Name the new Blueprint "BP_FPSProjectile".

    NameBP_FPSProjectile.png

  12. Double-click the BP_FPSCharacter icon to open it in the Blueprint Editor.

  13. Click on CollisionComponent in the Components tab.

  14. Click on the Add Component dropdown list and select Static Mesh.

    AddStaticMeshComponent.png

  15. Name your new component "ProjectileMeshComponent".

    NameProjectileMeshComponent.png

  16. Scroll down to the Static Mesh section of the Details tab and click on the dropdown menu that says "None".

  17. Select the Sphere static mesh.

    SelectSphereMesh.png

    Note that if you're making a multiplayer game, you'll need to also uncheck "Initial Velocity in Local Space" in the "MovementComp" Component in order for this projectile to replicate correctly over a server.

  18. Set the X, Y, and Z scale values to "0.09".

    Set_XYZ_ScaleValues.png

    Clicking on the lock icon locks all three axes so that they preserve their relative scale.

  19. Set the ProjectileMeshComponent Collision Presets value to NoCollision (since you're using SphereComponent for collision and not this Static Mesh).

    SetCollisionPresets.png

  20. Compile and Save your Blueprint before closing the Blueprint Editor.

  21. Double-click on BP_FPSCharacter to open the character blueprint for editing.

  22. Open Class Defaults Mode.

  23. Locate the Projectile Class property and set it to BP_FPSProjectile.

    SelectProjectileClass.png

  24. Set the MuzzleOffset property to {100, 0, 0} in order to spawn the projectile slightly in front of the camera.

    CharacterProjectileClass.png

  25. Compile and Save your Blueprint before closing the Blueprint Editor.

Shooting Projectiles In-Game

  1. Click the Play In button in the Level Editor Toolbar to shoot projectiles in-game.

  2. Left-click your mouse button to fire projectiles into the world.

    FiringProjectiles.png

  3. Press the Escape key or click the Stop button in the Level Editor to exit Play in Editor (PIE) mode.