関連ブログ
- [UE4][UE5]開発環境の容量を少しでも減らす 2024.08.14UE
- [UE5] PushModel型のReplicationを使い、ネットワーク最適化を図る 2024.05.29UE
- [UE5]マテリアルでメッシュをスケールする方法 2024.01.17UE
CATEGORY
2015.06.12UE4UE/ C++
改訂バージョン: Unreal Engine 4.19 |
UE4に少し慣れてきたプログラマの方に、
「C++でもBlueprintでも実装可能だけれど、どちらを使えばよいのか?」
「何を基準にして、どのように使い分ければよいのか?」
という質問を頂くことが多いです。
今回は、自分がゲームを制作する際の、C++とBPの切り分け方法について書いてみたいと思います。
ゲームプログラムの設計は、プロジェクトの状況やチームメンバーの構成、既存のアセット、ゲーム仕様の要求や使用するミドルウェアによっても大きく影響を受けます。
この記事は、あくまで個人的な考え方であり、参考にして頂けても、絶対的なものではありませんのでご了承下さい。
サテ、まず一番基本的な方針としては、「BPで実現可能なものはBPで実装する」です。
やはり、トライ&エラーの早さ、修正の手軽さの面で、BPの方が素早い開発が行い易いです。
BPの機能はかなりリッチなので、使いこなせば、通常のゲームロジックを組み立てるうえでは、ほとんど不便はありません。
では、C++を使用するケースにはどのような場合があるのか、ですが、分かりやすいものとしては下記のような内容があります。
ただ、このような場合においても、C++で実装するのは最小限の機能単位に留めておき、ゲームのフローやロジックの部分はBP側で実装する方がオススメです。
C++でしか使用出来ない機能をラップし、BPから使用可能なユーティリティを実装して、BPから利用する、というようなイメージです。
ただ、ある程度以上の規模のプロジェクトでは、やはり何か起きた時にはC++の方が・・・という考え方はあります。
C++であれば、何か致命的な問題が起きた際に、最後の最後に自力でどうにか出来る部分が大きいためです。
そのため、例えばキャラクターのアクタを実装するような場合には、下図のようなクラス構成をオススメしています。
C++側で基底クラスを定義し、BP側でそれを継承した基底クラスを作り、さらにそれを継承して個別のキャラクターを実装していく、という方法です。
実際にレベル上に配置されるアクタの具象クラスは、「BP_CharacterA」などになります。
この際にも、AMyCharacterBaseには大きなロジックは、ほとんど何も実装しません。
例えば、
などが、このクラスの役割になります。
後は、最後にどうしようもない大きな問題が起きた際に、C++からアクセスするための窓口として、存在することになります。
「BP_MyCharacterBase」には、キャラクター共通の挙動のほとんどを実装します。
一般的なゲームプログラムでの、キャラクターの基底クラスの役割は、このBPが担うことになります。
あとは、そこから派生した個別のBPで、描画用のメッシュにアセットを設定したり、特定のキャラクターに固有の挙動やパラメータを設定します。
このように、条件分岐や実行順序などのフロー制御は、ほぼBP側で実装してしまい、一部C++でしか記述できない箇所だけを、機能単位でC++で実装してBPに提供する、という方法を、自分はよく取ります。
とはいえ、いつもそんなにキレイにいく訳ではありません。
そこでもう1つ、ココだけでもBPを使った方が良いよ、という箇所を紹介しておきたいと思います。
それは、アセットやBPの型情報にアクセスするような場合です。
一応、C++からでも、
1 |
FindObject<UTexture>(NULL, TEXT("/Game/StarEmblem.StarEmblem")); |
のように、名前からアセットを直接参照したり、
1 2 |
UBlueprint* BulletBP = FindObject<UBlueprint>(NULL, TEXT("/Game/BP_BulletA.BP_BulletA")); GWorld->SpawnActor(BulletBP->GeneratedClass); |
のように、BPで定義されたActorをSpawnしたりも可能なのですが、管理がややこしくなるのと、UE4のワークフローとはあまり相性が良くありません。
通常、予め分かっているアセットをC++から参照したい場合は、C++側のクラスに
1 2 |
UPROPERTY(EditAnywhere, Category=Hoge) UTexture* EmblemTexture; |
1 2 |
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Hoge) TSubclassOf<ABulletBase> BulletBP; |
このような作りにしておくことで、厳しい命名規則に縛られることなく、プログラマの手を離れた場所で新しいキャラクターの実装を進めることが出来ます。のようなプロパティを定義しておき、BP側の具象クラスでココにContentBrowser上から選択したアセットや型情報を設定します。
繰り返しになりますが、この方法が全てのプロジェクトにおいて正解という訳でありません。
しかし、UE4を使用するのであれば、BluePrintの機能を活かさないのは、非常にもったいない選択になります。
この記事が、少しでもUE4導入初期のプロジェクトの助けになれば幸いです。