2D-Kollisionserkennung

Aus Spieleprogrammierer-Wiki
(Unterschied zwischen Versionen)
Wechseln zu: Navigation, Suche
[unmarkierte Version][unmarkierte Version]
(Allgemeiner Ansatz)
(Kollision Kreis-Strecke)
Zeile 452: Zeile 452:
 
Allerdings ist die Strecke nur der Teil der Geraden, für den <math>t\in [0,1]</math> ist. Also setzt man  
 
Allerdings ist die Strecke nur der Teil der Geraden, für den <math>t\in [0,1]</math> ist. Also setzt man  
 
<math>t*=\begin{cases}0&t<0\\t& t\in [0,1]\\1& t > 1\end{cases}</math>
 
<math>t*=\begin{cases}0&t<0\\t& t\in [0,1]\\1& t > 1\end{cases}</math>
Der Punkt auf der Strecke, der dem Kreis am nähesten ist, ist dann <math>\boldsymbol{d} = \boldsymbol{x}+\boldsymbol{a}\cdot t*</math>. Wenn nun <math>||\boldsymbol{m}-\boldsymbol{x}||<r^2</math>, dann Kollidiert der Kreis im Punkt '''d''' mit der Strecke.
+
Der Punkt auf der Strecke, der dem Kreis am nähesten ist, ist dann <math>\boldsymbol{d} = \boldsymbol{x}+\boldsymbol{a}\cdot t*</math>. Wenn nun <math>||\boldsymbol{m}-\boldsymbol{x}||^2<r^2</math>, dann Kollidiert der Kreis im Punkt '''d''' mit der Strecke.
 +
 
 +
=====Komplexität=====
 +
Diese Berechnungen benötigen 0 Quadratwurzeln, 3*n Multiplikationen und n Divisionen und lassen sich damit sehr schnell durchführen.
 +
 
 +
===Kollision Rechteck-Kreis (2D)===
 +
Ein Rechteck fasst man als 4 Strecken auf. Man berechnet den Minimalen Abstand (und die Position des Basispunkts) des Kreises von allen 4 Seiten, nimmt von den 4 Abständen (bzw. deren Quadrate, um Wurzeln zu vermeiden) das Minimum. Wenn dieses kleiner als r² ist, dann kollidiert der Kreis mit dem Rechteck im dazugehörigen Basispunkt.
 +
 
 +
{{Spoiler|<xh4>Implementierung</xh4>|
 +
{{Spoiler|
 +
<xh5>Implementierung in C++</xh5>
 +
|
 +
<sourcecode lang="cpp" tab="4">
 +
Vector2 PointLineDist(Vector2 point, Vector2 linestart, Vector2 lineend)
 +
{
 +
      Vector2 a = lineend - linestart;
 +
      Vector2 b = point - linestart;
 +
      double t = dot(a, b)/(length(a)²);
 +
      if (t < 0) t = 0;
 +
      if (t > 1) t = 1;
 +
      return linestart + a * t;
 +
}
 +
 
 +
struct CollisionResult
 +
{
 +
      bool isCollided;
 +
      Vector2 collisionPoint;
 +
      float distanceSq;
 +
}
 +
 
 +
// Gibt zurück, ob eine Kollision stattfand und wenn ja, wo, und wie lang der (minimale, quadratische) Abstand zum Rechteck ist.
 +
CollisionResult RectangleCircleKollision(Rect rect, Circle circle)
 +
{
 +
      float minDistSq = HUGE_VAL;
 +
      Vector2 basePoint = Vector2(0,0);
 +
      // Seiten durchgehen, Schleife kann (bzw muss, je nachdem wie Rect aussieht) entrollt werden
 +
      for(int i=0; i<4 ;i++)
 +
      {
 +
            Vector2 base = PointLineDist(circle.mid, rect.points[i], rect.points[ (i+1) % 4]);
 +
            if(lengthsq(circle.mid-base)<minDistSq)
 +
            {
 +
                  // Kürzerer Abstand, neu zuweisen.
 +
                  minDistSq = lengthsq(circle.mid - base);
 +
                  basePoint = base;
 +
            }
 +
      }
 +
      return {minDistSq < circle.radius * circle.radius,
 +
              basePoint,
 +
              minDistSq};
 +
}
 +
</sourcecode>
 +
}}
 +
}}

Version vom 11. September 2012, 11:56 Uhr

Klicke hier, um diese Version anzusehen.

Meine Werkzeuge
Namensräume
Varianten
Aktionen
Navigation
Werkzeuge