Entwickler-Ecke

Algorithmen, Optimierung und Assembler - Collision Detection mit SAT


huuuuuh - So 23.10.11 14:21
Titel: Collision Detection mit SAT
Hallo zusammen,

für ein Spiel, an dem ich derzeit hobby-mäßig arbeite, brauche ich einen Algorithmus, um die Kollision zwischen beliebigen Objekten erkennen zu können. Einfache Kollision mittels Rectangle.Intersect() ist zu ungenau, Pixelgenaue Kollision wird bei vielen Objekten zu langsam. Also habe ich mich ein wenig umgeschaut und SAT (http://en.wikipedia.org/wiki/Separating_axis_theorem) gefunden, welches ich dann versucht hab zu implementieren. Leider ohne Erfolg:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
public bool IntersectsWith(ICollidable obj)
        {
          List<Vector2[]>[] axes=new List<Vector2[]>[2];
         axes[0]=new List<Vector2[]>();
            axes[1]=new List<Vector2[]>();
           for (int i = 0; i < corners.Count; i++)
      {
               axes[0].Add(new Vector2[]{corners[i],i==corners.Count-1?corners[0]:corners[i+1]});
      }
            for (int i = 0; i < obj.Corners.Count; i++)
      {
               axes[1].Add(new Vector2[]{obj.Corners[i],i==obj.Corners.Count-1?obj.Corners[0]:obj.Corners[i+1]});
      }
            float[] minX = new float[2];
            float[] maxX = new float[2];
            float[] minY = new float[2];
            float[] maxY = new float[2];
            foreach (Vector2[] axes1 in axes[0])
            {
                minX[0]=Math.Min(axes1[0].X,axes1[1].X);
                    maxX[0] = Math.Max(axes1[0].X, axes1[1].X);
                    minY[0] = Math.Min(axes1[0].Y, axes1[1].Y);
                    maxY[0] = Math.Max(axes1[0].Y, axes1[1].Y);
                foreach(Vector2[] axes2 in axes[1])
                {
                    
                   bool[] xBetween=new bool[2];
       bool[] yBetween=new bool[2];
                   minX[1] = Math.Min(axes2[0].X, axes2[1].X);
                   maxX[1] = Math.Max(axes2[0].X, axes2[1].X);
                   minY[1] = Math.Min(axes2[0].Y, axes2[1].Y);
                   maxY[1] = Math.Max(axes2[0].Y, axes2[1].Y);

                   xBetween[0] = minX[0] > minX[1] && minX[0] < maxX[1];
                   xBetween[1] = maxX[0] > minX[1] && maxX[0] < maxX[1];

                   yBetween[0] = minY[0] > minY[1] && minY[0] < maxY[1];
                   yBetween[1] = maxY[0] > minY[1] && maxY[0] < maxY[1];
                    if(((xBetween[0]||xBetween[1])&&(yBetween[0]||yBetween[1])))
                        return true;
                }
            }
            return false;
            
        }

Gegeben sind zwei Listen von Punkten, welche die Eckpunkt beider Objekte sind. (corners und obj.Corners) Die obige Methode funktioniert leider nicht so richtig...
Hoffe ihr könnt mir dabei helfen, das hinzukriegen. hab gestern den ganzen Tag mit Hilfe von Google und Co. erfolglos versucht das hinzukriegen


Kha - So 23.10.11 15:16

Ich weiß nicht genau, was du von uns erwartest, aber zumindest ich habe den Algorithmus nicht so genau im Kopf, dass ich durch bloßes Draufblicken einen Bug finden könnte :) . Wenn du ihn aber tatsächlich verstanden hast, solltest du doch in der Lage sein, ihn parallel im Programm und auf dem Papier durchzugehen, bis du eine Abweichung feststellst - Debugging eben.


F34r0fTh3D4rk - So 23.10.11 22:33

Hier findest du eine ausführlichere Beschreibung des Algorithmus inklusive Quellcode (allerdings Delphi): http://wiki.delphigl.com/index.php/Tutorial_Separating_Axis_Theorem
Das hier ist auch sehr gut (und interaktiv): http://www.metanetsoftware.com/technique/tutorialA.html
Ich hoffe es hilft.