【Unreal Engine】Migrating from Blueprint to C++: Creating Your First C++ Class

Created: 2025-12-12

Once comfortable with Blueprint, you may want to explore C++. Learn UCLASS, UPROPERTY, UFUNCTION basics, and integration methods using BlueprintImplementableEvent.

The Need for C++ Migration

Many people starting to learn Unreal Engine (UE) likely begin with Blueprint, which can be operated intuitively. Blueprint, a node-based visual scripting system, is a powerful tool for quickly building game logic without programming knowledge. However, as development progresses, haven't you faced challenges like these?

  • Performance Limits: When performing complex calculations or large amounts of processing, Blueprint can become slow.
  • Management Difficulty in Large Projects: Nodes become complexly tangled, reducing readability and maintainability.
  • Deep Access to Engine Features: C++ is needed for low-level engine features and integration with external libraries.

To solve these challenges and aim for more advanced, optimized game development, migration to C++ is an inevitable path. C++ is the foundational language of UE, providing control and performance levels that Blueprint cannot achieve. This article targets intermediate developers with Blueprint experience, explaining concrete steps for smooth migration to C++ development and integration methods between the two.


Step 1: Understand Blueprint and C++ Role Division

When starting C++ development, you don't need to completely abandon Blueprint. The best practice for UE development is implementing foundational logic and performance-critical processing in C++, then using Blueprint to extend those C++ features or build settings and events that designers and level artists can easily handle.

FeatureBlueprint (Visual Scripting)C++ (Programming Language)
Execution SpeedSlower than C++ (executes as Blueprint bytecode)Fast (compiles to native code)
Access LevelLimited to portion of engine featuresFull access to entire engine, low-level features
Learning CurveGentle, intuitiveSteep, requires programming knowledge
Use CasesPrototyping, UI logic, data settings, artist-facing eventsGame core logic, complex calculations, performance-critical parts

About Blueprint Execution Speed

Blueprint is indeed slower than C++, but for normal game logic (event handling, UI operations, simple calculations), there's almost no perceptible difference. Performance differences become problematic with complex processing executed every frame or handling large numbers of objects. Rather than "it's slow so migrate everything to C++," the efficient approach is to C++ify only the bottleneck portions.


Step 2: Creating C++ Classes and Basic Structure

To start C++ development in UE, first create a new C++ class from the editor.

1. Creating a C++ Class

From the editor's "File" > "New C++ Class...", select a parent class and create. Common parent classes include Actor, Pawn, Character, etc.

2. Basic C++ Code Structure

The created C++ files (e.g., MyCppActor.h and MyCppActor.cpp) contain UE-specific macros.

MyCppActor.h (Header File)

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyCppActor.generated.h" // File where UE-specific macros are expanded

UCLASS() // Macro indicating this class is registered with UE's object system
class MYPROJECT_API AMyCppActor : public AActor
{
    GENERATED_BODY() // Macro generating class boilerplate code

public:
    // Constructor
    AMyCppActor();

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

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

    // Define function callable from Blueprint
    UFUNCTION(BlueprintCallable, Category = "My Functions")
    void PrintMessage(FString Message);
};

MyCppActor.cpp (Source File)

#include "MyCppActor.h"

AMyCppActor::AMyCppActor()
{
    // Setting to call Tick function every frame
    PrimaryActorTick.bCanEverTick = true;
}

void AMyCppActor::BeginPlay()
{
    Super::BeginPlay();

    UE_LOG(LogTemp, Warning, TEXT("C++ Actor Started!"));
}

void AMyCppActor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);
}

void AMyCppActor::PrintMessage(FString Message)
{
    // Log output
    UE_LOG(LogTemp, Log, TEXT("Message from Blueprint: %s"), *Message);
}

Technical Terms: UE-Specific Macros

  • UCLASS() / USTRUCT() / UENUM(): Essential macros for registering classes, structs, and enums with UE's reflection system. These enable editor display, serialization (save/load), and Blueprint access.
  • GENERATED_BODY(): Macro indicating where UE's build system inserts generated code (constructors, reflection information, etc.).
  • UPROPERTY(): Registers member variables with reflection system, enabling editor editing and Blueprint access.
  • UFUNCTION(): Registers member functions with reflection system, enabling Blueprint calls and timer registration.

Step 3: Integration with Blueprint (UPROPERTY and UFUNCTION)

Making C++-defined variables and functions usable from Blueprint is the most important step in migrating from Blueprint. Use UPROPERTY and UFUNCTION macros.

1. Blueprint-Accessible Variables (UPROPERTY)

Add specifiers like EditAnywhere or BlueprintReadOnly to UPROPERTY macro to control behavior in Blueprint and editor.

// MyCppActor.h
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Configuration")
float MovementSpeed = 500.0f; // Read/write from editor and Blueprint

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Status")
int CurrentHealth = 100; // Read-only from editor and Blueprint

2. Blueprint-Callable Functions (UFUNCTION)

Specifying BlueprintCallable in UFUNCTION macro makes the function callable as a Blueprint node.

// MyCppActor.h
UFUNCTION(BlueprintCallable, Category = "Combat")
void ApplyDamageToActor(float DamageAmount);

// Note: TakeDamage name already exists in AActor,
// so use a different name for custom functions or implement as override

Implementation Example: Damage Processing

// MyCppActor.cpp
void AMyCppActor::ApplyDamageToActor(float DamageAmount)
{
    CurrentHealth -= FMath::RoundToInt(DamageAmount);
    UE_LOG(LogTemp, Log, TEXT("Took %f damage. Health remaining: %d"), DamageAmount, CurrentHealth);

    if (CurrentHealth <= 0)
    {
        // Handle complex death logic in C++...
        UE_LOG(LogTemp, Warning, TEXT("Actor Died!"));
    }
}

This ApplyDamageToActor function can be called as a node from Blueprint's event graph, executing performance-critical damage calculation on the C++ side while making results available to Blueprint.


Common Mistakes and Best Practices

Common Mistakes

  1. Implementing same processing in both Blueprint and C++: Concentrate logic on one side, let the other focus on calls and settings.
  2. Writing too much Blueprint logic in C++ header files: C++ header files (.h) should define only minimal interface needed for Blueprint access (UPROPERTY, UFUNCTION), concentrate implementation in (.cpp).
  3. Fearing compile errors: C++ requires compilation so errors appear more than Blueprint, but reading error messages deepens understanding of UE's internal structure.

Best Practices

  • Position C++ as "foundation," Blueprint as "extension": Create performance-critical core systems and highly reusable components in C++, inherit/extend those to implement specific gameplay logic in Blueprint.
  • Use BlueprintImplementableEvent: Use when defining events in C++ where "I want to delegate processing to Blueprint at this timing."
// MyCppActor.h
UFUNCTION(BlueprintImplementableEvent, Category = "Events")
void OnDeath(); // Called in C++, implemented in Blueprint
// MyCppActor.cpp
void AMyCppActor::TakeDamage(float DamageAmount)
{
    // ... (damage processing)
    if (CurrentHealth <= 0)
    {
        OnDeath(); // Call Blueprint-implemented event
    }
}

Key Points for C++ Migration

Migrating from Blueprint to C++ is an important step for elevating your skills as an Unreal Engine developer.

  1. Understand Role Division: C++ for performance and foundation, Blueprint for flexible extension and settings.
  2. Master Basic Structure: Understand UE-specific macros like UCLASS, GENERATED_BODY, UPROPERTY, UFUNCTION.
  3. Establish Integration: Master BlueprintCallable and BlueprintImplementableEvent to maximize the strengths of both C++ and Blueprint.

It may feel difficult at first, but mastering C++ will allow your Unreal Engine project to evolve larger and higher-performance. We recommend starting with simple Actor classes, gradually expanding scope.