Fragensteller
Verständnis Frage zur Kollission

Frage
-
Hallo
Nachdem ich meine theoretische Abschlussprüfung endlich hinter mir habe versuche ich mich mal wieder mir der Fernschule bis zur praktischen Prüfung ab zu lenken.
Ich habe in diesem Heft ein lauffähiges Pong erstellt und stehe vor der Frage:
Warum wird der Ball nicht zurück "geschlagen" wenn er an seiner unteren Kante den Schläger berührt oder der Schläger den Ball dort berührt und warum wird er nicht in der oberen Ecke zurückgeschlagen obwohl der Schläger dort ist. Unfairer weise geht er dann ins Aus.
// setzt die Position des Balls Void zeichneBall(Point position) { Random ^zufall = gcnew Random(); ball -> Location = position; // stößt der Ball hinten an, dann die Richtung umdrehen if ((position.X + 10) >= spielfeldMaxX) ballPosition.richtungX = false; // stößt er unten bzw. oben an, ebenfalls if ((position.Y + 10) >= spielfeldMaxY) ballPosition.richtungY = true; else if (position.Y <= spielfeldMinY) ballPosition.richtungY = false; // ist er wieder vorne, prüfen wir, ob der Schläger in der Nähe ist // bitte in einer Zeile eingeben if ((position.X == spielfeldMinX) && ((schlaeger -> Top <= position.Y) && (schlaeger -> Bottom >= position.Y))) { if (ballPosition.richtungX == false) { // einen Punkt dazu und die Punkte ausgeben // bitte in einer Zeile eingeben zeichnePunkte(Convert::ToString(spielpunkte -> veraenderePunkte(punkteMehr))); } // die Richtung ändern ballPosition.richtungX = true; // und den Winkel ballPosition.winkel = zufall -> Next(winkelZufall); } // ist der Ball hinter dem Schläger? if (position.X < spielfeldMinX) { // fünf Punkte abziehen und die Punkte ausgeben // bitte in einer Zeile eingeben zeichnePunkte(Convert::ToString(spielpunkte -> veraenderePunkte(punkteWeniger))); // eine kurze Pause einlegen Threading::Thread::Sleep(1000); // und alles von vorne zeichneBall(Point(spielfeldMinX, position.Y)); ballPosition.richtungX = true; } } // setzt die Y - Position des Schlägers Void zeichneSchlaeger(Int32 Y) { // befindet sich der Schläger im Spielfeld? // bitte in einer Zeile eingeben if (((Y + schlaegerGroesse) < spielfeldMaxY) && (Y > spielfeldMinY)) schlaeger -> Top = Y; } // Schläger ist 50 groß
Definitiv kann ich sagen, dass ich eine Kollision direkt mit dem Schläger haben muss in der auch die Größe des Schlägers wieder zu finden ist.
Denn zu Anfang liegt der Ball in der Mitte des Spielfeldes und dies ist auch die Position des Schlägers. Im Programm selber sieht es eher so aus, als wenn der Ball eher in der unteren Hälfte des Schlägers anliegt. Es gibt nur die Abfrage ob der Schläger in der nähe ist, also wird der Ball denke ich nur dann zurückgeschlagen, wenn er eben genau wieder auf diese anfangs Position am Schläger auftrifft. Also ziemlich in der Mitte "untere Hälfte" des Schlägers.
Ich müsste also, wenn ich wollte die Position der oberen Ecke an der rechten Seite des Schlägers und die untere linke Ecke des Balls abfragen. Dann, wenn diese beiden Ecken kollidieren muss der Ball wieder zurückgeschlagen werden.
Liegt es wirklich nur daran, dass der Ball am Anfang ca. Mittig am Schläger liegt und diese Stelle wieder beim zurückschlagen getroffen werden muss?
Wie würde die Abfrage für die Kollision dann aussehen? Muss ich diese dann in der Abfrage, die nach der nähe des Schlägers fragt einbringen?
Schläger (10 * 50) und Ball (10 * 10) sind jeweils ein jeweils ein Panel, die wiederum in einem Panel liegen.
Im Moment habe ich keinen Plan ob ich das so richtig gesehen und gedeutet habe. Bin für jede Antwort dankbar, die mich weiter bringt
lieben Gruß
lempy
Alle Antworten
-
Hallo Lempy,
ich stehe gerade vor dem gleichen Problem. Ich gehe aber davon aus, dadurch, dass der ball 10x10 Pixel groß ist und nur der "Mittelpunkt" des Balles abgefragt wird, muss man hier noch die Entfernung zwischen Schlägerkante und Mittelpunkt des Balls prüfen.
Hast du hierfür schon eine Lösung? Ich verzweifle langsam :)
Viele Grüße
Paul
-
Evtl. weil position.X == spielfeldMinX geprüft wird.
Kann es sein, dass sich die Position pro Zeiteinheit um mehr als einen Koordinaten Punkt verschiebt... dann kann der Ball faktisch durch den Schläger durch springen.
BTW: Ein Ball ist rund... ;) dachte ich immer nicht eckig...
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
-
Eigentlich egal. Aber wenn Du Bewegungen mit mehr als einen Koordinatenpunkt in einer Zeiteinheit hast, dann musst Du schauen ob sich der Weg mit einem Gegenstand (Wand/Schläger) kreuzt...
Wenn Du Winkel mit einbeziehst hast Du normalerweise kein System das auf "ganzen" Koordinaten basiert.
Martin Richter -- MVP for VC++ [Germany] -- http://blog.m-ri.de
-
Also zunächst einmal können auch Gegenstände kollidieren, deren Weg sich nicht schneidet. Es reicht ja, wenn sich ihre äußeren Begrenzungen (nehmen wir der Einfachheit halber mal eine rechteckige Boundingbox) überlappen.
Will man aber die Kollision ganz einfach halten (und natürlich ggf. Überlappungen riskieren), ginge auch die einfache Wegkreuzung. Heißt: zwei Geraden bilden aus Start und Zielpunkt durch Zwei-Punkte-Form der Geradengleichung, anschließend Schnittpunkt ausrechnen und schauen ob bei beiden Geraden der Schnittpunkt zwischen den beiden Punkten liegt.
Da hier mit rechteckigen Begrenzungen gearbeitet wird, bietet sich m. M. nach an mit Rectangle.Intersect zu arbeiten, wobei die Rückgabe wieder ein Rectangle ist. Ist dessen Breite und Höhe jeweils >0, liegt eine Kollision bzw. Überlappung vor. Das spart die elendigen vielen IFs mit < min und > max und so. Also einfach Zielrechteck errechnen (Verschiebung der bisherigen Position um den Bewegungsvektor, selbe Ausmaße), und dann Zielrechtecke vergleichen.
Und Martin ... das Runde muss ins Eckige. ;-)
(also der runde Ball in die eckige Boundingbox)
LG, Dennis.
EDI Consultant/Developer
Ich nutze meistens VB6 und VS2005 bis VS2012
Bitte die Antworten sowie weitere hilfreiche Beiträge von Mitgliedern markieren. Vielen Dank.
-
So, hab den Fehler jetzt gefunden.
position.X und position.Y sind die Koordinaten der linken oberen Ecke des Balles. Bei einer "höhe" des Balles von 10 Pixel, geht beim Auftreffen des unteren Endes des Balles am oberen Ende des Schläger der Ball vorbei. Da die linke obere Ecke so gesehen außerhalb ist.
Zur Lösung. Man muss einfach bei der Abfrage ((schlaeger -> Top <= position.Y) 10 dazurechnen. dadurch hat auch das untere Ende des Balles kontakt zum Schläger.
if ((position.X == spielfeldMinX) && ((schlaeger -> Top <= position.Y + 10) && (schlaeger -> Bottom >= position.Y)))
Beim Codeausschnitt vom Lempy ist nicht ersichtlich, dass es hier nur das linke obere Eck des Balles auf Kollision überprüft wird, deswegen war die Beantwortung der Frage hier im Forum fast unmöglich.
Trotzdem vielen Dank, an alle die sich Gedanken gemacht haben.
Beste Grüße
Paul
- Als Antwort vorgeschlagen Dennis Becker Mittwoch, 28. August 2013 13:25
-
Hey Leute,
hatte diese Frage schon wieder vergessen und bin eben erst per Zufall wieder darauf gestoßen. Erst hat sich dabei nichts getan und jetzt sind ja so viele Antworten dabei.
Echt toll, dass sich doch noch was getan hat. Werde ich mir am Wochenende genauer ansehen.
Liebe Grüße
lempy