読者です 読者をやめる 読者になる 読者になる

明日への断片

ゲーム制作やプログラミング関する記事を中心に更新していこうと思います。

4欠片目:ビット演算の応用

 こんにちは!ケーキのイチゴは最初でも最後でもなく途中で食べるvoidです。
何故かこの時間にブログを書くのが定着しそうなのが少し不安な今日この頃...(現在、午後11時)
(一応)毎日更新できてるので、この調子でどんどん書いていこうと思います。

続・ビット演算

 さて、昨日はビット演算の基本的な計算方法を紹介しましたね。

↓昨日の記事
yasu-game.hatenablog.com

技術的な話をすると、「間違えたらまずい...」っていう感覚あって結構緊張しますね...まぁそれはそれで訓練(?)になると思うので慣れていきたいと思います。

ビット演算の使い道

 自分が初めてビット演算を勉強した時は、こう思いました。
 「ビット演算の基本は分かったが、こんな計算いつ使うんや?」
実はこいつには中々便利な使い道が存在しています。
その1つが、フラグ管理です。

ビット演算によるフラグ管理

 ここでは、ロールプレイングゲームを例に挙げてみましょう。
ロールプレイングゲームに、毒、混乱、睡眠、火傷...等の状態異常を実装するとします。その状態によって、プレイヤーはダメージを受けたり、行動を制限されたりしますよね。そのためには、プレイヤーが今どの状態異常にかかっているかを記憶する必要があります。これを1つずつ管理しようとすると、C言語ではint型、C++言語ではbool型のフラグ用変数を用意する必要があります。

int isPoison;   // 毒状態かどうか
int isConfused; // 混乱状態かどうか
int isSleeping; // 睡眠状態かどうか
・
・
・

このように、状態異常の数と同じ分だけ変数を作る必要があります。



これをたった1つの変数で管理出来たらすごいと思いませんか?思いますよね? なんとできてしまうのです!そう、ビット演算ならね(言ってみたかっただけ)

int state;

はい、これだけで良いのです。

フラグ管理の仕組み

 ビット演算でのフラグ管理の仕組みを説明していきます。ビットのデータは「1」または「0」が存在していましたね。すなわち「ON」または「OFF」の状態が存在してるのです。その各ビット毎に状態異常を対応させてあげるのです。

 状態異常  混乱 睡眠 火傷
ビットデータ 0 0 0 0

このように対応させてみました。int型は4byte = 32bitなのでもっとたくさんの状態異常を用意できますね。(32個も状態異常があるゲームは見たことないですが...)

この対応で見ると、

プレイヤーの状態 stateの値(2進数) stateの値(10進数)
火傷 0001 1
睡眠 0010 2
混乱 0100 4
1000 8

更には、

火傷+毒 1001 9

なんてこともできます。

プログラムに実装するには

 サンプルコードを書いてみました

/* Sample.c*/
#include <stdio.h>

// 状態異常を定数にする
#define NORMAL 0	// 通常状態
#define BURN 1     	// 火傷
#define SLEEP 2    	// 睡眠
#define CONFUSE 4  	// 混乱
#define POISON 8   	// 毒

int main(void)
{
	// 最初は通常状態
	int state = NORMAL;

	// 毒状態を追加
	state = state | POISON;

	// 火傷状態を追加
	state = state | BURN;

	// 毒状態をチェック
	if (state & POISON)
	{
		// 毒状態のときの処理	
		printf("今は毒状態です\n");
	}

	// 火傷状態をチェック
	if (state & BURN)
	{
		// 火傷状態のときの処理	
		printf("今は火傷状態です\n");
	}

	return 0;
}

まず、初めは通常状態なのでstateの値はNORMAL(0)です。次に、

state = state|POISON;

とありますが、stateは0000でPOISONは1000なので、ビット和は1000となりstate == 1000となります。ちゃんと毒状態になっていますね。

次を見てみましょう。

state = state | BURN;

となっています。現在のstateは1000で、BURNは0001なのでビット和は1001となりstate == 1001となります。このとき、

state = BURN;

としてしまうと、毒状態が上書きされて消えてしまうのでしっかり現在の状態とのビット和を求めましょう。

最後にstateと、調べたい状態のビット積を求めていますね。stateの値は1001、POISONの値は1000でビット積は1000となり、0以外なので真として判定されます。BURNを同じようにして調べても、ビット積は0001となり真になります。
しかし、SLEEP(0010)やCONFUSE(0100)と比べると、ビット積は0000となり、偽になります。
しっかりと、毒と火傷の状態をだけを判別できていますね!

長くなりましたが...

 はい、思っていたよりも本当に長くなってしまいましたが、『ビット演算によるフラグ管理』、分かっていただけたでしょうか?(書き始めてから2時間たってました...)
ビット演算を使うと変数が一つで済むので、メモリも減らせますし、なんかかっこいいなぁと思って自分は結構使ってたりします。是非、使い道を探してみてください!

反省、そして明日へ...

 全体的にもっと簡潔にまとめたいのですが、書いているうちにこれもいるんじゃないか?あれもいるんじゃないか?ここは間違ってないか?などとしているうちにこうなってしまいました...文章構成にも気にしながら明日からは書いていこうと思います...
ではまた!