PaperSloth’s diary

Unity(C#)、UE4(Blueprint/C++)についての記事を書いたり日常のことをつぶやきます。

UE4 2の累乗か否かを判定する関数

目次

・2の累乗かを判定
・BPとUnreal C++での違い
・まとめ

環境

Visual Studio Community 2015
・Unreal Engine4.16


2の累乗かを判定

以前にBP MacroLibraryで2の累乗か否かを判定するマクロを制作しました。
その際は0, 0以下でエラーになることを指摘いただいた方々ありがとうございました。

・使用用途
 Textureのサイズが正しく2の累乗になっているか等で使用します。
 ゲーム中に使うよりはツール制作でのTextureの検索等で使うことが多いと思います。

今回は2の累乗の計算をビット演算を使って行っています。
ビットごとの AND 演算子 (&)

UObjectを親としたBlueprintMacroLibraryに追加しました。
下記はUObjectを継承したクラスから呼び出すことができるものです。
f:id:PaperSloth:20170708002659p:plain

呼び出し
f:id:PaperSloth:20170708002706p:plain

・計算
本当に2の累乗になっているかを見てみましょう。
value = 2のケース
(value & (value - 1)) == 0)

↓ 値を入れて2進数として見てみます。

(0010 & (0010 - 0001)) == 0)

0010 (value)
AND 0001 (value - 1)
----
0000 (結果)
結果が0なのでこれは2の累乗となります。

value = 7のケース
0111 & 0111 - 0001

0111 (value)
AND 0110 (value - 1)
----
0001 (結果)
結果が1なのでこれは2の累乗ではありません。

また、0の場合にもこの判定では2の累乗であるという結果が返ってきてしまいます。
しかし、0は2の累乗ではないため、最初の判定でfalseを返すようにしています。


少し話が逸れますがMath Expressionは非常に便利なので積極的に使っていきましょう
下記は

(value > 0) && ((value & (value - 1)) == 0)

の中身です。
f:id:PaperSloth:20170708002937p:plain


MathExpressionは数式を入力することで計算結果を得られます。
BPで計算を長々と行うとノードが肥大化して可読性が下がるため、必要に応じて使いましょう。
公式ドキュメントで使用可能な演算子などが載っています。
Unreal Engine | Math Expression ノード

BPとUnreal C++での違い

さて、先程のマクロを見て疑問を感じた方もいると思います。

value > 0

という判定部分です。
unsignedにすれば良いのではないかと思った方もいるかもしれません。
unsignedを雑に説明するとマイナスの数値を扱うか否かの指定です。
通常はsignedでマイナスの数値が扱えるようになっています。

これには理由があります。
あまり話題に上がらないのですが、

Blueprintではunsignedを指定できません。

Unreal C++では下記のような記述になると思います。

// header
bool IsPowerOfTwo(const uint32 value);

// cpp
bool ClassName::IsPowerOfTwo(const uint32 value)
{
    if (value == 0)
        return false;
    return !(value & (value - 1));
}

そこで、Unreal C++側でUBlueprintFunctionLibrary等を使用してuint32を指定したらどうか?と思うかもしれません。

UCLASS()
class PROJECTNAME_API UExampleBlueprintFunctionLibrary : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()
	
    UFUNCTION(BlueprintPure, Category = Math)
        static bool IsPowerOfTwo(const uint32 value);
};
bool UExampleBlueprintFunctionLibrary ::IsPowerOfTwo(const uint32 value)
{
    if (value == 0)
        return false;
    return !(value & (value - 1));
}

しかし、その場合は下記のようなエラーとなります。
"Error: Type 'uint32' is not supported by blueprint."
先も述べたようにBPではunsigendをサポートしていないからです。


よって、Unreal C++でBPに公開可能な同様の関数を定義したい場合は下記のようになります。

// header
UFUNCTION(BlueprintPure, Category = Math)
    static bool IsPowerOfTwo(const int32& value);

// cpp
bool UExampleBlueprintFunctionLibrary ::IsPowerOfTwo(const int32& value)
{
    if (value <= 0)
        return false;
    return !(value & (value - 1));
}

値渡しで使うことも少なそうな関数だったため、参照渡しに変更しています。
f:id:PaperSloth:20170708010141p:plain

因みにBPからも参照渡しの指定は可能です。
Pass-by-Referenceにチェックを入れるだけです。
f:id:PaperSloth:20170708010623p:plain

まとめ

今回伝えたかったことは2点です。
・Blueprintからはunsigned(プラスのみの指定)が使用できない
・MathExpressionは便利。使いどころを見分けて複雑な計算を整理しよう。