はじめに
ゲームを作っていると難易度ごとで敵の体力や攻撃力などを設定できるようにしたいという状況に出くわすことがあると思います。
敵のデータテーブルを難易度ごとに作るなど色々と方法があると思いますが、今回はプロパティ上でできる方法をご紹介します。
例として難易度ごとに敵のデータを設定できるようにするため、適当に敵のデータ構造体と難易度の列挙型を作ります。
USTRUCT()
struct FEnemyData
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere)
int32 Health;
UPROPERTY(EditAnywhere)
int32 Attack;
UPROPERTY(EditAnywhere)
FName RewardId;
};
UENUM()
enum class EDifficulty : uint8
{
Easy,
Normal,
Hard,
Max
};
ENUM_RANGE_BY_COUNT(EDifficulty, EDifficulty::Max);
ENUM_RANGE_BY_COUNT
マクロはUENUM
をforeach
で簡単に回せるTEnumRange
というクラステンプレートを使うために定義しています。
Iterating over UENUM with TEnumRange - ben ui
まずすぐに思いつく方法としては以下の様に難易度の列挙型をkey
で敵データの構造体をvalue
にしたTMap
を作るというのがあるかと思います。
UPROPERTY(EditAnywhere, EditFixedSize)
TMap<EDifficulty, FEnemyData> EnumMap;
Detailsパネルでの見た目は後で紹介するenum
をインデックスとした配列とほとんど変わりませんが、普通のTMap
だと難易度分の要素を自分で追加しないといけない上に、特定の難易度のデータがない状態などが起こり得ます。
そこで、TArray
やTMap
の要素数を編集できないようにするUPROPERTY
のメタ指定子のEditFixedSize
を使い、Detailsパネルから要素数の編集をできないようにして、以下の様にコンストラクタかどこかで難易度の種類分の要素を追加しておく必要があります。
ATest()
{
if (EnumMap.Num() == 0)
{
for (const auto& ArrayIndex : TEnumRange<EDifficulty>())
{
EnumMap.Add(ArrayIndex);
}
}
}
色々と面倒くさいですね...
作り方
それでは本題に入ります。
enum
をインデックスとした配列は以下の様にして定義できます。
UPROPERTY(EditAnywhere)
FEnemyData EnumArray[(int32)EDifficulty::Max];
この方法で定義するとEditFixedSize
を設定しなくても要素数の変更ができないようになっています。
ちなみにC++で扱う際はTArray
ではなくC++
標準の固定長配列になっているため、要素を足したりはできません。
また、普通の固定長配列なのでC++
で要素を取得する際は以下の様に整数にキャストしてインデックスを指定する必要があります。
EnumArray[static_cast<int32>(EDifficulty::Easy)].Attack;
余談
EnumArray
の定義を見た時に「あれ?C++なのにCタイプのキャスト使ってない?」と思った方も多いと思います。
とりあえず、static_cast
に直してみてみましょう。
UPROPERTY(EditAnywhere)
FEnemyData EnumArray[static_cast<int32>(EDifficulty::Max)];
難易度の表示名があるところがなぜか、Index[N]
の表示になってしまっています。
エンジンコードでこの方法を使っているところを見るといずれもCタイプのキャストを使っていたため、私もstatic_cast
に直したのですがどうやらCタイプキャストでないといけない理由があるようでした。
おそらくUnrealHeaderTool
でstatic_cast
を使った構文に対応していないことが原因だと思います。
また、UnrealHeaderTool
関連でもう一つ問題があります。
難易度ごとに何かの有効無効を設定するためにbool
で同じように定義するとビルドできません。
UPROPERTY(EditAnywhere)
bool EnumArray[static_cast<int32>(EDifficulty::Max)];
どうやらbool
の固定長配列がUnrealHeaderTool
でサポートされていないのが原因のようです。(なぜなのか...)
固定長配列ではサポートされていないだけで、TArray<bool>
はサポートされています。
Bool arrays in c++? - Forums
おわりに
[(int32)
で全体検索してみるとエンジンコードで結構使われているのが伺えます。(なのにこれに関する記事が全然ない不思議...)
余談で書いたこと以外にもUPROPERTY
のメタ指定子のTitleProperty
が使えないなどの制約もありますが、便利なのでぜひTMap
の代わりに使って頂ければと思います。
TitleProperty
については以下の記事が参考になります。
エディター上で配列の要素の横に文字列を表示する