|
執筆バージョン: Unreal Engine 5.7
|
今回はフラグ管理方法の一つ、「ビットフラグ」に関して UnrealEngine での取り扱い方法を解説します。
〇前提
ゲーム開発でフラグを管理するのであればビットフラグを利用するのが当たり前!といった時代もありましたが、今では必ずしもそうではありません。
とはいえ、1つの変数だけで複数のフラグを管理したい!となると、やはり今でもビットフラグで実装するのが楽だな…となるケースもあるかと思います。
UnrealEngineでも、ブループリントでビットフラグを扱う事ができますが、今回はプログラマがC++を使ってビットマスクを実装し、非プログラマがエディタ上でフラグを設定するシチュエーションを前提に、ビットマスクの実装方法と使い方を解説していきたいと思います。
ちなみに全てをブループリント側で実装する事ももちろん可能です。
今回は例として、探索パート、バトルパート、イベントパートなど、複数のパートが存在するRPGで、それらを各モードとして切り分けた場合、特定のモードの時にアクティブ状態になるアクターの実装方法をご紹介します。
探索パートとイベントパートでは動かしたいが、バトルパートでは動かしたくない、といったアクターの有効無効を切り替える際に便利になるかと思います。
〇C++でビットフラグ用の列挙体と変数を用意
まずは、各フラグ用のenum、今回だと各パートを示すフラグを用意します。
|
|
UENUM( BlueprintType, meta = ( Bitflags, UseEnumValuesAsMaskValuesInEditor = "true" ) ) enum class EPlayModeUsageFlags : uint8 { PlayMode_None = 0 UMETA( Hidden ), PlayMode_Exploration = 1 << 0 UMETA(DisplayName = "探索"), PlayMode_Battle = 1 << 1 UMETA(DisplayName = "バトル"), PlayMode_Event = 1 << 2 UMETA(DisplayName = "イベント"), PlayMode_All = PlayMode_Exploration | PlayMode_Battle | PlayMode_Event UMETA( Hidden ) // 全てのモードで有効 }; ENUM_CLASS_FLAGS( EPlayModeUsageFlags ) |
enumの各列挙子の値は、ビットでの指定になります。
ちなみに今回はブループリントでの使用を前提としているため、Unrealの仕様の関係上「BlueprintType」にしたいのでuint8でのenum宣言になります。そのためフラグは最大8個までしか定義できないため、注意が必要です。
そして今回ポイントとなるのは、UENUMの中のメタデータ指定子です。「Bitflags」を指定する事で、後述する「Bitmask」のメタデータを指定したUPROPERTYの整数によって、このenumをビットフラグとして扱える事を意味しています。
また、その時にエディタ上でビットフラグとして設定できるように「UseEnumValuesAsMaskValuesInEditor」を「true」にしておく必要があります。これを指定しないと、エディタ上では enum の並び順(0,1,2…)がビット値として解釈されてしまい、enum側で指定したビット値と一致しなくなります。
最後に「ENUM_CLASS_FLAGS」に用意したenumを指定します。これにより、このenumに対してビット演算子(|や&)やEnumHasAnyFlagsなどのユーティリティ関数が使用可能になります。
これでenumの宣言は完了です。
また、テクニックの一つとして、変数の初期化用にPlayMode_Noneや、全部のフラグで有効な場合のPlayMode_Allを用意しておくと便利です。とくにPlayMode_Allのようなenumは、用意しておくと今後新しいモード(チュートリアルパートや、カットシーン、メニューなど)が増えた時に、全モードでフラグを立てたい場合に対応が楽になります。ただし、利便性のための定義であり自動生成ではないので、新しくモードを追加した場合は、PlayMode_Allも忘れずに更新するよう注意してください。
次に、アクター側にフラグ用の変数を用意します。
|
|
UPROPERTY( EditAnywhere, meta = ( Bitmask, BitmaskEnum = "EPlayModeUsageFlags" ) ) int32 UsageFlags = (int32)EPlayModeUsageFlags::PlayMode_None; |
こちらもポイントとなるのはUPROPERTYの中のメタデータ指定です。「Bitmask」を設定し、「BitmaskEnum」に先ほど用意したenumの名前を指定します。
また、初期化時に 0 を代入しても構いませんが、PlayMode_Noneでも大丈夫です。ただ、その場合はint32型にキャストが必要になるので注意して下さい。
これでint32型の変数を使ってビットフラグとして扱えるようになりました。
【注意点】
それぞれのメタデータ指定子で「Bitflags」「Bitmask」と名前が似ているため混同しやすいですが、指定箇所が異なるため、注意が必要です。
| Bitflags |
enum側の宣言で使用 |
| Bitmask |
変数側の宣言で使用 |
〇エディタ側で値を設定する
次に、アクター側に用意したフラグを実際にエディタにて設定していきます。
今回は「探索パートとイベントパートでは動かしたいが、バトルパートでは動かしたくない」アクターになるので、PlayMode_ExplorationとPlayMode_Eventが有効になるように設定します。

エディタ上でアクターの変数を編集する際、有効にしたいパートに関してチェックマークを入れるだけです。
とても分かりやすいですね。
〇C++でビットフラグによる判定の処理を行う
最後に特定のパート、今回は探索パートの時に、設定されたアクターのみをアクティブにする処理です。
|
|
UCLASS() class TESTPROJECT_API ATestGameMode : public AGameModeBase { GENERATED_BODY() public: UFUNCTION(BlueprintCallable) void ChangeExplorationMode(); }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
#include "TestGameMode.h" #include "Kismet/GamePlayStatics.h" #include "TestActorBase.h" void ATestGameMode::ChangeExplorationMode() { TArray<AActor*> TestActorList; UGameplayStatics::GetAllActorsOfClass(GetWorld(), ATestActorBase::StaticClass(), TestActorList); for( auto Actor : TestActorList ) { ATestActorBase* TestActor = Cast(Actor); // 探索パート時に有効にしたいアクターか判定 if( EnumHasAnyFlags( (EPlayModeUsageFlags)TestActor->UsageFlags, EPlayModeUsageFlags::PlayMode_Exploration ) ) { // 有効にする。 実際の用途に応じて、表示処理や衝突処理、Tickの有効などを制御する関数を用意して呼び出す } } } |
EnumHasAnyFlags関数は、指定したフラグが1つでも含まれているかを判定するための関数です。ENUM_CLASS_FLAGSで定義されているenumで使用する事が可能です。
もちろんビット演算でも構いません。その場合は
|
|
if( TestActor->UsageFlags & (int32)EPlayModeUsageFlags::PlayMode_Exploration ) |
となります。
また、引数の「EPlayModeUsageFlags::PlayMode_Exploration」を変数化するなどして、探索パート以外にも他のパートでも判定を行う事ができます。
ちなみにEnumHasAllFlags関数というのも存在しますが、こちらは指定したフラグが全て含まれているかを判定したい場合に使います。
〇おまけ
フラグ判定に関して、先ほどの説明では直接メンバ変数を参照しているため、本来は以下のように関数を用意するのがより望ましいです
|
|
UFUNCTION( BlueprintCallable ) bool HasUsageFlag( EPlayModeUsageFlags InFlags ) const; |
|
|
bool ATestActorBase::HasUsageFlag(EPlayModeUsageFlags InFlags) const { return EnumHasAnyFlags( (EPlayModeUsageFlags)UsageFlags, InFlags ); } |
また、ブループリント側から関数を使ってビットフラグを設定する場合などは、以下ようにする事でビットフラグを設定しやすくなります。
|
|
UFUNCTION( BlueprintCallable ) void SetUsageFlags( UPARAM(meta=(Bitmask, BitmaskEnum="EPlayModeUsageFlags")) int32 NewFlags ); |
|
|
void ATestActorBase::SetUsageFlags(int32 NewFlags) { UsageFlags = NewFlags; } |

ビットフラグ、ぜひ活用してみください!