1

C# ゲーム プログラミングでのスプライトの衝突に関する C# スニペット コードがあります。

IsCollided メソッド、特にスプライトが衝突するかどうかを判断するための d1 と d2 の計算、この場合の Matrix Invert() と Multiphy の意味と使用、衝突を判断するためのカラー アルファ コンポーネントの使用を理解していません。 2スプライトの。

どうもありがとうございました。

public struct Vector
{
   public double X;
   public double Y;

   public Vector(double x, double y)
   {
      X = x;
      Y = y;
   }

   public static Vector operator -(Vector v, Vector v2)
   {
      return new Vector(v.X-v2.X, v.Y-v2.Y);
   }

   public double Length
   {
      get
      {
         return Math.Sqrt(X * X + Y * Y);
      }
   }
}

public class Sprite
{
    public Vector Position;
    protected Image _Image; 
    protected Bitmap _Bitmap;
    protected string _ImageFileName = "";
    public string ImageFileName
    {
       get { return _ImageFileName; }
       set
       {
          _ImageFileName = value;
          _Image = Image.FromFile(value);
          _Bitmap = new Bitmap(value);
        }
     }

    public Matrix Transform
    {
      get
      {
            Vector v = Position;
            if (null != _Image)
               v -= new Vector(_Image.Size) / 2;

            Matrix m = new Matrix();
            m.RotateAt(50.0F, new PointF(10.0F, 100.0F));
            m.Translate((float)v.X, (float)v.Y);
            return m; 
       }
    }

    public bool IsCollided(Sprite s2)
    {
        Vector v = this.Position - s2.Position;
        double d1 = Math.Sqrt(_Image.Width * _Image.Width + _Image.Height * _Image.Height)/2;
       double d2 = Math.Sqrt(s2._Image.Width * s2._Image.Width + s2._Image.Height * s2._Image.Height)/2;
       if (v.Length > d1 + d2)
           return false;

        Bitmap b = new Bitmap(_Image.Width, _Image.Height);
        Graphics g = Graphics.FromImage(b);
        Matrix m = s2.Transform;

        Matrix m2 = Transform;
        m2.Invert();

        Matrix m3 = m2;
        m3.Multiply(m);

        g.Transform = m3;

        Vector2F v2 = new Vector2F(0,0);
        g.DrawImage(s2._Image, v2);

        for (int x = 0; x < b.Width; ++x)
           for (int y = 0; y < b.Height; ++y)
           {
              Color c1 = _Bitmap.GetPixel(x, y);
              Color c2 = b.GetPixel(x, y);

              if (c1.A > 0.5 && c2.A > 0.5)
                  return true;
            }

       return false;
    }
}
4

1 に答える 1

3

少し複雑です。2 つの部分:

パート 1 (シンプル & 高速)

最初の部分 (v, d1 + d2 を含む) は、ボックスを使用して衝突テストを行う代わりに、画像の寸法を使用して境界円を構築するため、おそらく混乱を招きます。次に、これらの境界円を使用して簡単な衝突テストを実行します。これは、明らかに衝突していないスプライトを排除する「クイック アンド ダーティ」テストです。

「そこ(原文のまま)の半径の合計がそれらの中心間の距離よりも大きい場合、2つの円は重なります。したがって、ピタゴラスにより、次の場合に衝突が発生します。

(cx1-cx2)2 + (cy1-cy2)2 < (r1+r2)2"

このリンクの「境界円」セクションと、この回答の下部にある 2 番目のリンクを参照してください。

コメント付きのコード:

// Get the vector between the two sprite centres
Vector v = this.Position - s2.Position;

// get the radius of a circle that will fit the first sprite
double d1 = Math.Sqrt(_Image.Width * _Image.Width + _Image.Height * _Image.Height)/2;

// get the radius of a circle that will fit the second sprite
double d2 = Math.Sqrt(s2._Image.Width * s2._Image.Width + s2._Image.Height * s2._Image.Height)/2;

// if the distance between the sprites is larger than the radiuses(radii?) of the circles, they do not collide
if (v.Length > d1 + d2)
       return false;

注: ここでは、円の代わりに軸方向に整列したバウンディング ボックス テストの使用を検討することをお勧めします。幅と長さが異なる長方形がある場合は、より効果的/正確な最初のテストになります。

パート 2 (遅い)

コードを 100% チェックする時間はありませんが、2 番目の部分 (ステップ 1 で 2 つのスプライトが衝突する可能性があることを確認した後) は、より複雑な衝突テストを実行しています。スプライトの画像ソース、特にそのアルファ チャネルを使用して、ピクセルごとの衝突テストを実行しています。ゲームでは、透明度の表現を格納するためにアルファ チャネルがよく使用されます。値が大きいほど、イメージの不透明度が高くなります (つまり、0 は 100% 透明、1.0f は 100% 不透明になります)。

表示されているコードでは、両方のスプライトのピクセルがオーバーラップしており、両方のアルファ値が 0.5f より大きい場合、ピクセルは同じ空間を共有しており、ソリッド ジオメトリを表しているため、衝突しています。このテストを行うことで、衝突のテスト時にスプライトの透明な (つまり、見えない) 部分が考慮されなくなるため、コーナーなどで衝突しない円形のスプライトを作成できます。

これについては、もう少し詳しく説明しているリンクがあります。

于 2010-01-03T19:21:00.423 に答える