はじめに

C#には、enum(列挙型)というものがあります。

以下の様に記述します。

public enum JobType
{
	Fighter = 0,
	Magician,
	Preast,
	Thief,
	Paladin,
}

定数をまとめたような型で、列挙型に含まれる定数を列挙子といいます。

Fighterに0を指定してますが、0であれば省略できます。

以降の列挙子は1ずつ増えていくので、

Magicianは1,Preastは2となっています。

ゲーム中でよく使う職業や属性をint型としておくより、専用の列挙型を用意してあげると、

コード上分かりやすくなります。

連番の定数を沢山定義している場合は列挙型を使えないか検討しましょう。

Flagsとは?

RPGにおける状態異常について考えてみます。

以下の様な列挙型を用意しました。

public enum BadStatusType
{
	Poison,
	Sleep,
	Silence,
	Stone,
}

通常、状態異常は複数の状態を同時に持つため、このままだと扱いに困ります。

(Listで持てばいいとかありますがここでは一旦置いておきます)

こういった場合に、Flags属性を使って以下の様に定義することが出来ます。

using System;

[Flags]
public enum BadStatusType
{
    Poison = 0b_0000_0001,
    Sleep = 0b_0000_0010,
    Silence = 0b_0000_0100,
    Stone = 0b_0000_1000,
}

0xで始めると16進数を記述できるように(0xFFなど)、

0bで始めると2進数で記述できます。

こうした場合、BadStatusType型の変数は複数の状態を持つこと出来るため、以下の様に出来ます。

using UnityEngine;

public class BadStatusTest : MonoBehaviour
{
    private void Awake()
    {
        // 毒と睡眠の状態を持たせる
        BadStatusType badStatus = BadStatusType.Poison | BadStatusType.Sleep;

        if (badStatus.HasFlag(BadStatusType.Poison))
        {
            Debug.Log("毒だよ");
        }
        
        if (badStatus.HasFlag(BadStatusType.Sleep))
        {
            Debug.Log("寝てるよ");
        }
    }
}

ビット演算

ビット演算とは、ざっくり言うと2進数での演算を指します。

2進数については中学校数学で習っているはずなので省略します。

1ビットとは、0と1、onとoff、trueとfalse、正と負のような二つの状態を持ちます。

int型や列挙型は32bitなので、0と1の組み合わせを32個持てることになります。

先ほどの例では、BadStatusTypeの列挙子を2進数で初期化しました。

各列挙子で1になっているビットが違うため10進数にした時の値も違います。

using System;

[Flags]
public enum BadStatusType
{
    Poison = 0b_0000_0001,  // 1
    Sleep = 0b_0000_0010,   // 2
    Silence = 0b_0000_0100, // 4
    Stone = 0b_0000_1000,   // 8
}

以下の様な「|(OR演算子)」での演算を論理和といいます。

「Poison or Sleep」「Poison または Sleep」の状態を作っています。

BadStatusType badStatus = BadStatusType.Poison | BadStatusType.Sleep;

2進数にしてみると以下の状態となり、

PoisonとSleepのビットが1になっているのが分かります。

0b_0000_0011 // (0b_0000_0001 | 0b_0000_0010)

ビット演算には他にも、

  • 論理積
  • 排他的論理和
  • 反転
  • シフト

もあります。

興味があったら調べてみてください。

インスペクタ上に表示する

Flags属性をつけた列挙型もインスペクタに表示することが出来ます。

以下のコンポーネントを用意してどのように表示されるか確認します。

using UnityEngine;

public class BadStatusTest : MonoBehaviour
{
    [SerializeField] private BadStatusType _badStatus;
}

インスペクタ上では以下の様に表示されました。

CameraコンポーネントのCulling Maskのように組み合わせで選択出ることがわかります。

最後に

Unityでビット演算を使うところといえば、Physics.Raycast 系のメソッドにLayerMaskを指定する場合でしょうか。

複数のレイヤーとのコリジョンを判定したい場合に論理和でレイヤーの組み合わせを指定するのに使いますね。

それ以外にはあまり思い当たりませんが。

かつてのメモリの少ないコンシューマゲーム機向けにゲームを作っていた際は、

メモリを節約するためビット演算は普通に使っていました。

現在のデバイスでは余り出番がないかもしれませんが、

覚えておくと何かの役に立つかもしれません。