「がんばれない」けど「がんばりたい」

ITエンジニアの仕事のこと。AI、機械学習、ディープラーニング。地頭力。車のこと。

Group Behaviors|Nature of Code

■ グループ

これまでMoverクラスやVehicleクラスも配列でインスタンスを管理し扱ってきた。配列はある意味【グループ】と考えることが出来る。だが、これまで行ってきた事は各々オブジェクトがそれぞれの動作を個々で行うのみに過ぎなかった。ここではComplex Systemsのページで言述した”Compete”にあたるseparateを実装してみる。

個々のオブジェクトが毎フレーム時に次の動作を決めるためにtargetをseekする事は変わらないが、自分自身以外のオブジェクトに【ブツカラナイ】ようにしてみる。これを行うには任意のVehicleオブジェクトが【動く】為のSteerベクトルを決める行程で、自分以外のオブジェクトと自分自身の関係について気にする必要がある。

余談ですがbox2dなどの物理エンジンで実装されているCollision(衝突)アルゴリズムとは全く違うAutonomousAgentsコンセプトであることが、面白いし、すごく重要だと進めば進むほど実感しています。

■ separate

「自分以外の全てのVehicleとseparateしないといけない」ので、

v.separate();

ではなく、

v.separate(vehicles); ※vehiclesはVehicleオブジェクトを管理する配列 流れを明確にするためにコードにしてみると

void update()
{
  for (int i = 0; i<vehicles.size(); i++)
  {
    Vehicle* v = &vehicles[i];
    v->separate(vehicles);
    v->update();
  }
}

void draw()
{
  for (int i = 0; i<vehicles.size(); i++)
  {
    Vehicle* v = &vehicles[i];
    v->draw();
  }
}

v->separate(vehicles)はvオブジェクトが他オブジェクトとseparateするためのforceを計算し決定するために自分以外の全てのVehicleオブジェクトを気にしないといけない。

separate()の実装を具体的にみていきましょう。Raynoldsは"Steer to avoid crowding.“と書いています。もう少し分かりやすく書くと「あるvehicleが超近くにいたら、そいつから離れろ!」です。なんだかseek(target)と逆なことっぽい感じもしますね。

じゃぁ「複数のVehicleが超近づいてきたら?」どうしましょうか。このケースは次のように定義する事にします。「その複数vehicleたちのベクトルの平均から離れる」。

コードにしてみます。

void separate(vector<Vehicle> vehicles)
{

    //20ピクセルより近くにあるか
    float desired_separation = r*2;

    //平均を計算するためのカウンタ
    int count = 0;

    //平均ベクトル
    ofVec3f sum;

    //自分と他各々のvehileとを比べる
    for (int i = 0; i < vehicles.size(); i++)
    {
        //自分と他vehicleとの距離
        float distance = (location - vehicles[i].location).length();

        //近かったら
        //distance>0は自分自身とは比べないようにするための条件
        if((distance > 0) && (distance < desired_separation))
        {
            //離れる方向を求める|location - other.location
            ofVec3f diffVec = location - vehicles[i].location;
            diffVec.normalize();

            //近ければ近いほど、大きく離れるべきだし
            //遠ければ遠いほど、そんなに離れる必要はない。
            diffVec /= distance;

            //近いother vehicleとの位置関係差を加算する
            sum += diffVec;

            count++;
        }
    }

    //近いvehicleが1つ以上居たら
    if (count > 0)
    {
        //平均ベクトル
        sum /= count;

        //maximum speedでスケールアップ
        //これがdesiredとなる
        sum *= maxspeed;

        //これ以降はReynold'sのdesired公式まま
        ofVec3f steer = sum - velocity;
        steer.limit(maxforce);

        applyForce(steer);
    }
}