Da dies auf Ihrer anderen Frage basiert, gebe ich eine Lösung für den Fall, dass das Rechteck achsenausgerichtet ist.
Zunächst bauen Sie das Rechteck Ihres aktuellen Objekts mit den folgenden Werten auf:
int boxLeft = box.X;
int boxRight = boxLeft + box.Width;
int boxTop = box.Y;
int boxBottom = boxTop + box.Height;
Als nächstes müssen Sie die Position des alten Objekts haben (die Sie auf jedem Objekt speichern oder einfach an eine Funktion übergeben können), um das Rechteck des alten Objekts zu erstellen (wenn es nicht kollidierte):
int oldBoxLeft = box.OldX;
int oldBoxRight = oldBoxLeft + box.Width;
int oldBoxTop = box.OldY;
int oldBoxBottom = oldBoxTop + box.Height;
Um zu wissen, woher die Kollision stammt, müssen Sie die Seite finden, auf der sich die alte Position nicht im Kollisionsbereich befand und auf der sich ihre neue Position befindet. Denn wenn Sie daran denken, passiert Folgendes, wenn Sie kollidieren: Eine Seite, die nicht kollidiert, tritt in ein anderes Rechteck ein.
So können Sie dies tun (diese Funktionen setzen eine Kollision voraus. Sie sollten nicht aufgerufen werden, wenn keine Kollision vorliegt):
bool collidedFromLeft(Object otherObj)
{
return oldBoxRight < otherObj.Left && // was not colliding
boxRight >= otherObj.Left;
}
Rince und wiederholen.
bool collidedFromRight(Object otherObj)
{
return oldBoxLeft >= otherObj.Right && // was not colliding
boxLeft < otherObj.Right;
}
bool collidedFromTop(Object otherObj)
{
return oldBoxBottom < otherObj.Top && // was not colliding
boxBottom >= otherObj.Top;
}
bool collidedFromBottom(Object otherObj)
{
return oldBoxTop >= otherObj.Bottom && // was not colliding
boxTop < otherObj.Bottom;
}
Nun zur tatsächlichen Verwendung mit der Kollisionsantwort aus der anderen Frage:
if (collidedFromTop(otherObj) || collidedFromBottom(otherObj))
obj.Velocity.Y = -obj.Velocity.Y;
if (collidedFromLeft(otherObj) || collidedFromRight(otherObj))
obj.Velocity.X = -obj.Velocity.X;
Auch dies ist möglicherweise nicht die beste Lösung, aber so gehe ich normalerweise zur Kollisionserkennung vor.
Da die Frage teilweise mit dieser Frage identisch ist , werde ich einige Teile meiner Antwort erneut verwenden, um zu versuchen, Ihre Frage zu beantworten.
Definieren wir einen Kontext und einige Variablen, um die folgende Erklärung verständlicher zu machen. Das Darstellungsformular, das wir hier verwenden, passt wahrscheinlich nicht zur Form Ihrer eigenen Daten, sollte jedoch einfacher zu verstehen sein (tatsächlich können Sie die folgenden Methoden verwenden, indem Sie andere Arten von Darstellungen verwenden, sobald Sie das Prinzip verstanden haben).
Wir werden also eine achsenausgerichtete Begrenzungsbox (oder eine orientierte Begrenzungsbox ) und eine sich bewegende Entität betrachten .
Die Begrenzungsbox besteht aus 4 Seiten, und wir definieren jede als:
Seite1 = [x1, y1, x2, y2] (zwei Punkte [x1, y1] und [x2, y2])
Die sich bewegende Entität ist definiert als ein Geschwindigkeitsvektor (Position + Geschwindigkeit):
eine Position [posX, posY] und eine Geschwindigkeit [speedX, speedY] .
Mit der folgenden Methode können Sie bestimmen, welche Seite eines AABB / OBB von einem Vektor getroffen wird:
1 / Finden Sie die Schnittpunkte zwischen den unendlichen Linien, die durch die vier Seiten des AABB verlaufen, und der unendlichen Linie, die durch die Entitätsposition verläuft (Vorkollision), wobei der Entitätsgeschwindigkeitsvektor als Steigung verwendet wird. (Sie können entweder einen Kollisionspunkt oder eine undefinierte Zahl finden, die Parallelen oder überlappenden Linien entspricht.)
2 / Sobald Sie die Schnittpunkte kennen (falls vorhanden), können Sie nach solchen suchen, die innerhalb der Segmentgrenzen liegen.
3 / Wenn die Liste noch mehrere Punkte enthält (der Geschwindigkeitsvektor kann mehrere Seiten durchlaufen), können Sie anhand der Größen des Vektors vom Schnittpunkt zum Entitätsursprung nach dem nächstgelegenen Punkt vom Entitätsursprung suchen.
Anschließend können Sie den Kollisionswinkel mit einem einfachen Punktprodukt bestimmen.
----------
Mehr Details:
1 / Kreuzungen suchen
a / Bestimmen Sie die unendlichen Linien (Ax + Bx = D) anhand ihrer Parameterformen (P (t) = Po + tD).
Ich habe die Entitätspunktwerte verwendet, um die Methode zu veranschaulichen, aber dies ist genau dieselbe Methode, um die 4 seitlichen unendlichen Linien des Begrenzungsrahmens zu bestimmen (Verwenden Sie Po = [x1, y1] und D = [x2-x1; y2-y1] stattdessen).
b / Um den Schnittpunkt zweier unendlicher Linien zu finden, können wir das folgende System lösen:
Dies ergibt die folgenden Koordinaten für das Abfangen:
Wenn der Nenner ((A1 * B2) - (A2 * B1)) gleich Null ist, sind beide Linien parallel oder überlappen sich, andernfalls sollten Sie einen Schnittpunkt finden.
2 / Test auf die Segmentgrenzen. Da dies einfach zu überprüfen ist, sind keine weiteren Details erforderlich.
3 / Suchen Sie nach dem nächstgelegenen Punkt. Wenn die Liste noch mehrere Punkte enthält, können wir herausfinden, welche Seite dem Entitätsursprungspunkt am nächsten liegt.
a / Bestimmen Sie den Vektor, der vom Schnittpunkt zum Entitätsursprungspunkt verläuft
b / Berechnen Sie die Vektorgröße
4 / Nachdem Sie nun wissen, welche Seite getroffen wird, können Sie den Winkel mit einem Punktprodukt bestimmen.
a / Sei S = [x2-x1; y2-y1] ist der Seitenvektor, der getroffen wird, und E = [speedX; speedY] sei der Geschwindigkeitsvektor der Entität.
Mit der Vektorpunktproduktregel wissen wir das
Wir können also θ bestimmen, indem wir diese Gleichung ein wenig manipulieren ...
mit
Hinweis: Wie ich im anderen Fragenthread sagte, ist dies wahrscheinlich weder der effizienteste noch der einfachste Weg, dies zu tun. Dies ist genau das, was mir in den Sinn kommt, und ein Teil der Mathematik könnte vielleicht helfen.
Ich habe nicht mit einem konkreten OBB-Beispiel verifiziert (ich habe es mit einem AABB gemacht), aber es sollte auch funktionieren.
quelle
Eine einfache Möglichkeit besteht darin, die Kollision aufzulösen und dann die Kollisionsbox des sich bewegenden Objekts nacheinander um ein Pixel in jede Richtung zu verschieben und zu sehen, welche zu einer Kollision führen.
Wenn Sie es "richtig" und mit gedrehten Kollisionsformen oder beliebigen Polygonen machen möchten, empfehle ich, den Satz der Trennachse nachzulesen. Die Metanet-Software (die Leute, die das N-Spiel entwickelt haben) hat zum Beispiel einen großartigen Entwicklerartikel über SAT . Sie diskutieren auch die Physik.
quelle
Eine Möglichkeit wäre, die Welt um Ihr Rechteck zu drehen. "Die Welt" sind in diesem Fall nur die Objekte, die Sie interessieren: das Rechteck und der Ball. Sie drehen das Rechteck um seine Mitte, bis seine Grenzen mit den x- / y-Achsen ausgerichtet sind, und drehen dann den Ball um den gleichen Betrag.
Der wichtige Punkt hierbei ist, dass Sie den Ball um die Mitte des Rechtecks drehen, nicht um seine eigene.
Dann können Sie einfach wie bei jedem anderen nicht gedrehten Rechteck auf Kollision testen.
Eine andere Möglichkeit besteht darin, das Rechteck als vier verschiedene Liniensegmente zu behandeln und die Kollision mit jedem von ihnen separat zu testen. Auf diese Weise können Sie auf Kollision testen und herausfinden, welche Seite gleichzeitig kollidiert wurde.
quelle
Ich habe bei meinen Berechnungen feste Winkel verwendet, aber dies sollte Ihnen helfen
quelle