Cocos2d-xで乱数を取得する

Cocos2d-xにはライブラリ自体に標準で乱数を取得できるrandom関数があります。

自分でsrand + rand とか、mt19937を自分でしなくて大丈夫です。便利に使えるようにUtility作る必要ありません。使い方は以下の通りです。

// 使い方
bool HelloWorld::init()
{
    // ...省略...

    // 0~int最大値までの乱数を取得
    int num = cocos2d::random();

    // 指定した範囲内の乱数を取得
    int scoped_num = cocos2d::random<int>(10, 20);
}

範囲指定も対応しているので、rand()%10とかせず引数に範囲を直接指定できます。また、random関数はいくつかオーバーロードがあるので整数以外にも、float, double, longの型が使用できます。

範囲指定の場合、(0, 3) とすると 0~3(0, 1, 2, 3)の範囲が取得できます。テンプレートには、int, float, double, long double の4つが指定できます。

// Cocos2d-x内の宣言

// ccRandom.h

template<typename T>
inline T random(T min, T max) {
    return RandomHelper::random_int<T>(min, max);
}

template<>
inline float random(float min, float max) {
    return RandomHelper::random_real(min, max);
}

template<>
inline long double random(long double min, long double max) {
    return RandomHelper::random_real(min, max);
}

template<>
inline double random(double min, double max) {
    return RandomHelper::random_real(min, max);
}

上記宣言が既にあるので使い方はだいたい以下の通りに書けば意図したとおり動作します。*1

// 使い方

bool HelloWorld::init()
{
    // ...省略...

    float frand_1 = random(0.0f, 15.36f);
    float frand_2 = random<float>(0, 5);

    double drand_1 = random(0.0, 5.36985);
    double drand_2 = random<double>(0, 20);

    long = lrand_1 = random(3L, 50L);
    long = lrand_2 = random<long>(7, 12);
}

おまけ - 最初から使える理由

なんでcocos2d.hをincludeするとccRandum.hが付いてくるかというと以下の順序でincludeされているためです。

cocos2d.h > base/ccMacros.h > base/ccRandom.h

おまけ - 実装の中身

乱数の実装にはいろいろありますが、Cocos2d-xの乱数の実際の実装は以下の通りです。

// ccRandom.cpp

// 乱数エンジン取ってくるところ
std::mt19937 &cocos2d::RandomHelper::getEngine() {
    static std::random_device seed_gen;
    static std::mt19937 engine(seed_gen());
    return engine;
}

// テンプレートの型に合わせて数字を取れるようにするところ
class CC_DLL RandomHelper {
public:
    template<typename T>
    static T random_real(T min, T max) { // int以外
        std::uniform_real_distribution<T> dist(min, max);
        auto &mt = RandomHelper::getEngine();
        return dist(mt);
    }

    template<typename T>
    static T random_int(T min, T max) { // intの時
        std::uniform_int_distribution<T> dist(min, max);
        auto &mt = RandomHelper::getEngine();
        return dist(mt);
    }
private:
    static std::mt19937 &getEngine();
};

*1:VS2017でしか動作見てないのでもしかしてgccではNGあるかも?