BOIDSv2.00 ~纏メル~ HOME > BOIDSとは > BOIDSv2.00 ~纏メル~

10.05 BOIDSv2.00 ~纏メル~

これで一連のBOIDS例題は一応終了となります。(最終版プログラムは最後に添付します)

最後のまとめとして、まずはこのプログラムを動かすとどうなるのか? やってみましょう。

実はこんな動きをします。


★1個体動作させた場合
まずポッド先端青矢印から出ている黄色の領域は、前方視野内に障害物を発見した場合表示されます。これは視野内に入ったすべての部分に対し表示され現在1個体のみですので「壁」に反応します。次に黄色い視野内にある黒い線は、障害物で最も自ポッドに近い部分に対する「視線」であります。したがって自ポッドは視線の先にあるものを基準に次の動作をします。次の動作は「旋回」のみですので、「壁が見えたら回避しろ」とも、今までのように減速処理や範囲処理などなくても回避していきます。
但し前回「予想される問題点」で上げたように、ポッドは前進しかしないため実際の魚が囲いの隅へ追いやられるように角へ向かって移動した場合は、範囲外へ押しやられてしまいますので、「物理的制約」としてプログラム中には動作範囲チェックは存在します。


【BOIDS NEW MODEL Ver02.00-1 ~壁を見る~】




★複数個体動作させた場合
次にご覧いただきます動画は、個体が複数個存在する場合です。
前回お話ししたように壁とポッドの関係において現在ポッドの距離は加味しているため、自ポッドから他ポッドへは「2つの視線」を送っています。検知視界は長方形ですが、その対角線の1/2より大遠くで検知した場合と近くで検知した場合の最小値の箇所のに箇所に対し視線を送っています。要するに下記のような2つのケースで自ポッドが旋回する角度が変更となっています。







【BOIDS NEW MODEL Ver02.00-2 ~ポッドを見る~】





★障害物が出現する場合

このケースは左下のボックス内にある「障害物」に途中でチェックを入れると、「障害物」である緑色の線に対し「視線」を送るようになり避けて通るようになります。これはポッドが「眼」を持っており発生した事象に対しルールを持っているだけですので、「緑色」は「壁」、「青色」は「ポッド」と判断され、形が丸でも三角でも直線でも全く関係なく回避されます。

ですので、ある意味このプログラムは「色を識別して動作パターンを決める」ものであるといえます。

面白いですよねぇ!

【BOIDS NEW MODEL Ver02.00-3 ~障害物を避ける~】


まだまだ、水族館のようにはいきませんでしたが、BOIDS課題はひとまず終了いたします。



【BOIDS ver2.00 最終プログラム】
#pragma once
/************************************************************************
*  Project : BOIDSシミュレーション                   *
*  create : 2017/10/08                        *
*  参考  : coderecipe.jp                       *
*  1987年Craig Reynoldsというプログラマが考えた鳥の群れのシミュレーション   *
*  このアルゴリズムを「boid(ボイド)」と呼ばれた            *
*  基本ルールは下記の3つのルールに基づいている            *
*    1)衝突回避:距離が近すぎれば遠のく              *
*    2)中心集中:距離が離れていれば近づく             *
*    3)速度適合:ほとほどの距離なら並走(移動方向を回りと合わせる) *
*************************************************************************/
/************************************************************************
【改訂履歴】
ver1.00 2018/05/11 HP用にカスタマイズ
ver1.01 2018/05/11 ALIGNMENTALIGNMENT
ver1.02 2018/05/11 cohesion等大改修
ver2.00 2018/05/18 HP用にnewVer0.00カスタマイズ
ver2.01 2018/05/19 衝突回避角度改訂 およぶルールの改訂
          衝突検知距離が不足しているため対角線にした
<問題点>
・ 複数個の場合に回避できないケースあり

ver2.02 2018/05/22 不要な宣言廃止               ④
          判別距離・検索幅を調整用に統一した     ②
          ポッド衝突条件に検出距離を2段階に改訂   ②
          衝突検知知能ベース時間経過用二次配列廃止  ④
          敵対応一時廃止               ④
          ポッド構造体でa,v廃止          ④
          衝突位置の初期値設定            ③
<問題点>
① 角へ到達すると角へ向かって行ってします
② 衝突回避できないケースがある
③ 時々すべてのポッドに対し向けて検知線が出る場合がある
④ 不要な宣言や処理が残留しているため観にくい

ver2.02 2018/05/24 壁衝突条件に検出距離を2段階に改訂
<問題点>
① 角へ到達すると角へ向かって行ってします
*************************************************************************/
#ifdef _MSC_VER
#define   _USE_MATH_DEFINES
#endif

#include <math.h>

/************************************************************************
*  算術マクロ                             *
************************************************************************/
#define _RadianToDegree(radian) ((180.0 / M_PI)*(radian))
#define _DegreeToRadian(degree) ((M_PI/180.0)*(degree))


/************************************************************************
*  BOIDSに必要な宣言                          *
************************************************************************/
#define _CANVAS_WIDTH      1220    /* スクリーンの横幅           */
#define _CANVAS_HEIGHT     630     /* スクリーンの縦幅           */
#define _MAX_VELOCITY      200     /* 最大速度               */
#define _INTERVAL_TIM      40     /* 時間間隔(interval 50ms)       */
#define _INTERVAL_SEC      (_INTERVAL_TIM/1000.0)
                      /* インターバル時間(sec)_INTERVAL_TIM/1000*/
/* BOIDS情報          */
#define _POD_COUNT_MAX     1000    /* ボイドの数(配列決定用最大値)     */
#define _POD_DRAW_SIZE     60     /* ボイドの大きさ  デフォルト値    */

                      /* 壁面衝突に関するパラメータ      */
//#define _KABE_REPUL_DIST   0      /* 壁への反発範囲          16 */
#define _COLLISION_DISTANCE   20     /* 衝突診断長            20 */
#define _COLLISION_VIEW_ANGLE  (90.0 * M_PI / 180)
                      /* 衝突回避用角度          90 */

#define _COLLISION_ANGLE_00   5      /* 衝突回避用角度          5  */
#define _COLLISION_ANGLE_01   10     /* 衝突回避用角度          10 */
#define _COLLISION_ANGLE_02   50     /* 衝突回避用角度          45 */
#define _COLLISION_ANGLE_03   60     /* 衝突回避用角度          90 */
#define _ROT_MIGI        0      /* 衝突回避用回転方向          */
#define _ROT_HIDARI       1


/************************************************************************
*  BOIDSに必要な
************************************************************************/
typedef struct {              /* 座標系標準形             */
  double     x;
  double     y;
}  Vector_str;


typedef struct Iwashi_tab {         /* iwashiの本体             */
  Vector_str   Pos;          /* iwashiの座標             */
  Vector_str   Vec;          /* 速度の成分              */
  unsigned char  CollisionStatus[20];  /* 衝突用ステータス           */
} Iwashi_str;

Iwashi_str     iwashi[_POD_COUNT_MAX];
                      /* BOIDS本体              */
struct field_tab {             /* フィールド限界の作成         */
  int       xMin;
  int       yMin;
  int       xMax;
  int       yMax;
} field;



namespace ProtoType {

  using namespace System;
  using namespace System::ComponentModel;
  using namespace System::Collections;
  using namespace System::Windows::Forms;
  using namespace System::Data;
  using namespace System::Drawing;

  /// <summary>
  /// MyForm の概要
  /// </summary>
  public ref class MyForm : public System::Windows::Forms::Form
  {
  public:
    Graphics^        gf;     /*                   */
    Bitmap^         canvas;   /*                   */
    System::Drawing::Pen ^ PodPen;   /* ポッドに使用されるペン        */
    System::Drawing::Pen ^ BlackPen;  /* 黒色のペン              */
    System::Drawing::Pen ^ RedPen;   /* 赤色のペン              */
    System::Drawing::Pen ^ GreenPen;  /* 緑色のペン              */
    System::Drawing::Pen ^ BluePen;  /* 青色のペン              */
    System::Drawing::Pen ^ YellowPen; /* 黄色のペン              */

    int           kosuMAX;  /* 変更された最大値           */
    double         PodSize;  /* ポッドサイズ             */
    double         PodHalfSize;/* ポッドの半径 (1/2のサイズ事前計算) */
    array<double>^     sinAngle;  /* sin(theta)              */
    array<double>^     cosAngle;  /* cos(theta)              */
    double         collision_dist;
                      /* 衝突回避用距離            */
    double         judge_distFar;
                      /* 判別距離1 最大判別距離        */
    double         judge_distNear;
                      /* 判別距離2 = 判別距離1 / 2      */
    double         judge_width;/* 検索横条件              */
     double         judge_height;/* 検索縦条件             */

    MyForm(void)
    {

      InitializeComponent();
      //
      //TODO: ここにコンストラクター コードを追加します
      //

/************************************************************************
*  初期スクリーン設定                         *
************************************************************************/
      //M_PIctureBoxを対象とするビットマップImageオブジェクトを作成する
      canvas = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);
      gf = Graphics::FromImage(canvas);
                      /* メインイメージ用キャンバス          */

      PodPen = gcnew Pen(Color::Blue, 1);
      BlackPen= gcnew Pen(Color::Black, 1);  /* 黒色のペン              */
      RedPen = gcnew Pen(Color::Red,  1);  /* 赤色のペン              */
      GreenPen= gcnew Pen(Color::Green, 1);  /* 緑色のペン              */
      BluePen = gcnew Pen(Color::Blue, 1);  /* 青色のペン              */
      YellowPen= gcnew Pen(Color::Yellow,1); /* 黄色のペン              */

      PodPen->EndCap = System::Drawing::Drawing2D::LineCap::ArrowAnchor;
                      /* ポッド中心に移動方向を示す矢印を出す     */
    }


  protected:
    /// <summary>
    /// 使用中のリソースをすべてクリーンアップします。
    /// </summary>
    ~MyForm()
    {
      if (components)
      {
        delete components;
      }
    }


  private:
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>

/************************************************************************
*  位置のセッター                           *
************************************************************************/
    void  setPosision(int index, double x, double y)
    {
      iwashi[index].Pos.x = x;
      iwashi[index].Pos.y = y;
    }

/************************************************************************
*  速度のセッター                           *
************************************************************************/
    void  setVelocity(int index, double vx, double vy)
    {
      iwashi[index].Vec.x = vx;
      iwashi[index].Vec.y = vy;
    }


/************************************************************************
*  ベクトルv1、v2の距離を算出する                   *
************************************************************************/
    void  Vector_Diff(Vector_str *diff,Vector_str  *v1,Vector_str *v2)
    {
      diff->x = v1->x - v2->x;
      diff->y = v1->y - v2->y;
    }


/************************************************************************
*  二点間の距離算出                          *
************************************************************************/
    double distanceTo(Vector_str  *v1,Vector_str *v2)
    {
      Vector_str   dPos;

      Vector_Diff(&dPos, v1, v2);

      return sqrt(dPos.x * dPos.x + dPos.y * dPos.y);
                      /* 距離を算出する            */
    }



/************************************************************************
*  ステータス設定部                          *
************************************************************************/
    void  SetupStatus(int index, Iwashi_str  *IwashiThis)
    {
      Vector_str   Vec;
      int       patternNo;
      int       Far_Wal;
      int       Far_Pod;
      double     theta;
      int       dir;
      int       rot;


      patternNo  = 0;
      Far_Pod = 0;
      Far_Wal = 0;
      if ((IwashiThis->CollisionStatus[0] != 0)
            ||
        (IwashiThis->CollisionStatus[2] != 0)
            ||
        (IwashiThis->CollisionStatus[3] != 0)
            ||
        (IwashiThis->CollisionStatus[5] != 0))
      {  /* 進行方向右に壁            */
        patternNo |= 0x0001;
        if ((IwashiThis->CollisionStatus[3] != 0)
              ||
          (IwashiThis->CollisionStatus[5] != 0))
        {
          Far_Wal |= 0x0001;
        }

      }

      if ((IwashiThis->CollisionStatus[1] != 0)
            ||
        (IwashiThis->CollisionStatus[4] != 0))
      {  /* 進行方向左に壁            */
        patternNo |= 0x0002;
        if (IwashiThis->CollisionStatus[4] != 0)
        {
          Far_Wal |= 0x0002;
        }
      }

      if (  (IwashiThis->CollisionStatus[6] != 0)
                ||
          (IwashiThis->CollisionStatus[8] != 0)
                ||
          (IwashiThis->CollisionStatus[9] != 0)
                ||
          (IwashiThis->CollisionStatus[11] != 0) )
      {  /* 進行方向右にポッド            */
        patternNo |= 0x0004;
        if (  (IwashiThis->CollisionStatus[9] != 0)
                ||
            (IwashiThis->CollisionStatus[11] != 0) )
        {
          Far_Pod |= 0x0004;
        }
      }

      if (  (IwashiThis->CollisionStatus[7] != 0)
                ||
          (IwashiThis->CollisionStatus[10] != 0) )
      {  /* 進行方向左にポッド            */
        patternNo |= 0x0008;
        if (IwashiThis->CollisionStatus[10] != 0)
        {
          Far_Pod |= 0x0008;
        }
      }


      if (patternNo != 0)
      {
        theta  = 0.0;
        dir   = 0;
        switch(patternNo)
        {
        case  1: /* 右壁     */
          dir   = _ROT_HIDARI;
          rot   = _COLLISION_ANGLE_01;
          break;

        case  2: /* 左壁     */
          dir   = _ROT_MIGI;
          rot   = _COLLISION_ANGLE_01;
          break;

        case  3: /* 左右壁    */
          dir   = _ROT_HIDARI;
          rot   = _COLLISION_ANGLE_02;
          break;

        case  4: /* 右ポッド   */
          dir   = _ROT_HIDARI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_01;
          }
          else
          {
            rot   = _COLLISION_ANGLE_00;
          }
          break;

        case  5: /* 右ポッド 右壁 */
          dir   = _ROT_HIDARI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_01;
          }
          else
          {
            rot   = _COLLISION_ANGLE_00;
          }
          break;

        case  6: /* 右ポッド 左壁 */
          dir   = _ROT_MIGI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_02;
          }
          else
          {
            rot   = _COLLISION_ANGLE_01;
          }
          break;

        case  7: /* 右ポッド 左右壁 */
          dir   = _ROT_HIDARI;
          rot   = _COLLISION_ANGLE_03;
          break;

        case  8: /* 左ポッド   */
          dir   = _ROT_MIGI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_01;
          }
          else
          {
            rot   = _COLLISION_ANGLE_00;
          }
          break;

        case  9: /* 左ポッド 右壁 */
          dir   = _ROT_HIDARI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_01;
          }
          else
          {
            rot   = _COLLISION_ANGLE_01;
          }
          break;

        case  10: /* 左ポッド 左壁 */
          dir   = _ROT_MIGI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_01;
          }
          else
          {
            rot   = _COLLISION_ANGLE_00;
          }
          break;

        case  11: /* 左ポッド 左右壁 */
          dir   = _ROT_MIGI;
          if (Far_Pod == 0)
          {
            rot   = _COLLISION_ANGLE_02;
          }
          else
          {
            rot   = _COLLISION_ANGLE_02;
          }
          break;

        case  12: /* 左右ポッド  */
          if ((Far_Pod & 0x04) == 0)
          {
            dir   = _ROT_HIDARI;
          }
          else
          {
            dir   = _ROT_MIGI;
          }
          rot   = _COLLISION_ANGLE_02;
          break;

        case  13: /* 左右ポッド 右壁 */
          dir   = _ROT_HIDARI;
          if ((Far_Pod & 0x08) == 0)
          {
            rot   = _COLLISION_ANGLE_02;
          }
          else
          {
            rot   = _COLLISION_ANGLE_01;
          }
          break;

        case  14: /* 左右ポッド 左壁 */
          dir   = _ROT_MIGI;
          if ((Far_Pod & 0x04) == 0)
          {
            rot   = _COLLISION_ANGLE_02;
          }
          else
          {
            rot   = _COLLISION_ANGLE_01;
          }
          break;

        case  15: /* 左右ポッド 左右壁 */
          dir   = _ROT_MIGI;
          rot   = _COLLISION_ANGLE_03;
          break;
        }

        if ( dir == 0 )
        {              /* 向かって右にいる場合     */
          Vec.x = IwashiThis->Vec.x * cosAngle[rot] - IwashiThis->Vec.y * sinAngle[rot];
          Vec.y = IwashiThis->Vec.x * sinAngle[rot] + IwashiThis->Vec.y * cosAngle[rot];
        }
        else
        {
          Vec.x = IwashiThis->Vec.x * cosAngle[rot] + IwashiThis->Vec.y * sinAngle[rot];
          Vec.y = -IwashiThis->Vec.x * sinAngle[rot] + IwashiThis->Vec.y * cosAngle[rot];
        }

        if (index == 0)
        {
          textBox3->Text = dir.ToString();
          textBox4->Text = patternNo.ToString();
        }
        IwashiThis->Vec.x = Vec.x;
        IwashiThis->Vec.y = Vec.y;
      }
    }


/************************************************************************
*  衝突検知                              *
************************************************************************/
    void  collisionCheck(int index,Iwashi_str  *IwashiThis)
    {
      int       AreaPx,AreaPy;
      Vector_str   AreaTempPos;
      Vector_str   absPos,TopPos;
      double     RotAng;
      Color      pixcelColor;
      int       c_judge;
      double     a_sin,a_cos;
      double     diff;

      Vector_str   walPos_near;  /* 距離が近い方             */
      double     walDst_near;
      int       walLR_near;
      Vector_str   walPos_far;   /* 距離が遠い方             */
      double     walDst_far;
      int       walLR_far;

      Vector_str   podPos_near;  /* 距離が近い方             */
      double     podDst_near;
      int       podLR_near;
      Vector_str   podPos_far;   /* 距離が遠い方             */
      double     podDst_far;
      int       podLR_far;
      int       j;

      for(j=0; j<20; j++)
      {
        iwashi[index].CollisionStatus[j] = 0;
      }

      RotAng = atan2(iwashi[index].Vec.y, iwashi[index].Vec.x);
                      /* 半径線を算出するための角度算出    */

      a_sin = sin(RotAng);
      a_cos = cos(RotAng);

                      /* 接触面回避のための+3       ↓*/
      TopPos.x = (PodHalfSize + 3) * a_cos + iwashi[index].Pos.x;
      TopPos.y = (PodHalfSize + 3) * a_sin + iwashi[index].Pos.y;

      podPos_near.x  = TopPos.x;   /* 初期値がないと異常線発生       */
      podPos_near.y  = TopPos.y;
      podPos_far.x  = TopPos.x;
      podPos_far.y  = TopPos.y;

      RotAng += _COLLISION_VIEW_ANGLE;
                      /* 半径線を算出するための角度算出    */
      a_sin = sin(RotAng);
      a_cos = cos(RotAng);

      walDst_near = judge_distNear;
      walLR_near = 0;
      walDst_far = judge_distFar;
      walLR_far  = 0;

      podDst_near = judge_distNear;
      podLR_near = 0;
      podDst_far = judge_distFar;
      podLR_far  = 0;

      for (AreaPx=(-1) * (int)judge_width; AreaPx <= (int)judge_width; AreaPx++)
      {
        for (AreaPy=(-1) * (int)judge_height; AreaPy <= 0; AreaPy++)
        {
    /************************************************************************
    *  進行方向を基準とした検索マトリックス座標算出            *
    ************************************************************************/
          AreaTempPos.x = AreaPx * a_cos - AreaPy * a_sin;
          AreaTempPos.y = AreaPx * a_sin + AreaPy * a_cos;
                        /* 進行方向へマトリックス回転         */

          absPos.x = (AreaTempPos.x + TopPos.x);
          absPos.y = (AreaTempPos.y + TopPos.y);
    /************************************************************************
    *  左右の壁の反射                           *
    ************************************************************************/
          if (absPos.x < field.xMin)
          {              /* 範囲はポッド半径の符号に注意     */
            continue;
          }
          else if (absPos.x > field.xMax)
          {
            continue;
          }

    /************************************************************************
    *  上下の壁の反射                           *
    ************************************************************************/
          if (absPos.y < field.yMin)
          {
            continue;
          }
          else if (absPos.y > field.yMax)
          {
            continue;
          }

    /************************************************************************
    *  検索対象ピクセルの色をみる                     *
    ************************************************************************/
          try{
            pixcelColor = canvas->GetPixel((int)absPos.x , (int)absPos.y);
            c_judge = pixcelColor.R + pixcelColor.G + pixcelColor.B;
          }
          catch (Exception^)
          {
            c_judge = 0;
          }

    /************************************************************************
    *  検索対象ピクセルが白以外を探す                   *
    ************************************************************************/
          if (c_judge != 765)
          {

    /************************************************************************
    *  検索対象全表示                           *
    ************************************************************************/
            if (checkBox17->Checked == false)
            {
              gf->DrawLine(YellowPen, (int)TopPos.x, (int)TopPos.y, (int)absPos.x, (int)absPos.y);
            }

    /************************************************************************
    *  検索対象距離測定                          *
    ************************************************************************/
            diff = fabs(distanceTo((Vector_str *)&TopPos.x , (Vector_str *)&absPos.x));

    /************************************************************************
    *  検索対象が壁(緑色)の検索                     *
    ************************************************************************/
            if ((pixcelColor.R == 0)&&(pixcelColor.G != 0)&&(pixcelColor.B == 0))
            {        /* 壁を判定する       */
              if (judge_distFar >= diff)
              {
                if (judge_distNear >= diff)
                {    /* 距離が近い方(judge_distNear)の選択    */
                  if (walDst_near > diff)
                  {
                    walDst_near = diff;
                    walPos_near.x = absPos.x;
                    walPos_near.y = absPos.y;
                    if (AreaPx > 0)
                    {
                      walLR_near |= 1;
                    }
                    else  if (AreaPx < 0)
                    {
                      walLR_near |= 2;
                    }
                    else
                    {
                      walLR_near |= 4;
                    }
                  }
                }
                else
                {
                  if (walDst_far > diff)
                  {
                    walDst_far = diff;
                    walPos_far.x = absPos.x;
                    walPos_far.y = absPos.y;
                    if (AreaPx > 0)
                    {
                      walLR_far |= 1;
                    }
                    else  if (AreaPx < 0)
                    {
                      walLR_far |= 2;
                    }
                    else
                    {
                      walLR_far |= 4;
                    }
                  }
                }
              }
            }

    /************************************************************************
    *  検索対象が物体(青色)の検索                    *
    ************************************************************************/
            else if ((pixcelColor.R == 0)&&(pixcelColor.G == 0)&&(pixcelColor.B != 0))
            {
              if (judge_distFar >= diff)
              {
                if (judge_distNear >= diff)
                {    /* 距離が近い方(judge_distNear)の選択    */
                  if (podDst_near > diff)
                  {
                    podDst_near = diff;
                    podPos_near.x = absPos.x;
                    podPos_near.y = absPos.y;
                    if (AreaPx > 0)
                    {
                      podLR_near |= 1;
                    }
                    else  if (AreaPx < 0)
                    {
                      podLR_near |= 2;
                    }
                    else
                    {
                      podLR_near |= 4;
                    }
                  }
                }
                else
                {
                  if (podDst_far > diff)
                  {
                    podDst_far = diff;
                    podPos_far.x = absPos.x;
                    podPos_far.y = absPos.y;
                    if (AreaPx > 0)
                    {
                      podLR_far |= 1;
                    }
                    else  if (AreaPx < 0)
                    {
                      podLR_far |= 2;
                    }
                    else
                    {
                      podLR_far |= 4;
                    }
                  }
                }

              }
            }
          }
/************************************************************************
*  検索対象ピクセルを点で表示                     *
************************************************************************/
          if (checkBox10->Checked == false)
          {
             canvas->SetPixel((int)absPos.x , (int)absPos.y, Color::Black);
                /* 検索領域ピクセルを描画する    */
          }
        }
      }


      if (walLR_near != 0)
      {
    /************************************************************************
    *  他の壁を進行方向右に検出                      *
    ************************************************************************/
        if ((walLR_near & 0x01) != 0)
        {
    /************************************************************************
    *  進行方向右に壁                           *
    ************************************************************************/
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)walPos_near.x, (int)walPos_near.y);
          }
          iwashi[index].CollisionStatus[0] |= 0x01;

        }

    /************************************************************************
    *  進行方向左に壁                           *
    ************************************************************************/
        if ((walLR_near & 0x02) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)walPos_near.x, (int)walPos_near.y);
          }
          iwashi[index].CollisionStatus[1] |= 0x01;
        }

    /************************************************************************
    *  進行方向前に壁                           *
    ************************************************************************/
        if ((walLR_near & 0x04) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)walPos_near.x, (int)walPos_near.y);
          }
          iwashi[index].CollisionStatus[2] |= 0x01;
        }
      }


      if (walLR_far != 0)
      {
    /************************************************************************
    *  他の壁を進行方向右に検出                      *
    ************************************************************************/
        if ((walLR_far & 0x01) != 0)
        {
    /************************************************************************
    *  進行方向右に壁                           *
    ************************************************************************/
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)walPos_far.x, (int)walPos_far.y);
          }
          iwashi[index].CollisionStatus[3] |= 0x01;

        }

    /************************************************************************
    *  進行方向左に壁                           *
    ************************************************************************/
        if ((walLR_far & 0x02) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)walPos_far.x, (int)walPos_far.y);
          }
          iwashi[index].CollisionStatus[4] |= 0x01;
        }

    /************************************************************************
    *  進行方向前に壁                           *
    ************************************************************************/
        if ((walLR_far & 0x04) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)walPos_far.x, (int)walPos_far.y);
          }
          iwashi[index].CollisionStatus[5] |= 0x01;
        }
      }


      if (podLR_near != 0)
      {
    /************************************************************************
    *  他のポッドを進行方向右に検出                    *
    ************************************************************************/
        if ((podLR_near & 0x01) != 0)
        {
    /************************************************************************
    *  進行方向右にポッド                         *
    ************************************************************************/
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)podPos_near.x, (int)podPos_near.y);
          }
          iwashi[index].CollisionStatus[6] |= 0x01;

        }

    /************************************************************************
    *  進行方向左にポッド                         *
    ************************************************************************/
        if ((podLR_near & 0x02) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)podPos_near.x, (int)podPos_near.y);
          }
          iwashi[index].CollisionStatus[7] |= 0x01;
        }

    /************************************************************************
    *  進行方向前にポッド                         *
    ************************************************************************/
        if ((podLR_near & 0x04) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)podPos_near.x, (int)podPos_near.y);
          }
          iwashi[index].CollisionStatus[8] |= 0x01;
        }
      }


      if (podLR_far != 0)
      {
    /************************************************************************
    *  他のポッドを進行方向右に検出                    *
    ************************************************************************/
        if ((podLR_far & 0x01) != 0)
        {
    /************************************************************************
    *  進行方向右にポッド                         *
    ************************************************************************/
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)podPos_far.x, (int)podPos_far.y);
          }
          iwashi[index].CollisionStatus[9] |= 0x01;

        }

    /************************************************************************
    *  進行方向左にポッド                         *
    ************************************************************************/
        if ((podLR_far & 0x02) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)podPos_far.x, (int)podPos_far.y);
          }
          iwashi[index].CollisionStatus[10] |= 0x01;
        }

    /************************************************************************
    *  進行方向前にポッド                         *
    ************************************************************************/
        if ((podLR_far & 0x04) != 0)
        {
          if (checkBox20->Checked == false)
          {
            gf->DrawLine(BlackPen, (int)TopPos.x, (int)TopPos.y, (int)podPos_far.x, (int)podPos_far.y);
          }
          iwashi[index].CollisionStatus[11] |= 0x01;
        }
      }

    /************************************************************************
    *  シナプスに見立てたチェックボックスに表示              *
    ************************************************************************/
      if (index == 0)
      {
        for(j=0; j<20; j++)
        {
          if (iwashi[index].CollisionStatus[j] != 0)
          {
            switch(j)
            {
            case  0:
              checkBox1->Checked = true;
              break;
            case  1:
              checkBox2->Checked = true;
              break;
            case  2:
              checkBox3->Checked = true;
              break;
            case  3:
              checkBox4->Checked = true;
              break;
            case  4:
              checkBox5->Checked = true;
              break;
            case  5:
              checkBox6->Checked = true;
              break;
            case  6:
              checkBox7->Checked = true;
              break;
            case  7:
              checkBox11->Checked = true;
              break;
            case  8:
              checkBox12->Checked = true;
              break;
            case  9:
              checkBox13->Checked = true;
              break;
            case  10:
              checkBox14->Checked = true;
              break;
            case  11:
              checkBox15->Checked = true;
              break;
            }
          }
          else
          {
            switch(j)
            {
            case  0:
              checkBox1->Checked = false;
              break;
            case  1:
              checkBox2->Checked = false;
              break;
            case  2:
              checkBox3->Checked = false;
              break;
            case  3:
              checkBox4->Checked = false;
              break;
            case  4:
              checkBox5->Checked = false;
              break;
            case  5:
              checkBox6->Checked = false;
              break;
            case  6:
              checkBox7->Checked = false;
              break;
            case  7:
              checkBox11->Checked = false;
              break;
            case  8:
              checkBox12->Checked = false;
              break;
            case  9:
              checkBox13->Checked = false;
              break;
            case  10:
              checkBox14->Checked = false;
              break;
            case  11:
              checkBox15->Checked = false;
              break;
            }
          }
        }
      }

    }

/************************************************************************
*  移動方向の矢印付きポッドを指定位置に描画する            *
************************************************************************/
    void  move(int  index,Iwashi_str  *IwashiThis)
    {
      double     newV;


/************************************************************************
*  ステータス設定部                          *
************************************************************************/
      SetupStatus(index, (Iwashi_str *)IwashiThis);


/************************************************************************
*  速さを最大に調整                          *
************************************************************************/
      newV = sqrt(IwashiThis->Vec.x * IwashiThis->Vec.x + IwashiThis->Vec.y * IwashiThis->Vec.y);
      IwashiThis->Vec.x  *= _MAX_VELOCITY / newV;
      IwashiThis->Vec.y  *= _MAX_VELOCITY / newV;
        /* 最大速度で調整する          */

/************************************************************************
*  原因不明の壁通過現象がある為一時的の挿入する            *
*  左右の壁の反射                           *
************************************************************************/
      if ((IwashiThis->Pos.x - PodHalfSize) < field.xMin)
      {  /* 範囲はポッド半径の符号に注意     */
        IwashiThis->Vec.x = fabs(IwashiThis->Vec.x);
      }
      else if ((IwashiThis->Pos.x + PodHalfSize) > field.xMax)
      {
        IwashiThis->Vec.x = (-1) * fabs(IwashiThis->Vec.x);
      }

/************************************************************************
*  上下の壁の反射                           *
************************************************************************/
      if ((IwashiThis->Pos.y - PodHalfSize) < field.yMin)
      {
        IwashiThis->Vec.y = fabs(IwashiThis->Vec.y);
      }
      else if ((IwashiThis->Pos.y + PodHalfSize) > field.yMax)
      {
        IwashiThis->Vec.y = (-1) * fabs(IwashiThis->Vec.y);
      }

      IwashiThis->Pos.x += (IwashiThis->Vec.x * _INTERVAL_SEC);
      IwashiThis->Pos.y += (IwashiThis->Vec.y * _INTERVAL_SEC);
                      /* 新しい座標値を算出する        */
    }


/************************************************************************
*  群れ全体を表示する                         *
************************************************************************/
    void  moveall(void)
    {
      static int     theta=0;
      static Iwashi_str  pos_Stock;
      static int     pos_Stock_Flag=0xff;

      gf->Clear(Color::White);

      for (int  i = 0; i<kosuMAX; i++)
      {
        move(i, (Iwashi_str *)&iwashi[i].Pos.x);
      }
    }


/************************************************************************
*  群れ全体を表示する                         *
************************************************************************/
    void  draw(void)
    {
      int       i;
      Vector_str   yajirushi;
      double     ang;

      gf->DrawRectangle(GreenPen, field.xMin, field.yMin, field.xMax-1, field.yMax-1);

      if (checkBox9->Checked == true)
      {
        gf->DrawLine(GreenPen, field.xMax / 4, field.yMax / 3, field.xMax * 3 / 4, field.yMax * 3 / 4);
      }


/************************************************************************
*  boids群れ全体                            *
************************************************************************/
      for (i = 0; i<kosuMAX; i++)
      {
        ang = atan2(iwashi[i].Vec.y, iwashi[i].Vec.x);
                      /* 半径線を算出するための角度算出    */

        yajirushi.x = PodHalfSize * cos(ang);
        yajirushi.y = PodHalfSize * sin(ang);
                      /* 半径線の頂点座標 一応矢印      */

        gf->DrawEllipse(BluePen, (int)(iwashi[i].Pos.x - PodHalfSize), (int)(iwashi[i].Pos.y - PodHalfSize),
				(int)PodSize, (int)PodSize);
        /*【描画注意点】
          描画座標はポッドの中心点を指しているのではなく
          四角の左上でY座標も下向きプラスであるため
          下記で変換している。
        */
        gf->DrawLine(PodPen, (int)(iwashi[i].Pos.x), (int)(iwashi[i].Pos.y),
			(int)(iwashi[i].Pos.x + yajirushi.x), (int)((iwashi[i].Pos.y + yajirushi.y)));
                      /* 矢印の表示              */
      }
      pictureBox1->Image = canvas;
    }

/************************************************************************
*  新規にポッドを作成し表示する                    *
************************************************************************/
    void  CreateIwashi(void)
    {
      for (int i = 0; i<_POD_COUNT_MAX; i++)
      {
        iwashi[i].Pos.x = _CANVAS_WIDTH / 2;
        iwashi[i].Pos.y = _CANVAS_HEIGHT / 2;

        iwashi[i].Vec.x = 0.0;
        iwashi[i].Vec.y = 0.0;
      }


      Random^     rr;
      double     x, y;
      double     spd;
      double     ang;
      double     MAXSpeed;

      rr = gcnew Random();
      MAXSpeed = _MAX_VELOCITY;

      for (int i = 0; i<kosuMAX; i++)
      {
        if (i != 0)
        {
          x = (double)rr->Next(0, (int)(field.xMax- PodSize*2)) + PodSize;
          y = (double)rr->Next(0, (int)(field.yMax- PodSize*2)) + PodSize;
        }              /* ランダムな位置を作成           */
        else
        {
          x = iwashi[i].Pos.x;
          y = iwashi[i].Pos.y;
        }
        setPosision(i, x, y);

        spd = (double)rr->Next(0, (int)(MAXSpeed / 2)) + MAXSpeed / 2.0;
        ang = _DegreeToRadian(rr->Next(0, 360));

        setVelocity(i, spd * cos(ang), spd * sin(ang));
      }
    }


/************************************************************************
*  ボイド位置・速度更新初期値設定                   *
************************************************************************/
    private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)
    {
      timer1->Interval = _INTERVAL_TIM;
                      /* 間隔秒単位                */


      try {
        kosuMAX = int::Parse(textBox1->Text);
                      /* 全体の個数を入力する           */
        if (kosuMAX > _POD_COUNT_MAX)
        {
          kosuMAX = _POD_COUNT_MAX;
        }

        PodSize = int::Parse(textBox2->Text);
                      /* ポッドサイズを入力する          */
      }
      catch (Exception^)
      {
        kosuMAX = _POD_COUNT_MAX;
        PodSize = _POD_DRAW_SIZE;
      }
      PodHalfSize = (double)(PodSize / 2);
      collision_dist = PodHalfSize + _COLLISION_DISTANCE;
                      /* 衝突回避用距離              */
      judge_width = (collision_dist + PodHalfSize);
                      /* 検索横条件                */
      judge_height= (collision_dist * 3);
                      /* 検索縦条件                */

      judge_distFar = sqrt(judge_width * judge_width + judge_height * judge_height);
                      /* 判別距離1 最大判別距離          */
      judge_distNear = judge_distFar / 2.0;
                      /* 判別距離2 = 判別距離1 / 2        */

                      /* ポッドの半径事前計算           */
      field.xMin = 0;         /* メインイメージキャンバスの範囲設定    */
      field.yMin = 0;
      field.xMax = _CANVAS_WIDTH;
      field.yMax = _CANVAS_HEIGHT;

      sinAngle = gcnew array<double>(360);
      cosAngle = gcnew array<double>(360);

      for (int i = 0; i < 360; i++)
      {
        sinAngle[i] = sin(_DegreeToRadian((double)i));
        cosAngle[i] = cos(_DegreeToRadian((double)i));

      }

      CreateIwashi();

      timer1->Enabled = true;
    }


/************************************************************************
*  ポッドを移動させる                         *
************************************************************************/
    private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e)
    {
      moveall();
      draw();

/************************************************************************
*  衝突検知                              *
************************************************************************/
      if (checkBox8->Checked == false)
      {
        for (int  i = 0; i<kosuMAX; i++)
        {
          collisionCheck(i, (Iwashi_str  *)&iwashi[i].Pos.x);
        }
      }

      pictureBox1->Image = canvas;
    }

/************************************************************************
*  ポッドを停止させる                         *
************************************************************************/
    private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e)
    {
      timer1->Enabled = false;
    }
  };
}





HOME   > BOIDSv2.00 ~纏メル~