HOME > BOIDSとは > BOIDSv1.00 ~現レル~


09.13 BOIDSv1.00 ~現レル~

【座標系の統一】
今まで「作るのが」先行したため色々なことを深く考えてこなかったので、改めて見ていくと先日お話ししたウィンドウズ上の様々な座標系が数学上の原点でなかったり、表示しているものと全く別の位置に原点があったりで分かりにくいため少なくとも見た目で分かる位置に原点を移動することにしました。


★ ウィンドウズ座標系とピクチャー座標

コンピュータの世界と数学の世界では前にお話ししたようにY座標の方向が違います。また必ずプラスの数値しかとらないため逆にマイナスが入ると、プログラムはその段階で強制的に中断してしまいます。方向を反対に変更すると全てそうしなければならなくなり手間がかかるため、ウィンドウズ原点は左上とし変更はしません。
これに伴い描画座標であるピクチャーボックス座標系も左上を原点としY成分は画面下に向けて大きくなり、第一象限のみの描画とします。

次に変更箇所としては、ピクチャーボックス上にサークルを表示する場合原点は通常左上(ウィンドウズ座標に同じ)で、そこから楕円を考慮して縦直径、横直径を入力して円を表示しますが、この点は実際には見えない位置であるため プログラム中扱われる座標=Iwashi[]は「見えていない座標」になってしまいます。そこで半径(PodHalfSize)だけ平行移動した点とし、円の中心を指し示すよう変更します。従って現在位置iwashi.Posは下記のようになります。





★ 距離の測定

iwashi座標原点を変更したことによってポッドとポッドの距離は点P1(Px1 , Py1)と点P2(Px2 , Py2)とすると、次のように計算できます。
( Px 2 - Px 1 ) 2 + ( Py 2 - Py 1 ) 2







★ 動作範囲

iwashi座標原点が変更されたことで逆に注意する点としては、ポッドが移動できる動作範囲についてです。
話は変わりますが、家の近くに高さ制限のある橋があり車で通っていると、隣のトラックの荷台がバリバリと大きな音を立ててめくれ上がった経験があります。幸いアルミのトラックだったので上の一部がめくれただけで済みましたが。今回のポッドも同じように核になる中心の周りに円形のバリアを張っているので、当然中心核だけで動作範囲を検知するとバリアが壁の中にめり込んでしまいます。そこで動作範囲は下記のようになります。

・ 0方向へ移動する場合は、「半径を引いた座標」で評価

・ プラス方向へ移動している場合の評価は、「半径をプラスした座標」で評価




★ 壁前の減速
ここでいきなり、ややこしいプログラムが登場します!


問題点にもあったように、生物ですから壁に頭からぶつかっていたら死んでしまいます(近畿大学もカツオの養殖時デリケートなカツオが頭から激突して死んでしまうために苦労した話は有名です)。 ですから魚たちは下の動画を見て頂くとわかりますが、減速しながら徐々に方向を変えていきます。

これをシミュレーションします。




【一般旋回行動】




そこで次のようなプログラムを考えました。

<壁回避の秘策>
1) 壁反発距離の設定
  今Y座標のみの例で考えますと、次のような距離を設定します

        一番上の面の壁限界Y座標値:
        ピクチャーボックス座標=0
        壁認識距離(_KABE_VIEW_DIST):
        この位置から壁と衝突するという認識を持つ距離
        壁反発予定距離(_KABE_REPUL_DIST):
        減速を開始する予定距離

  (壁限界Y座標値+壁認識距離(_KABE_VIEW_DIST))からポッドのバリアが
  壁認識距離(_KABE_VIEW_DIST)の範囲内に入ったかを検出します。
  この距離まで到達すると、位置構造体内のOrgVec(x,y)に各速度の成分を一旦ストックします。


2) 速度を接近した距離により減速
  次に壁との距離は近づくと当然小さくなります。それに比例して移動速度が減速させます。
    但し全く0になってしまうと動かなくなるため、オリジナル速度の33%を最低ラインとしています。
  逆に離れていくと徐々に元の速度に戻っていき、壁認識位置を離れるとストックした速度データは解放され元に戻ります。


/************************************************************************
* 壁を避ける                              *
************************************************************************/
void KabeSakeru(Iwashi_str *IwashiThis)
{
  double   detectLEN;
  double   v_x,v_y;


  detectLEN = (PodHalfSize + _KABE_REPUL_DIST);

  /************************************************************************
  * 左右の壁の反射                            *
  ************************************************************************/
  v_x = IwashiThis->OrgVec.x / 3;

  if ((IwashiThis->Pos.x - detectLEN) < (field.xMin + _KABE_VIEW_DIST))
  { /* 範囲はポッド半径の符号に注意 */
    if (IwashiThis->OrgVec.x == 0)
    {
      IwashiThis->OrgVec.x = IwashiThis->Vec.x;
      v_x = IwashiThis->OrgVec.x / 3;
    }

    IwashiThis->Vec.x = (v_x * 2 * (((IwashiThis->Pos.x - detectLEN) - field.xMin) / _KABE_VIEW_DIST) + v_x);
  }
  else if ((IwashiThis->Pos.x + detectLEN) > (field.xMax - _KABE_VIEW_DIST))
  {
    if (IwashiThis->OrgVec.x == 0)
    {
      IwashiThis->OrgVec.x = IwashiThis->Vec.x;
      v_x = IwashiThis->OrgVec.x / 3;
    }

    IwashiThis->Vec.x = (v_x * 2 * ((field.xMax - (IwashiThis->Pos.x + detectLEN)) / _KABE_VIEW_DIST) + v_x);
  }
  else
  {
    if (IwashiThis->OrgVec.x != 0)
    {
      IwashiThis->Vec.x = IwashiThis->OrgVec.x;
      IwashiThis->OrgVec.x = 0;
    }
  }


  /************************************************************************
  * 上下の壁の反射                            *
  ************************************************************************/
  v_y = IwashiThis->OrgVec.y / 3;

  if ((IwashiThis->Pos.y - detectLEN) < (field.yMin + _KABE_VIEW_DIST))
  { /* 範囲はポッド半径の符号に注意 */
    if (IwashiThis->OrgVec.y == 0)
    {
      IwashiThis->OrgVec.y = IwashiThis->Vec.y;
      v_y = IwashiThis->OrgVec.y / 3;
    }

    IwashiThis->Vec.y = (v_y * 2 * (((IwashiThis->Pos.y - detectLEN) - field.yMin) / _KABE_VIEW_DIST) + v_y);
  }
  else if ((IwashiThis->Pos.y + detectLEN) > (field.yMax - _KABE_VIEW_DIST))
  {
    if (IwashiThis->OrgVec.y == 0)
    {
      IwashiThis->OrgVec.y = IwashiThis->Vec.y;
      v_y = IwashiThis->OrgVec.y / 3;
    }

    IwashiThis->Vec.y = (v_y * 2 * ((field.yMax - (IwashiThis->Pos.y + detectLEN)) / _KABE_VIEW_DIST) + v_y);
  }
  else
  {
    if (IwashiThis->OrgVec.y != 0)
    {
      IwashiThis->Vec.y = IwashiThis->OrgVec.y;
      IwashiThis->OrgVec.y = 0;
    }
  }
}




これを起動すると、次のような動きになります。


BOIDS MODEL V1 00 01 ~壁減速~


どうでしょうか!

通常の魚の一般回避行動と損傷なく壁にぶつかることなく移動しているとは思いませんか?
壁認識距離は自由に設定できるので、自由度も結構あるはずです。

次に問題なのはいわし同士がクロスしてしまって事実上衝突状態であるということです。
これを数学で回避したいと考えています。




HOME > BOIDSv1.00 ~仕様~  > BOIDSv1.00 ~現レル~