1

今日は、Boid をシミュレートする AI プログラムの作成と投稿に忙殺されました。現在、私は動き回る単一の「ボイド」を取得することに取り組んでいます。「ボイド」は、その「前方ベクトル」を象徴する線を引いた円(省略記号)です。

class SwarmCir
{
    public float _pointX;
    public float _pointY;
    public float _height;
    public float _width;
    Pen _pen = new Pen(Color.Black);
    PointF _ForwardPoint = new PointF(0, 0);
    float rotAng = 0.0f;

    public SwarmCir()
    {
        _pointX = 1.0f;
        _pointY = 1.0f;
        _height = 5.0f;
        _width = 5.0f;
        _ForwardPoint.X = 7.0f;
        _ForwardPoint.Y = 7.0f;
    }
    public SwarmCir(Point XY)
    {
        _pointX = XY.X;
        _pointY = XY.Y;
        _height = 5.0f;
        _width = 5.0f;
    }
    public SwarmCir( Point XY, float Height, float Width )
    {
        _pointX = XY.X;
        _pointY = XY.Y;
        _height = Height;
        _width = Width;
    }
    public void SetPen(Pen p)
    {
        _pen = p;
    }
    public void Draw(Graphics g)
    {
        g.DrawEllipse(_pen, _pointX, _pointY, _width, _height);
        g.DrawLine(_pen, new PointF(_pointX, _pointY), _ForwardPoint);
    }
    public void Rotate(PaintEventArgs e)
    {
        e.Graphics.TranslateTransform(_pointX, _pointY);
        e.Graphics.RotateTransform(rotAng);
        e.Graphics.TranslateTransform(-_pointX, -_pointY);
    }
    public PointF ForwardVec()
    {
        PointF temp = new PointF();
        temp.X = _pointX - _ForwardPoint.X;
        temp.Y = _pointY - _ForwardPoint.Y;
        return Normalize(temp);
    }
    public PointF Normalize(PointF p)
    {
        PointF temp = new PointF();
        if (p.X > p.Y)
        {
            temp.X = 1;
            temp.Y = p.Y / p.X;
        }
        else if (p.Y > p.X)
        {
            temp.Y = 1;
            temp.X = p.X / p.Y;
        }
        else
        {
            return new PointF(1, 1);
        }
        return temp;
    }
    public void MoveForward()
    {
        _pointX += ForwardVec().X;
        _pointY += ForwardVec().Y;
    }
    public void MoveBackwards()
    {
        _pointX -= ForwardVec().X;
        _pointY -= ForwardVec().Y;
    }
    public void TurnLeft()
    {
        rotAng += 10.0f;
    }
    public void TurnRight()
    {
        rotAng -= 10.0f;
    }
}

現在、このクラスを実装するプログラムを実行しているときに、デフォルトの SwarmCir() をインスタンス化し、下部にある移動関数を呼び出すだけで、非常に奇妙な結果が得られます。基本的に、「W」で円を「前方ベクトル」に沿って移動させたいのです。明らかに「S」の場合は逆です。それから回す時はちゃんと形と線が曲がって欲しいです。さらに情報が必要な場合はお問い合わせください。完全な AI ワークベンチに向けて取り組んでいます。

4

2 に答える 2

2

円と線しか描いていないので、Rotate メソッドで使用される変換はスキップします。また、前方ポイントと rotAngle の代わりに前方ベクトルをクラスに格納します。また、float _pointX/_pointY の代わりに位置に PointF を使用し、幅/高さの代わりに半径を使用します。これらは円に対して等しいためです。また、クラス外からの変更を避けるために、フィールドをプライベートにします。

class SwarmCir
{
  private PointF _point;
  private PointF _forwardVector = new PointF(1, 0);
  private float _radius = 2.5f;
  private float _vectorLength = 5.0f;
  private Pen _pen = new Pen(Color.Black);

次に、円の中心点として _point を使用します (コードでは、_pointX/_pointY は円の上部/左側の点を参照します)。draw メソッドと move メソッドは次のようになります。

public void Draw(Graphics g)
{
  g.DrawEllipse(_pen, _point.X - _radius, _point.Y - _radius, 2 * _radius, 2 * _radius);
  g.DrawLine(_pen, _point,
      new PointF(_point.X + _forwardVector.X * _vectorLength,
                 _point.Y + _forwardVector.Y * _vectorLength));
}

public void MoveForward()
{
  _point.X += _forwardVector.X;
  _point.Y += _forwardVector.Y;
}

ところで、PointF とスカラーの加算と乗算を容易にするために、PointF の拡張メソッドをいくつか定義することがよくあります。

static class PointFExtensions
{
  public static PointF Add(this PointF point, PointF other)
  {
    return new PointF(point.X + other.X, point.Y + other.Y);
  }

  public static PointF Add(this PointF point, float value)
  {
    return new PointF(point.X + value, point.Y + value);
  }

  public static PointF Multiply(this PointF point, PointF other)
  {
    return new PointF(point.X * other.X, point.Y * other.Y);
  }

  public static PointF Multiply(this PointF point, float value)
  {
    return new PointF(point.X * value, point.Y * value);
  }
}

私の意見では、これにより draw メソッドと move メソッドのコードがもう少しエレガントになります。

public void Draw(Graphics g)
{
  g.DrawEllipse(_pen, _point.X - _radius, _point.Y - _radius, 2 * _radius, 2 * _radius);
  g.DrawLine(_pen, _point, _point.Add(_forwardVector.Multiply(_vectorLength)));
}

public void MoveForward()
{
  _point = _point.Add(_forwardVector);
}

よし、残りは回転だけだ。Rotate メソッドを PointFExtensions に追加することから始めます。

public static PointF Rotate(this PointF point, double angle)
{
  angle *= Math.PI / 180.0; // Convert from degrees to radians
  return new PointF(
      Convert.ToSingle(point.X * Math.Cos(angle) - point.Y * Math.Sin(angle)),
      Convert.ToSingle(point.X * Math.Sin(angle) + point.Y * Math.Cos(angle)));
}

turn メソッドは次のようになります。

public void TurnLeft()
{
  _forwardVector = _forwardVector.Rotate(10.0f);
}

それがうまくいくことを願っています。このコードをコンパイルおよびテストしていないため、タイプミスがある可能性があります...

于 2012-04-19T07:35:04.437 に答える
0

私はあなたのコードをざっと見てきましたが、TurnLeft()あなたTurnRight()はフィールドを変更しましたrotAng。これは、クラスの他の場所では使用しないフィールドです。おそらくForwardVec()それを使用する必要がありますか?おそらく、いくつかのx座標に?を掛けMath.Cos(rotAng)、ay座標にMath.Sin(rotAng)

ここで推測するだけ...

于 2012-04-18T18:32:26.410 に答える