概要
この記事では、今年2023年に新卒ゲームプログラマとして働き始めた、UE初心者である筆者が、8ヶ月間Unreal Engine5を使用してきた中で「最低でもこれさえ使えれば大丈夫」と感じた、UPROPERTYとUFUNCTIONをまとめて、紹介させていただきます。
この記事の主な対象者
- Unreal EngineのC++初心者の方
UPROPERTY
EditAnywhere
UPROPERTY( EditAnywhere )
Blueprintのエディタの詳細パネルと、レベルに配置したアクタの詳細パネルの両方で、値を編集することができます。
レベルに配置したアクタの詳細パネルの方で値を変更すれば、レベルに配置したアクタごとに、異なる値を設定することができます。
例)
UPROPERTY( EditAnywhere )
int TestNum = 0;
EditDefaultsOnly
UPROPERTY( EditDefaultsOnly )
Blueprintのエディタの詳細パネルからのみ、値を編集することができます。
そのため、EditAnywhereとは違い、レベルに配置したアクタごとに異なった値を設定することはできず、レベルに配置したアクタにはBlueprintで設定した同じ値が設定されます。
Widgetなどのレベルに配置することができないオブジェクトに保持させる変数や、レベルに配置したアクタに統一した値が入っていたほしい変数などには、「EditDefaultsOnly」で良いと思います。
VisibleAnywhere
UPROPERTY( VisibleAnywhere )
Blueprintのエディタの詳細パネルと、レベルに配置したアクタの詳細パネルの両方で、値を確認することができます。
下画像の、赤丸の値のところが少し灰色になっていることからおわかりかもしれませんが、編集することはできません。
Blueprintの方からは値を編集してほしくはないけど、C++でどのような値を設定していたかをBlueprintで確認できるようにしておきたいというような変数に「VisibleAnywhere」をつけると良いと思います。
例)
UPROPERTY( VisibleAnywhere )
int TestNum = 0;
BlueprintReadWrite
UPROPERTY( BlueprintReadWrite )
Blueprintのイベントグラフで、値の読み込み処理と、書き込み処理の両方を行うことができます。
Blueprintのイベントグラフで値を変更する必要のある変数に「BlueprintReadWrite」をつけると良いのですが、むやみにつけない方が良いです。
「BlueprintReadWrite」をむやみにつけると、デバッグの際に「BlueprintReadWrite」を付けた変数に関しては、C++とBlueprintの両方を確認する必要が出てくるので、デバッグ作業が大変になります。
例)
UPROPERTY( BlueprintReadWrite )
int TestNum = 0;
BlueprintReadOnly
UPROPERTY( BlueprintReadOnly )
Blueprintのイベントグラフで、値の読み込み処理ができます。
「BlueprintReadOnly」と同様に、むやみにつけない方が良いです。
SetやGetができるクラスのポインタを格納したTObjectPtrなどに「BlueprintReadOnly」をつけると、「BlueprintReadWrite」を付けた場合と同じくらい、デバッグ作業が大変になります。
例)
UPROPERTY( BlueprintReadOnly )
int TestNum = 0;
ClampMin, ClampMax
UPROPERTY( meta = (ClampMin = "[最小値]", ClampMax = "[最大値]") )
数値の変数の値の、最小値と最大値を設定することができます。
特に、Blueprintのエディタから編集することができる「EditAnywhere」や「BlueprintReadWrite」などがついている変数には「ClampMin, ClampMax」をつけたほうが良いです。
Blueprintのエディタから値を設定することができる変数などには、プログラマ以外の方が触れる可能性があり、想定していない値が入る可能性が特に高いからです。
例)
UPROPERTY( meta = (ClampMin = "0", ClampMax = "100") )
float TestPercentage = 0.0f;
このようにすると、変数「TestPercentage」に0未満の値が設定されると0が設定されている状態になり、100より大きい値が設定されると100が設定されている状態になります。
AllowPrivateAccess
UPROPERTY( meta = (AllowPrivateAccess = "true") )
private変数に「BlueprintReadWrite」や「BlueprintReadOnly」をつけると、コンパイルエラーが発生しますが「AllowPrivateAccess」をつけると、コンパイルエラーが発生しなくなります。
しかし、「AllowPrivateAccess」の利用はかなり注意が必要です。理由は、「AllowPrivateAccess」をつけることにより、Blueprintではpublic変数になってしまうからです。
例えば「TestActor」というクラスに、下のような変数を作成します。
private:
UPROPERTY( meta = (AllowPrivateAccess = "true") )
int TestNum = 0;
レベルブループリントに、TestActorをスポーンする処理を書き、スポーンしたアクタのインスタンスから呼び出すことができる関数を確認します。
上の画像のように、private変数のはずの「TestNum」が、Blueprintのエディタからはインスタンスから直接編集できるようになってしまっています。
private変数をBlueprintで扱う際は、注意しましょう。
Category
UPROPERTY( Category = "[カテゴリ名]" )
変数の、Blueprintエディタの詳細パネル上のカテゴリを指定することができます。
例)
UPROPERTY( EditAnywehre, Category = "TestCategory" )
int TestNum = 0;
カテゴリ名にプロジェクト名などをつけると、プログラムで作って公開している変数をすぐに見つけることができるようになります。
BindWidgetOptional
UPROPERTY( meta = (BindWidgetOptional) )
「BindWidgetOptional」をつけた変数を持つ変数名と同じ名前のWidgetのポインタを取得することができます。
例)
ウィジェットブループリントを作成し、構成が下のようにします。
上の画像のテキストブロックウィジェットの名前を「TestText」にします。
このウィジェットブループリントの親クラスとして設定するクラスに、下のような変数を作成します。
UPROPERTY( meta = (BindWidgetOptional) )
TObjectPtr<UTextBlock> TestText = nullptr;
上の画像のようにすると、変数「TestText」には、ウィジェットブループリントに作成したテキストブロックウィジェットのポインタが格納され、変数「TestText」からウィジェットの文字を変えることができたりします。
ウィジェットブループリントに該当する名前のウィジェットが見つからなければ、「BindWidgetOptional」をつけた変数には nullptr が格納されます。
BindWidget
UPROPERTY( meta = (BindWidget) )
基本的には「BindWidgetOptional」と同じですが、ウィジェットブループリントに該当する名前のウィジェットが見つからなければ、ウィジェットブループリントでコンパイルエラーが発生します。
下記は、エラーの例です。
UPROPERTY( meta = (BindWidget) )
TObjectPtr<UTextBlock> TestText = nullptr;
上の変数の名前と同じ、テキストブロックウィジェットがないと、Blueprint上で下図のようなコンパイルエラーが発生します。
UFUNCTION
BlueprintCallable
UFUNCTION( BlueprintCallable )
Blueprint
BlueprintImplementableEvent
UFUNCTION( BlueprintImplementableEvent )
「BlueprintImplementableEvent」をつけた関数は、Blueprint上でのみ実装を行うことができるようになります。
「BlueprintImplementableEvent」をつけた関数をC++で定義すると、コンパイルエラーが発生するので、実装はBlueprint上でのみ行うようにしましょう。
また、private関数に「BlueprintImplementableEvent」をつけても、コンパイルエラーが発生するので、public変数やprotected変数にしましょう。
例)
public:
UFUNCTION( BlueprintImplementableEvent )
void SayHello();
実装する際は、最初にBlueprintエディタのマイブループリントパネルの関数の「オーバーライド」のところをクリックします。
そのようにすると、下図のように「BlueprintImplementableEvent」をつけた関数が、表示されたリストの中にあるので、それをクリックします。
そうすると、関数のイベントノードがイベントグラフに追加されるので、そのイベントノードを用いて実装を行いましょう。
BlueprintNativeEvent
UFUNCTION( BlueprintNativeEvent )
「BlueprintNativeEvent」をつけると、一部をC++で実装、一部をBlueprintで実装というようなことができるようになります。
例)
C++で、下のような変数と関数を作ります。
(TestActor.hファイル)
public:
UFUNCTION( BlueprintNativeEvent, BlueprintCallable )
void SayHello();
virtual void SayHello_Implementation();
public:
UPROPERTY( BlueprintReadOnly )
FString TextToSay = "";
(TestActor.cppファイル)
void ATestActor::SayHello_Implementation()
{
TextToSay = "Hello";
}
C++の方で行いたい処理は、「[元の関数名]_Implementation」という名前の関数を作り、そちらの関数に処理を実装します。「[元の関数名]_Implementation」という名前の関数には、virtualをつけて、仮想関数にするようにします。
Blueprintのエディタでは、マイブループリントパネルの関数の「オーバーライド」のところをクリックし、「SayHello」をクリックします。
イベントグラフに関数名のイベントノードが追加されるので、イベントノードを右クリックし「親関数への呼び出しを追加」をクリックします。クリックすると、オレンジ色のノードが追加されます。そのノードでは、C++で書いた「SayHello_Implementation」関数で実装した処理を行われます。
下図のようにノードを組みます。
ゲームをプレイすると、C++で文字列に追加した「Hello」と、Blueprintで文字列に追加した「 World」がつながって表示されます。
以上でUPROPERTY、UFUNCTIONの紹介は終了です。
最後まで読んでいただき、ありがとうございました。