PG日誌

受託系 PG が C# の事を書いています

Cocos2d-xで乱数を取得する

Cocos2d-xにはライブラリ標準で乱数を取得できるrandom関数があります。自分でsrand + rand とか、mt19937を自分でしなくて大丈夫です。便利に使えるようにUtility作る必要ありません。使い方ですが、

// Cocos2d-x内の宣言

// ccRandom.h

inline int random() {
    return cocos2d::random(0, RAND_MAX);
};

フリー関数で宣言されているので利用時は以下の通り使用できます。ccRandum.hに実装されていますが、"cocos2d.h"をincludeしていれば使用できると思います。

// 使い方

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

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

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

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

// 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あるかも?