Skip to content

Unreal Engine 4 Camera part 2: Adding Components

In the previous article of this series on creating a C++ powerful camera for Unreal Engine 4 you created a C++ class with a root Static Mesh component. Today you are going to create a blueprint in unreal Engine based from this C++ class, make your C++ components editable from within the Unreal Editor, and add more components. Let’s get started!

Create a blueprint from the C++ class

You don’t need the blueprint you created from the last episode anymore. Let’s delete it: in your content browser, navigate to the Content/Camera folder and delete B_PlayerCamera.

Now create a new blueprint based on your C++ class. Still in Content Browser, navigate to C++ Classes/TopCamera/Public. Your C++ class is right here, it’s C_PlayerCamera. Right click on it and click on Create Blueprint class.

Name it B_PlayerCamera, select the Content/Camera folder, and click Create Blueprint Class. This creates the blueprint based on your C++ class, and opens it in the blueprint editor.

Make the component editable

As expected the Static Mesh component is a Sphere, cause that’s the asset you loaded.

But you can see 2 problems in the Editor. The name of the StaticMesh is “RootComponent” instead of “CameraTarget” as you specified, and if you click on it the Details panel remains empty. Let’s fix this.

Why is this happening?

Jump to the implementation file (C_PlayerCamera.cpp), and search the line with a call to CreateDefaultSubobject. On the left side of the equal sign you can see that you create the object and allocate it to a local private variable named CameraTarget.

What’s a local private variable?

In the last part of this tutorial we had a close look at variables. Let’s talk today about access specifiers. An access specifier tells if a variable or a function can be accessed or not by other functions and classes. A local private variable is a variable that is accessible only from within the function where it’s created. The program cannot access this variable from another function or another class.

You certainly already been working with access specifiers in Unreal Engine Editor: a variable’s access can be specified by using the small closed/open eye icon and the Instance Editable option.

In C++, access specifiers also apply to functions and classes. Access specifier is a basic concept of object oriented programming, and we’ll come back to it often. For now I advise to check this documentation.

So, to sum up, the CameraTarget variable is private, hence the Unreal Editor cannot access it. That is the reason why the Details panel remains empty when you click on the Static Mesh component. To fix it you need to set the CameraTarget variable “protected”.

Make CameraTarget protected

1. Declare the protected variable

Open the declaration file. For reminder it’s the C_PlayerCamera.h file which is used to declare all members of the class. That’s where we are going to create the protected CameraTarget variable.

Go to the bottom of the class declaration block, after the line virtual void BeginPlay() override; and add the following code:

// StaticMesh root component
UPROPERTY(BlueprintReadWrite, VisibleDefaultsOnly, Category = "")
UStaticMeshComponent* CameraTarget;

As this code is under a protected: keyword (look few lines above to see it), the variable CameraTarget is set protected. Yep, it’s that simple.

The UPROPERTY line is called a macro, and is specific to Unreal Engine. It is defining specifically how the variable is accessible from the Editor panels (i.e displayed and editable in the Detail panel).

2. Use the protected variable

Now go to the implementation file, and look at the line UStaticMeshComponent* CameraTarget = CreateDefaultSubobject<UStaticMeshComponent>(TEXT(“CameraTarget”));. You need to tell to the program to use the protected variable declared in the header file instead of creating a local private variable, so change the line to:

CameraTarget = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CameraTarget"));

So you only removed UStaticMeshComponent* from the beginning of the line. This was the part that was instructing the program to create a new local variable to store the UStaticMeshComponent object (actually it’s a pointer, but we’ll clarify this later). Without it, the program is searching for something already existing with the name CameraTarget, and find the protected variable you just declared. It’s this very same variable Unreal Editor is going to access.

3. Move the include directive

As per those modifications, you are now using the UStaticMeshComponent class in the header file, so you need to move the include directive accordingly. Remove the following line from C_PlayerCamera.cpp and add it to C_PlayerCamera.h, just before the line #include “C_PlayerCamera.generated.h”:

#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"

The include directive works in cascade. When you include a file A, which includes files B and C, then you are implicitly including files A, B and C.

In our case, if you look at the top of your C_PlayerCamera.cpp implementation file you can see the line #include “C_PlayerCamera.h”. So you are including the C_PlayerCamera.h header file along with every files it includes (plus every files those files include, and so on). And that’s the reason why if you include a class declaration in your header file you do not need to include it in your definition file.

Take some time to read another documentation about include directive.

4. Compile

From the menu Build click on Build Solution, or press Ctrl+Shift+B. Anyhow, you have to always do this after modifying the code, so put it in your muscle memory.

Refresh the blueprint

Back in Unreal Engine in the blueprint editor, click in the File menu on Refresh All Nodes. This is reloading external changes, including the modification you made to the C++ class. Now CameraTarget component has a correct name, and clicking on it shows all properties in the Detail panel. Success!

Don’t miss any important update, subscribe to the newsletter. I hate spam as much as you do, and I’ll never share your data.

Add 2 components in the blueprint

Now the bug is fixed, it’s time to add more components. Let’s follow the same process: perform your changes in the blueprint first, visually adjusting your settings to your needs, then when satisfied implement those in your C++ class.

In the Components panel, add a SpringArm component as a child of CameraTarget, then add a Camera as a child of the SpringArm.

Click in the Components panel on SpringArm, then in Details panel set Z Location to 50.0, Y Rotation to -80.0 and TargetArm Length to 2500.0

Add 2 components in the C++ class

Yeah, I gave you the values for the SprintArm properties. But when you’ll be working on your own projects you’ll be playing around with those properties before you can find the right settings, so it will make sense to proceed by creating a blueprint first before typing code. Anyhow, let’s replicate the creation of your 2 components in the C++ class.

Creating the SprintArm

Learning from the previous experience, you know you have to make SpringArm a protected variable. Let’s start by editing the header file. After the line UStaticMeshComponent* CameraTarget; add the following code:

// Camera's spring arm
UPROPERTY(BlueprintReadWrite, VisibleDefaultsOnly, Category = "")
USpringArmComponent* SpringArm;

Obviously you need to include the header file that declares the USpringArmComponent class. Just before the line #include “C_PlayerCamera.generated.h” add the following code:

#include "GameFramework/SpringArmComponent.h"

Now open your implementation file, and at the end of the constructor add the following code:

// Camera's spring arm
SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
SpringArm->SetupAttachment(RootComponent);
SpringArm->SetRelativeLocation(FVector(0.f, 0.f, 50.f));
SpringArm->RelativeRotation = FRotator(-80.f, 0.f, 0.f);
SpringArm->TargetArmLength = 2500.f;

This piece of code contains few new things, and I’m going to explain to you what’s going on here. Though you should be able to search from more information by yourself using Unreal Engine search page if you need more details.

The first line is creating an object from the class USpringArmComponent. The resulting object is stored in the SpringArm protected variable you declared earlier in the header file.

The second line is attaching the SpringArm as the child of the CameraTarget component, which is referenced through the member RootComponent.

The third, the fourth and the fifth lines are setting the SpringArm properties similarly to what you did in the blueprint. FVector and FRotator are constructors to create a Vector (3D space coordinate container) and a Rotator (Pitch, Yaw and Roll data container).

Creating the Camera

Adding the Camera component is very similar from what you did for the SpringArm.

Try doing it by yourself. Search the Unreal Engine documentation for which classes to use, and try to replicate what you did for the other components. When you are done resume reading from here to check if you did well.

In C_PlayerCamera.h, add the following include directive before the line #include “C_PlayerCamera.generated.h”:

#include "Runtime/Engine/Classes/Camera/CameraComponent.h"

Then after the SpringArm variable declaration, add the following code:

// Player's camera
UPROPERTY(BlueprintReadWrite, VisibleDefaultsOnly, Category = "")
UCameraComponent* Camera;

In C_PlayerCamera.cpp, at the end of the constructor, add the code:

// Player's camera
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);

Final Look

Here are how the 2 files of your C_PlayerCamera class should look at the end. C_PlayerCamera.h:

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "Runtime/Engine/Classes/Components/StaticMeshComponent.h"
#include "GameFramework/SpringArmComponent.h"
#include "Runtime/Engine/Classes/Camera/CameraComponent.h"
#include "C_PlayerCamera.generated.h"

UCLASS()
class TOPCAMERA_API AC_PlayerCamera : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values for this pawn's properties
    AC_PlayerCamera();

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

    // StaticMesh root component
    UPROPERTY(BlueprintReadWrite, VisibleDefaultsOnly, Category = "")
    UStaticMeshComponent* CameraTarget;

    // Camera's spring arm
    UPROPERTY(BlueprintReadWrite, VisibleDefaultsOnly, Category = "")
    USpringArmComponent* SpringArm;

    // Player's camera
    UPROPERTY(BlueprintReadWrite, VisibleDefaultsOnly, Category = "")
    UCameraComponent* Camera;

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

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

C_PlayerCamera.cpp:

#include "C_PlayerCamera.h"
#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h"

// Sets default values
AC_PlayerCamera::AC_PlayerCamera()
{
    // Set this pawn to call Tick() every frame. You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

    // Load Shape_Sphere from the StarterContent
    FString assetPath = FString(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
    static ConstructorHelpers::FObjectFinder<UStaticMesh> shapeSphereAsset(*assetPath);

    // StaticMesh root component
    CameraTarget = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CameraTarget"));
    RootComponent = static_cast<USceneComponent*>(CameraTarget);
    CameraTarget->SetCollisionProfileName(TEXT("NoCollision"));

    // Assign the shape to ourStaticMesh
    if (shapeSphereAsset.Succeeded())
    {
        CameraTarget->SetStaticMesh(shapeSphereAsset.Object);
    }
    // Log an error if the path cannot be found
    else
    {
        UE_LOG(LogScript, Error, TEXT("%s%s"), TEXT("Cannot load shape asset from path: "), *assetPath);
    }

    // Camera's spring arm
    SpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("SpringArm"));
    SpringArm->SetupAttachment(RootComponent);
    SpringArm->SetRelativeLocation(FVector(0.f, 0.f, 50.f));
    SpringArm->RelativeRotation = FRotator(-80.f, 0.f, 0.f);
    SpringArm->TargetArmLength = 2500.f;

    // Player's camera
    Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
    Camera->SetupAttachment(SpringArm, USpringArmComponent::SocketName);
}

Refresh and test the blueprint

Build Solution, then back in Unreal Engine in the blueprint editor, click in the File menu on Refresh All Nodes.

You should see 2 sets of SpringArm-Camera child attached to the CameraTarget root. Delete the SpringArm and the Camera that are not “Inherited”. Then compile the blueprint and check if all your settings (the length, angle and position of the SpringArm) are correctly set.

Conclusion

You’ve learned how to import your C++ class as a blueprint, learned about C++ access specifiers, declared variables protected and made them editable in Unreal Engine editor, created more components, and add properties to components.

In the next episode we will start to make the class reusable by making the SpringArm properties editable in Unreal Engine editor through class default properties.

Share this story
Published inTutorials

Be First to Comment

    Leave a Reply

    Your email address will not be published. Required fields are marked *