【Unity】Bit演算覚書【C#】
はじめに
執筆日は20222/11/14になります。
Unityのバージョンは2021.3.1f1を使用しています。
よく忘れて調べ直すので、自分でまとめ
自己紹介
活動名はHiruko、もしくはHirukoTimeで活動してます。
個人でSteamでゲームを販売したり、定期的にゲームジャムなどに参加をしています。
基本的な処理
初期化
//0で初期化[32bit] int bit0 = 0 //[00000000000000000000000000000000] //1で初期化[32bit] int bit1 = -1 //[11111111111111111111111111111111]
左シフト
//[8]1000 var bit = 1 << 3 //ゲームなどでフラグ管理で使う場合はconstやEnumで使う const int Flag_A = 1 << 3; [System.Flags] public enum Status { None = 0, All = -1, //0001 Attack = 1 << 0, //0010 Jump = 1 << 1, //0100 Crouch = 1 << 2, //1000 Dead = 1 << 3, }
Bitを左にずらす
UnityのInspectorでは自動でEverythingが追加される。
右シフト
var bit = 256; var rightShift = bit >> 1; //[100000000]bit //-------------- //[010000000]rightShift
Bitを右にずらす。
OR演算
//左シフトの際のenum Statusを例として使う var state = (Status.Attack | Status.Jump); //0001 Attack //0010 Jump //----- //0011 stateに代入される値
どちらかのBitが1なら1、両方0なら0
[ | ]OR演算子 (縦棒、vertical bar)
[shifr] + [ ¥ ]キー([ \ ]キー)
AND演算
//左シフトの際のenum Statusを例として使う var state = (Status.Attack | Status.Jump); //[0011] state = state & Status.Attack; //0011 現在のstate値 //0001 Attack //----- //0001 計算後の値
どちらのBitも1なら1、それ以外なら0
[ & ]AND演算子
[shifr] + [ 6 ]キー
XOR演算(排他的論理和)
var a = 0b0101; var b = 0b1001; var flag = a ^ b; //0101 a //1001 b //----- //1100 計算結果 flag
ビット同士が同じなら0、違うなら1
[ ^ ]XOR演算子 (ハット、キャレット)
[ ^ ]キー ([ ¥ ]キーの左)
NOT演算(補数、反転)
//左シフトの際のenum Statusを例として使う var state = (Status.Attack | Status.Jump); //[0011] state = ~state; //0000-0000-0000-0000-0000-0000-0000-0011 現在のstate値 //----- //1111-1111-1111-1111-1111-1111-1111-1100 計算後の値
0と1を入れ替える。
全部のビットを入れ替える。
[ ~ ]NOT演算子 (チルダ)
[shifr] + [ ^ ]キー
フラグを追加する。
//左シフトの際のenum Statusを例として使う //初期化 var state = (Status.Attack | Status.Jump); //OR演算を用いる // state = (status | Status.Crouch); と同義 state |= Status.Crouch; //0011 stateの現在値 //0100 Crouch //----- //0111 計算後のstate
フラグを削除する。
//左シフトの際のenum Statusを例として使う //初期化 var state = (Status.Attack | Status.Jump); //AND演算とNOT演算を用いる。 // state = (status & ~Status.Jump); と同義 state &= ~Status.Jump; //0011 stateの現在値 //1101 ~Status.Jump //----- //0001 計算後のstate
指定のフラグが立っているか
例1
//左シフトの際のenum Statusを例として使う //初期化 var state = (Status.Attack | Status.Jump); //AND演算を用いる。 if( (state & Status.Crouch) == Status.Crouch) { //何かの処理 } //0011 stateの現在値 //0100 Crouch //----- //0000 (state & Status.Crouch) //(state & Status.Crouch)[0000] == Crouch[0100] 一致しないのでfalse
例2
var state = (Status.Attack | Status.Jump | Status.Crouch ); var CrouchAttack = (Status.Attack | Status.Crouch ); if( (state & CrouchAttack ) == CrouchAttack ) { //しゃがみ攻撃!! } //0111 state //0101 CrouchAttack //----- //0101 (state & CrouchAttack ) //(state & CrouchAttack )[0101] == CrouchAttack[0101] 一致するのでtrue
BitCount
int BitCount(int bits) { bits = (bits & 0x55555555) + (bits >> 1 & 0x55555555); bits = (bits & 0x33333333) + (bits >> 2 & 0x33333333); bits = (bits & 0x0f0f0f0f) + (bits >> 4 & 0x0f0f0f0f); bits = (bits & 0x00ff00ff) + (bits >> 8 & 0x00ff00ff); return (bits & 0x0000ffff) + (bits >>16 & 0x0000ffff); }
有名なアルゴリズム。
ログで出力する際の変換
public static string LogBit(int flag , int digit = 4 , bool isForce = false , char padding = '0') { //ToString( 変換元 , 進数指定 ) 第二引数に[2]を入れると2進数で表現する。 //※[8]8進数 [16]16進数と言う感じ //左詰めする処理:PadLeft( 桁数 , 空埋する文字 ) //PadLeft(4,'0')だと、ToStringの変換を4文字で埋めて、空の場合は左に0を埋める。 //[flag = 3]の場合[11] => [0011] //Consoleの出力で確認する場合桁が揃った方が見やすいので必要だと思う。 //digitより桁数が多い場合は表示がずれるので、Maskを掛ける。 //デバッグ上問題があるのでisForceでmaskを無視する。 var mask = !isForce ? ((1 << digit) - 1) : -1; return Convert.ToString(flag & mask, 2).PadLeft(digit,padding); //digit = 4 //[10000 = 32] 1 << digit //[01111 = 31] (1 << digit) - 1は(32) - 1 //flag & maskで下位4bit以外を全部0にする //XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX flag //0000-0000-0000-0000-0000-0000-0000-1111 mask //------------------------------------------------------- //0000-0000-0000-0000-0000-0000-0000-XXXX 計算結果 }