Unityでゲームを作成しているとフラグ判定により処理を分岐することがあります。
今までの私は、フラグ管理を下記のように行っていました。
bool flagA = true;
bool flagB = false;
bool flagC = true;
このやり方は、フラグが数種類なら良いのですが種類が増えてくると、煩雑になりバグの原因となっていました。
そこで今回はビット演算を使ってフラグ管理をする方法を、備忘も兼ねて記事にします。
ビット演算は1と0の二進数により、ON/OFFの状態を判定するものです。
ビット演算の基本
ビット(bit)とはコンピュータが処理する最小単位と言われ、0と1を判定する事ができます。・・・というかそれしかできません。
ビットと聞くと何だか難しそうで嫌煙しがちですが安心してください。
0と1、つまり電気信号のONとOFFを利用してフラグ管理ができるわけです。
- 0の状態がfalse
- 1の状態がtrue
これをゲームのフラグ管理に応用するとこんな感じになります。
int flag = 0000;
4桁の二進数がありますが、それぞれの桁にフラグを割り当てていきます。
// 死亡, 呪い, 混乱, 毒のフラグを各桁に割り当てる
0000; // -> 死亡-false, 呪い-false, 混乱-false, 毒-falseと判断できる
0101; // -> 死亡-false, 呪い-true, 混乱-false, 毒-trueと判断できる
こんな感じでビット演算を使って状態管理する時に、よく使う演算子を紹介します。
AND演算(&)
どちらも1の場合に1を返します。
それ以外の場合は0を返します。
1 & 1 // 結果は 1
1 & 0 // 結果は 0
0 & 1 // 結果は 0
0 & 0 // 結果は 0
1100 & 1010 // 結果は1000
OR演算( | )
どちらかが1の場合は1を返します。
どちらも0の場合のみ0を返します。
1 | 1 // 結果は 1
1 | 0 // 結果は 1
0 | 1 // 結果は 1
0 | 0 // 結果は 0
1100 | 1010 // 結果は1110
NOT演算(~)
1つのビットパターンを取り、その反対のビットパターンを返します。
~1 // 結果は 0
~0 // 結果は 1
~1100 // 結果は0011
フラグ管理のしかた
分かりやすいように少しだけ10進数と2進数の対比表を載せておきます。
10進数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
2進数 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 |
使用するフラグを列挙型で設定
まずは状態を表すフラグを設定します。列挙型(enum)を使うことで見やすくなります。今回は例としてロールプレイングでよく使われる状態異常、毒・混乱・呪い・死亡を管理してみましょう。
using System; // <- Flags付ける時はこれも必要
public class StateScript : MonoBehaviour
{
[Flags] // <- Debug時にフラグが見やすくなる
enum StateFlags
{
NOMAL = 0, // 初期状態 0000
POISON = 1, // 毒 0001
CONFUSION = 2, // 混乱 0010
CURSE = 4, // 呪い 0100
DEATH = 8, // 死亡 1000
}
}
状態異常を追加する
毒攻撃により毒の状態異常を与えたい!そんな時ありますよね。それを先ほど定義した列挙型で再現していきます。ビットで表現すると下のような状態にしていきます。
0000 | 0001 // 結果は 0001 つまり毒状態
それでは毒状態にしてみましょう。
まずはflagという変数を作成して、毒のフラグをOR演算で追加します。ちなみに書き方の例を二つ挙げましたが、どちらでも大丈夫です。
void Start() // 毒攻撃!
{
StateFlags flag = 0; // 状態を初期化
flag = flag | StateFlags.POISON; // 毒状態にする 書き方1
flag |= StateFlags.POISON; // 毒状態にする 書き方2
Debug.Log(flag); // 出力してみる
}
コンソールに出力した結果は下のように、毒フラグが立っていることが一目瞭然です。
状態異常を解除する
毒消し草を使って毒状態を解除したい。そんな時はAND演算とNOT演算を併用することで毒フラグのみ解除することができます。
では、毒消し草のコードを書いてみましょう。
// 毒消し草!
flag &= ~ StateFlags.POISON; // 毒状態を解除
Debug.Log(flag); // 出力してみる
ビットで表現すると下のような処理を行いました。
~ 0001 // 消したい毒フラグの二進数を反転させる -> 1110
0001 & 1110 // 毒状態のステータスにAND演算 -> 0000
コンソールに出力してみると、下のように毒フラグが解除され初期状態に戻ったことが確認できます。
フラグを条件判定に使用する
もちろんフラグはif文の条件判定に使用できます。
フラグの状態をbool値で返してくれる、便利なHasFlagメソッドというのがありますので、それを使っていきます。
HasFlagは指定したフラグがONかOFFかをチェックしてくれます。返り値はbool型になりますのでそのままif文に突っ込めます。
if (flag.HasFlag(StateFlags.POISON)) // 毒フラグが立っていたらtrue
{
Debug.Log("毒ダメージ!"); // 毒フラグがtrueなら表示
}
毒フラグが立っている状態で実行するとコンソールに正しく表示されました。
複数フラグの条件判定
HasFlagは複数の条件判定にも使用できます。
- ■■ かつ ▲▲ -> &&
- ■■ または ▲▲ -> ||
// 毒かつ混乱
if (flag.HasFlag(StateFlags.POISON) && flag.HasFlag(StateFlags.CONFUSION))
{
Debug.Log("毒かつ混乱");
}
// 毒または混乱
if (flag.HasFlag(StateFlags.POISON) || flag.HasFlag(StateFlags.CONFUSION))
{
Debug.Log("毒または混乱");
}
コメント