Unreal Engine (UE)での 開発において、C++ はパフォーマンスが求められる処理や複雑なゲームロジックの中核を担い、Blueprint は迅速なプロトタイピングやデザイナーによる直感的なロジック構築を可能にする、まさに両輪の関係にあります。
しかし、多くの初心者や中級者が直面する課題があります。それは、「C++で書いた便利な関数や変数を、どうすればBlueprintから簡単に、安全に呼び出せるのか? 」という点です。せっかくC++で効率的なコードを書いても、Blueprintから使えなければ、その恩恵を十分に受けられません。
本記事では、このC++とBlueprintの連携をスムーズに行うための核となる仕組み、特にUFUNCTION とUPROPERTY マクロの使い方に焦点を当て、具体的なコード例とベストプラクティスを交えて徹底的に解説します。この記事を読めば、あなたのUE開発の幅が格段に広がるでしょう。
UCLASS・UFUNCTION・UPROPERTYの概要
C++のコードをBlueprintの世界に公開するためには、Unreal Engineのリフレクションシステム にその存在を教える必要があります。この役割を果たすのが、UCLASS、UFUNCTION、UPROPERTYといった特別なマクロ群です。
UCLASS: クラスの登録
まず、Blueprintからアクセスしたいクラスには、必ずUCLASS()マクロを付与する必要があります。これは、そのクラスがUEのリフレクションシステムによって追 跡・管理されるべきであることを示します。
// MyActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"
UCLASS() // このマクロが必須
class MYPROJECT_API AMyActor : public AActor
{
GENERATED_BODY()
public:
AMyActor();
};
UPROPERTY: 変数の公開
C++で定義した変数をBlueprintから参照したり、編集したりできるようにするには、その変数にUPROPERTY()マクロを付与します。このマクロの引数(指定子)によって、Blueprintでの振る舞いを細かく制御できます。
| 指定子 | 意味 | Blueprintでの振る舞い |
|---|---|---|
EditAnywhere | どこからでも編集可能 | 詳細パネルで編集可能(インスタンス、デフォルト) |
BlueprintReadOnly | Blueprintから読み取り専用 | Blueprintグラフで値の取得ノードが生成される |
BlueprintReadWrite | Blueprintから読み書き可能 | Blueprintグラフで値の取得/設定ノードが生成される |
VisibleAnywhere | どこからでも参照可能 | 詳細パネルで値の参照のみ可能 |
Category = "My Category" | 詳細パネルでの表示カテゴリ | カテゴリ分けされ、整理しやすくなる |
コード例(UPROPERTY):
// MyActor.h
// ...
UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// Blueprintから読み書き可能で、詳細パネルで編集できる変数
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
float Health = 100.0f;
// Blueprintから読み取り専用の変数
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Stats")
int32 MaxAmmo = 30;
};
UFUNCTION: 関数の公開
C++で実装したロジックをBlueprintから呼び出すには、その関数にUFUNCTION()マクロを付与します。
| 指定子 | 意味 | Blueprintでの振る舞い |
|---|---|---|
BlueprintCallable | Blueprintから呼び出し可能 | 標準的な関数ノードとして利用可能 |
BlueprintPure | 純粋関数(Pure Function)として呼び出し可能 | 実行ピンがなく、戻り値のみを持つノードとして利用可能(状態を変更しない関数に推奨) |
BlueprintImplementableEvent | C++で宣言し、Blueprintで実装するイベント | Blueprintでイベントノードとしてオーバーライド可能 |
BlueprintNativeEvent | C++でデフォルト実装を持ち、Blueprintでオーバーライド可能 | C++とBlueprintの両方で実装を持つことができる |
コード例(UFUNCTION):
// MyActor.h
// ...
UCLASS()
class MYPROJECT_API AMyActor : public AActor
{
GENERATED_BODY()
public:
// 1. Blueprintから呼び出し可能な関数
UFUNCTION(BlueprintCallable, Category = "Combat")
void ApplyDamageToHealth(float DamageAmount);
// 2. Blueprintから呼び出し可能な純粋関数(Pure Function)
UFUNCTION(BlueprintPure, Category = "Stats")
float GetHealthPercentage() const;
// 3. Blueprintで実装するイベント
UFUNCTION(BlueprintImplementableEvent, Category = "Events")
void OnHealthDepleted();
};
コード例(UFUNCTIONの実装):
// MyActor.cpp
// ...
void AMyActor::ApplyDamageToHealth(float DamageAmount)
{
Health = FMath::Max(0.0f, Health - DamageAmount);
if (Health <= 0.0f)
{
// Blueprintで実装されたイベントを呼び出す
OnHealthDepleted();
}
}
float AMyActor::GetHealthPercentage() const
{
// MaxHealthをUPROPERTYで定義していないため、ここでは仮に100.0fで割る
return Health / 100.0f;
}
Blueprintでの利用方法
上記のC++コードをコンパイルした後、エディタに戻り、AMyActorを継承したBlueprintクラスを作成すると、C++で公開した機能が自動的に利用可能になります。
変数(UPROPERTY)の利用
-詳細パネル: EditAnywhereやVisibleAnywhereを指定した変数は、Blueprintインスタンスの詳細パネルの「Stats」カテゴリに表示され、値を編集・参照できます。
-グラフ: BlueprintReadWriteやBlueprintReadOnlyを指定した変数は、Blueprintグラフ内で右クリックメニューから「Get Health」や「Set Health」といったノードとして検索・利用できます。
関数(UFUNCTION)の利用
-呼び出し: ApplyDamageToHealth関数は、Blueprintグラフ内で右クリックメニューから「Apply Damage To Health」ノードとして検索し、実行ピンを繋いで呼び出すことができます。
💡 関数名の衝突に注意
C++で関数を定義する際、
TakeDamageのような名前はAActorクラスに既に存在するため、衝突や意図しないオーバーライドが発生する可能性があります。独自の機能にはApplyDamageToHealthのように、より具体的で一意な名前を付けることをお勧めします。
-純粋関数: GetHealthPercentage関数は、実行ピンなしで、戻り値ピンを直接他のノードに繋いで利用できます。
-イベント: OnHealthDepletedイベントは、Blueprintグラフ内で右クリックメニューから「Event On Health Depleted」ノードとして検索し、イベント発生時の処理を実装できます。
ベストプラクティスとよくある間違い
C++とBlueprintの連携を円滑にするために、以下の点に注意しましょう。
ベストプラクティス
- BlueprintPureの活用: 状態を変更しない、単に値を計算して返すだけの関数には、必ず
BlueprintPureを指定しましょう。これにより、Blueprintグラフが実行ピンで煩雑になるのを防ぎ、データフローが視覚的に分かりやすくなります。 - Category指定:
UPROPERTYやUFUNCTIONには、必ずCategory = "..."を指定しましょう。Blueprintの右クリックメニューや詳細パネルでの検索性が向上し、整理された状態を保てます。 - ロジックの分離: パフォーマンスが重要な処理や複雑なアルゴリズムはC++で実装し、それらを呼び出すタイミングや、デザイナーが調整するパラメータの制御はBlueprintに任せる、という役割分担を徹底しましょう。
よくある間違い
- マクロの付け忘れ:
UCLASS、UFUNCTION、UPROPERTYマクロを付け忘れると、リフレクションシステムに登録されず、Blueprintから一切アクセスできなくなります。特に、ヘッダーファイルにマクロを記述し、.generated.hファイルが正しくインクルードされているか確認してください。 - 引数の型: BlueprintでサポートされていないC++の型(例:標準ライブラリのコンテナなど)を関数の引数や戻り値に使用すると、Blueprintノードが生成されません。UE独自の型(
FString,TArray,TMapなど)を使用しましょう。 - constの利用: 状態を変更しない関数に
BlueprintPureを指定する場合、C++側でもconst修飾子 を付けるのが一般的です。これは、その関数がオブジェクトの状態を変更しないことを保証するC++のベストプラクティスです。
C++とBlueprint連携のポイント
Unreal EngineにおけるC++とBlueprintの連携は、UFUNCTIONとUPROPERTYマクロによって実現されています。
| 要素 | マクロ | 主な役割 | Blueprintでの利用 |
|---|---|---|---|
| 変数 | UPROPERTY | 変数をリフレクションシステムに登録し、Blueprintからのアクセス権限を設定する。 | 詳細パネルでの編集、Get/Setノードの利用。 |
| 関数 | UFUNCTION | 関数をリフレクションシステムに登録し、Blueprintからの呼び出し方法を設定する。 | 実行可能なノード、または純粋関数ノードとして利用。 |
この連携をマスターすることで、C++のパフォーマンスとBlueprintの柔軟性を最大限に引き出し、効率的でメンテナンス性の高いゲーム開発が可能になります。まずはシンプルな機能から、積極的にC++の機能をBlueprintに公開してみてください。