none
Verständnis Frage zur Kollission RRS feed

  • 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

    Dienstag, 14. Mai 2013 15:15

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

    Dienstag, 27. August 2013 07:50
  • 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

    Dienstag, 27. August 2013 08:05
    Moderator
  • das ist richtig, der "eckige Ball" bewegt sich um 10 Koordinatenpunkte. Sollte das auf 1 setzen oder ?? ;)

    Dienstag, 27. August 2013 08:11
  • 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

    Dienstag, 27. August 2013 14:28
    Moderator
  • 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.

    Mittwoch, 28. August 2013 10:19
  • 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
    Mittwoch, 28. August 2013 13:13
  • 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

    Mittwoch, 11. September 2013 16:56