フラグ管理

flag.png

Javaの場合は、EnumSetを使用するべし。

List of pages tagged with flag:

Skyrimみたいなゲームには沢山のフラグが存在するだろうけど、どうやって管理してるんだろか。
平山[4]によれば、ゲームではunsigned な整数を使ったフラグ管理がよく行われているらしい。
そういえば、よくOpenGLみたいなライブラリではフラグをor|で渡すよね。
この方法は使えるかも。
enumな定数にしてつかう、とかね。
フラグ管理にはbitsetも活躍するよ。

  • 複数のフラグオンにするには|
  • フラグを取り出すには&
  • ビット演算に使用する変数はunsignedにする。
  • フラグをオフにするにはフラグ変数&=~フラグ定数;
  • そのフラグが立っていないことを確認するには(フラグ変数 & フラグ定数)==0

引数が多すぎた時に、こういうフラグを使うようだ。
まぁ、ライブラリとして提供するときはこれがいいかもね。
やっぱり世の中で言うフラグ管理クラスが必要なのかな。
今、9個のフラグがある。

フラグの変化を探知

XORでシンプルに探知する

void CCloudRender::SetFlag(unsigned int _flags){
    //フラグに変化はないかどうか検知
    if(unsigned int flag_diff=m_Flags ^ _flags){//もし変化があったら
        OutputDebugString("変化があったよーーー\n");
        switch(flag_diff){//変化部位によって分岐
            case MY_LAND:
                (_flags & MY_LAND)? m_Land=new CLand() : delete m_Land;
                break;
        }
    }
    m_Flags=_flags;
}

もっと複雑な方法

bool CCloudRender::CheckParameterChange(){
    static unsigned int lastVolData=m_Flags & MY_VOLDATA;
    if((m_Flags & MY_VOLDATA)!=lastVolData){
        m_Land->ToggleMap();
        m_Flags &=~MY_FLOW_DAYTIME;
        cout<<"6分おきに変わるデータをロードします"<<endl;
        m_Flags |=MY_VOLDATA;
        ChangeVolData();
        lastVolData=m_Flags & MY_VOLDATA;
        return 0;
    }
    return 0;
}

フラグ定数の書き方

よくOpenGLなどでは0xで書いてあるけど、
enumをこんな風に書くとわかりやすい。
0xでベタ書きしたほうが、計算の無駄はないかもしれないけどね。

enum Flah{
FLAG_WALL=(1<<7),
FLAG_GOAL=(1<<6),
};

感想

はじめは、unsigned charでいいやって思ってたけど、後からフラグが8個以上増えて、unsigned intに変えた。
そしたらわけわからないバグになった。どうせフラグはちょっとのサイズなんだからはじめからintでよかったかも。

フラグ管理クラス

#ifndef FLAG_H_
#define FLAG_H_
 
//unsigned int型、32bit
namespace HN{
    class Flag{
    public:
        Flag() : mFlags(0){}//コンストラクタ
        bool check(unsigned int f) const;//フラグの確認
        void set(unsigned int f);//フラグを立てる
        void reset(unsigned int f);//フラグを消す
        void find();//フラグの一覧を見る
    private:
        unsigned int mFlags;
    };
}
 
#endif //#ifndef FLAG_H_
#include "Flag.h"
#include <iostream>
#include <limits>
using namespace std;
 
namespace HN{
    bool Flag::check(unsigned int f) const{
        return((mFlags & f) != 0);
    }
    void Flag::set(unsigned int f){
        mFlags |= f;
    }
    void Flag::reset(unsigned int f){
        mFlags &= (f ^ UINT_MAX);
    }
    void Flag::find(){
        unsigned int n = (1 << 31);
        cout << "フラグ一覧:";
        for(int i=0;i<32;i++){//32bitなので32回繰り返す
            cout << ((mFlags & n) != 0);
            n = (n >> 1);//2で割っていく
        }
        cout << endl;
    }
}

さらにbitのページが役に立つと思う。

bitset<enum>

今まで#defineでいいじゃんとenumを敬遠していたが、
bitsetと組み合わせると意外に便利なことを発見。
というか使わないとフラグ管理が面倒。
 
enum FLAG{
FLAG1=0,
FLAG2,
FLAG3,
.
.
.
FLAGNUM
};
 
std::bitset<FLAGNUM> FlagMgr;
 
enumの最後にFLAGNUMを加えることで
フラグの数が増えてもbitsetの定義はそのままで使える。
 
これでぐちゃぐちゃフラグ管理から脱出。よっしゃ。
Bibliography
2. フラグを管理するクラスc++….沢山のフラグを頻繁に立てたり、折ったりする場合に良いかも

サポートサイト Wikidot.com