hirukoTimeのUnity備忘録

Unityでゲームを作成してます。

【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    計算結果 
    }