Kollisionsproblem
-
Okay, dann hier mein nächster Vorschlag (Ball_Radius wird nicht mehr genutzt, kann also verworfen werden):
void Block::Collision( Sprite* Ball, PointManager* PM, DirectXAudio* DXAudio, Sprite* Funken ) { for( int i = 0; i < BlocksAnzahl; ++i ) { if( !daweg[i] ) continue; if( Blocks[i].RX() < Ball->RX() - Block_Width && Blocks[i].RX() < Ball->RX() - Block_Width + Ball->StepX ) continue; if( Blocks[i].RY() < Ball->RY() - Block_Height && Blcoks[i].RY() < Ball->RY() - Block_Height + Ball->StepY ) continue; if( Blocks[i].RX() > Ball->RX() + Ball_Durchmesser && Blocks[i].RX() > Ball->RX() + Ball_Durchmesser + Ball->StepX ) continue; if( Blocks[i].RY() > Ball->RY() + Ball_Durchmesser && Blocks[i].RY() > Ball->RY() + Ball_Durchmesser + Ball->StepY ) continue; daweg[i] = false; double yD, x; if( Ball->StepY ) yD = -Ball->RY() + Blocks[i].RY(); else yD = Ball->RY() - Blocks[i].RY() - Block_Height; x = yD * Ball->StepX / Ball->StepY + Ball->RX() + Ball_Durchmesser / 2; if( x < Blocks[i].RX() ) { Ball->SetX( 2 * x - Ball->RX() - Ball->StepX - Ball_Durchmesser ); Ball->StepX *= -1; } else if( x > Blocks[i].RX() + Block_Width ) { Ball->SetX( 2 * x - Ball->RX() - Ball->StepX - Ball_Durchmesser + 2 * Block_Width ); Ball->StepX *= -1; } else { Ball->SetY( ( Ball->StepX ? 2 : -2 ) * yD + Ball->RY() - Ball->StepY + Ball_Durchmesser ); Ball->StepY *= -1; } } }
Ich hoffe, dass es jetzt klappt...
mfG D1B
-
Ok vielen Dank.
Aber es gibt leider immer noch das Problem mit dem SetX() und SetY(),
denn wenn ein Block getroffen wird, dann wird der Ball an die falsche stelle gesetzt.
Ich weiß allerdings nicht an was das liegen könnte. Denn wenn ich es nachrechne stimmt alles.
Außer dem SetX() bzw. SetY() dort bekomme ich noch das falsche Ergebnis raus.
Ich weiß allerdings noch nicht warum.
Ich werde das dann noch einmal überprüfen.Vielen Dank nochmals für den Code.
-
Rekaptitulieren wir noch einmal: Die Funktionen RX() und RY() von Ball und Block liefern jeweils die linke obere Ecke. Probier doch mal folgendes: Setze den Ball mit SetX(0); SetY(0) auf den Koordinatenursprung. Dann sollten der linke und der obere Bildschirm(Viewport-)Rand Tangentem an den Ball sein, er ist also so weit in der Ecke, wie (physikalisch) möglich. Wenn das klappt, scheinen die Set-Funktionen zu funktionieren. Über das Ergebnis dieses Versuches solltest du mich umgehend informieren... Setze für diesen Versuch ruhig mal StepX und StepY auf Null, um genau gucken zu können.
Gibt es denn noch Kollisionen, die er nicht erkennt, oder auf die er die Richtung in falscher Weise ändert? Wenn nicht ist das Problem fast gelöst...
mfG D1B
-
Ok ich habe jetzt einmal die letzten Abfragen ein wenig umgeschrieben, da es passiert ist, dass der Ball von links oben gekommen ist, dann rechts oben den Block getroffen hat und dann nach links unten abgeprallt ist. Und das kann ja wohl nicht Sinn der Sache sein, oder?
Ok hier jetzt einmal mein Verbesserungsvorschlag:if( x <= Blocks[i].RX() && Ball->StepX >= 0 ) { Ball->SetX( 2 * x - Ball->RX() - Ball->StepX - Ball_Durchmesser ); Ball->StepX *= -1; } else if( x >= Blocks[i].RX() + Block_Width && Ball->StepX <= 0 ) { Ball->SetX( 2 * x - Ball->RX() - Ball->StepX - Ball_Durchmesser + 2 * Block_Width ); Ball->StepX *= -1; } else { Ball->SetY( ( Ball->StepY ? 2 : -2 ) * yD + Ball->RY() - Ball->StepY + Ball_Durchmesser); Ball->StepY *= -1; }
Ok viel hat sich nicht geändert ist aber eben auch wichtig.
Das mit dem SetX() und SetY() bekomme ich einfach nicht hin.
Bitte hilf mir.Thx
Edit: Wenn ich bei SetX() und SetY() jeweils 0 angebe, dann befindet sich der Ball in der linken oberen Ecke des Bildschirms. und zwar so weit wie möglich.
[ Dieser Beitrag wurde am 24.02.2003 um 19:48 Uhr von Zero0Cool editiert. ]
-
Poste doch mal bitte die Struktur namens Sprite, das würde uns sehr weiterhelfen...
-
> von links oben gekommen ist, dann rechts oben den Block getroffen hat und dann nach links unten abgeprallt
Wie kannst du denn sehen, wo der Ball den Block trifft, dass passiert doch zwischen 2 Frames...
Nochwas: Weißt du eigentlich, was x ist?
-
Na ja also das mit dem Treffer da ich mir ja nur einen Block gemacht habe, kann ich schon ungefähr vorraus sagen, wo der Ball den Block treffen wird.
Und da habe ich eben gesehen, dass der Ball den Block rechts oben treffen muss.
Und trotzdem ist er nach links unten abgeprallt. Aber das ist jetzt nicht mehr.Das mit dem x ich denke, dass das x für die X-Koordinate steht, an der der Ball den Block treffen wird???
Wenn es nicht so ist, dann kläre mich bitte auf...
Ich weiß echt nicht mehr weiter...
Thx@D1BAKEL
-
Oh Mann, ich glaube, jetzt haben wirs. Es gab da noch zwei kleine Fehler: Der erste ist passiert, als ich die ganzen Radien entfernt hab, da hab ich ein Vorzeichen übersehen und es weggenommen, statt nen Durchmesser draus zu machen. Und der zweite Fehler ist mir ja so richtig peinlich, ein simpler Tippfehler: In der letzten Abfage darfs natürlich nicht Ball->StepX heißen, sondern muss Ball->StepY heißen, man will ja die vertikale Richtung wissen...
void Block::Collision( Sprite* Ball, PointManager* PM, DirectXAudio* DXAudio, Sprite* Funken ) { for( int i = 0; i < BlocksAnzahl; ++i ) { if( !daweg[i] ) continue; if( Blocks[i].RX() < Ball->RX() - Block_Width && Blocks[i].RX() < Ball->RX() - Block_Width + Ball->StepX ) continue; if( Blocks[i].RY() < Ball->RY() - Block_Height && Blcoks[i].RY() < Ball->RY() - Block_Height + Ball->StepY ) continue; if( Blocks[i].RX() > Ball->RX() + Ball_Durchmesser && Blocks[i].RX() > Ball->RX() + Ball_Durchmesser + Ball->StepX ) continue; if( Blocks[i].RY() > Ball->RY() + Ball_Durchmesser && Blocks[i].RY() > Ball->RY() + Ball_Durchmesser + Ball->StepY ) continue; daweg[i] = false; double yD, x; if( Ball->StepY ) yD = -Ball->RY() + Blocks[i].RY() - Ball_Durchmesser; else yD = Ball->RY() - Blocks[i].RY() - Block_Height; x = yD * Ball->StepX / Ball->StepY + Ball->RX() + Ball_Durchmesser / 2; if( x < Blocks[i].RX() ) { Ball->SetX( 2 * x - Ball->RX() - Ball->StepX - Ball_Durchmesser ); Ball->StepX *= -1; } else if( x > Blocks[i].RX() + Block_Width ) { Ball->SetX( 2 * x - Ball->RX() - Ball->StepX - Ball_Durchmesser + 2 * Block_Width ); Ball->StepX *= -1; } else { Ball->SetY( ( Ball->StepY ? 2 : -2 ) * yD + Ball->RY() - Ball->StepY + Ball_Durchmesser ); Ball->StepY *= -1; } } }
Ich möchte dich bitte, das gleich ma auszuprobieren, und mir zu sagen, obs jetzt endlich funktioniert, wenn nicht mit entsprechender Fehleranalyse...
mfG D1B
[ Dieser Beitrag wurde am 24.02.2003 um 20:19 Uhr von D1BAKEL editiert. ]
-
Und hier ist noch die Struktur Sprite...
Na ja es ist eigentlich keine Struktur sonder eine Klasse.
Aber ich denke du meinst diese?class Sprite { public: bool Bounce(IM* InputM, Sprite* Brett, DirectXAudio* DXAudio, Sprite* Ball); Sprite(); void Create(DDClass* DDraw, char* Filename, int frmWidth, int frmHeight, int frmX, int frmY); void SetXY(int SpriteX, int SpriteY); void SetX(int SpriteX); void SetY(int SpriteY); void Move(int SpriteDX, int SpriteDY); void Drawhin(LPDIRECTDRAWSURFACE7 lpDDSurface); void Drawweg(LPDIRECTDRAWSURFACE7 lpDDSurface); void Drawloop(LPDIRECTDRAWSURFACE7 lpDDSurface); bool TestCollide(Sprite* Sprite); void Release(); void ResetCurrentFrame(); void ResetFrames(void) { CurrentFrame = 0; } int RX(); int RY(); int GetWidth(void) { return FrameWidth; } int GetHeight(void) { return FrameHeight; } double StepX; double StepY; private: LPDIRECTDRAWSURFACE7 lpDDSpriteSurface; int SpriteWidth; int SpriteHeight; int x; int y; int FrameWidth; int FrameHeight; int FrameDelay; int FramesX; int FramesY; int CurrentFrameX; int CurrentFrameY; int delay; int CurrentFrame; };
[ Dieser Beitrag wurde am 24.02.2003 um 20:21 Uhr von Zero0Cool editiert. ]
-
Es tut mir leid, aber der Code funktioniert immer noch nicht.
Es funktioniert immer noch nicht.
Aber was mich noch interessieren würde ist, was du eigentlich geändert has ich kann nämlich nichts finden...
na ja auf jeden Fall siehts so aus, dass es eigentlich nur funktioniert, wenn der Ball die Oberkante des Blocks trifft. Ansonsten wird er an die falsche Stelle gesetzt.
Ich komme einfach nicht darauf wo der Fehler liegt.
-
Okay, jetzt folgen einige Erklärungen:
Die ersten vier if-Abfragen testen, ob sich der Ball vor und nach der Bewegung auf ein und derselben Seite (oben, unten, links oder rechts) vom Block befindet, wenn dieses zutrifft, gibt es keine Kollision und dieser Block kann übersprungen werden (continue;) Andernfalls gehe ich davon aus, dass er getroffen wird. Nach etwas Überlegung sollte auffallen, dass der Ball vor der Bewegung rechts vom Block sein kann, und nach der Bewegung über dem Block, so dass es trotzdem zu keiner Kollision kommt, diese aber fälschlicherweise ausgelöst wird. Dazu kommt es allerdings nur, wenn der Ball wirklich schnell ist und sehr klein.
yD ist der Abstand vom Ball zum Block. Wenn der Ball also nach unten fliegt (Ball->StepY) speichert yD den Abstand von der Oberkante des Blockes zu der unteren Tangente des Balles, die parallel zur X-Achse liegt, andernfalls (else) speichert yD den (senkrechten) Abstand von der unteren Blockkante bis zur BallOberkante.
Mithilfe des Strahlensatzes und der Größe yD wird x berechnet. Da die y-Koordinate des Balles links und nicht in der Mitte ist, muss noch ein halber Durchmesser addiert werden, um den tatsächlichen Schnittpunkt zu bekommen, dessen x-Koordinate in x gespeichert wird. In den folgenden Abfragen wird getestet, ob x überhaupt auf der Kante des Blockes liegt. Wenn x sich links vom Block befindet (x < Blocks[i].RX()) Kollidiert der Ball links, wenn x rechts liegt (x > Blocks[i].RX() + Block_Width), kollidiert er rechts. In beiden fällen wir StepX umgekehrt, nachdem der Ball an der entsprechenden (linken oder rechten) Kante gespiegelt wird (SetX(...)) zum elseZweig: Wenn x weder links noch rechts ist, hat der Ball den Block oben oder unten getroffen. Nun muss man auch hier spiegeln, da yD aber immer positiv ist, muss man nochmal unterscheiden, ob der Ball nach oben oder nach unten fliegt (Ball->StepY) und yD entsprechend addieren oder subtrahieren...
mfG D1B
PS: Um auf die genauen Formeln zu kommen mach ich mir immer Zeichnungen, hierfür sind 2 DinA4-Blätter draufgegangen...
-
Von oben funktionierts? Das is ja lustig, dazu hab ich nämlich grad ne Skizze gemacht und den Code überarbeitet... Dann weiß ich ja, wie ichs fertigstellen kann...
Ich gucks mir nochma an...
-
Vielen Dank für die Erklärungen.
Aber eine kleine Frage hätte ich da noch:
Ich sehe in der ganzen Figur keine einzige Strahlensatzfigur heraus.Und das mit deinen zwei Din A 4 Seiten tut mir leid.
Aber falls es dich tröstet:
Ich habe bereits 4 Seiten vollgeschrieben und immer wieder das gleiche ausgerechnet und bin zu keinem Ergebins gekommen.
Na ja aber das ist ja nicht so wichtig...Nur einmal so eine Frage hast du irgendwie Mathe studiert oder so?
weil du so gut darin bist...Ich meine ich habe immerhin ne 2 im Zeugnis und sehe trotzdem in dieser ganzen Figur keinen Strahlensatz.
-
Okay, jetzt hab ich aber ein gutes Gefühl, waren wieder peinliche Fehler drin, naja ein paar von ihnen sind raus. (Hoffentlich alle... )
void Block::Collision( Sprite* Ball, PointManager* PM, DirectXAudio* DXAudio, Sprite* Funken ) { for( int i = 0; i < BlocksAnzahl; ++i ) { if( !daweg[i] ) continue; if( Blocks[i].RX() < Ball->RX() - Block_Width && Blocks[i].RX() < Ball->RX() - Block_Width + Ball->StepX ) continue; if( Blocks[i].RY() < Ball->RY() - Block_Height && Blcoks[i].RY() < Ball->RY() - Block_Height + Ball->StepY ) continue; if( Blocks[i].RX() > Ball->RX() + Ball_Durchmesser && Blocks[i].RX() > Ball->RX() + Ball_Durchmesser + Ball->StepX ) continue; if( Blocks[i].RY() > Ball->RY() + Ball_Durchmesser && Blocks[i].RY() > Ball->RY() + Ball_Durchmesser + Ball->StepY ) continue; daweg[i] = false; double yD, x; if( Ball->StepY ) yD = -Ball->RY() + Blocks[i].RY() - Ball_Durchmesser; else yD = Ball->RY() - Blocks[i].RY() - Block_Height; x = yD * Ball->StepX / abs( Ball->StepY ) + Ball->RX() + Ball_Durchmesser / 2; if( x < Blocks[i].RX() ) { Ball->SetX( 2 * Blocks[i].RX() - Ball->RX() - Ball->StepX - Ball_Durchmesser ); Ball->StepX *= -1; } else if( x > Blocks[i].RX() + Block_Width ) { Ball->SetX( 2 * Blocks[i].RX() - Ball->RX() - Ball->StepX - Ball_Durchmesser + 2 * Block_Width ); Ball->StepX *= -1; } else { if( Ball->StepY ) Ball->SetY( 2 * yD + Ball->RY() - Ball->StepY + Ball_Durchmesser ); else Ball->SetY( -2 * yD + Ball->RY() - Ball->StepY - Ball_Durchmesser ); Ball->StepY *= -1; } } }
Gleich ausprobieren und mich informieren!!!
mfG D1B
-
Noch mal zu der Strahlensatzfigur:
Durch StepX und StepY hast du ja ein rechtwinkliges Dreieck, deren Katheten bekannt sind, sie sind parallel zu den Achsen. Eine (mathematisch) ähnliche Figur ergibt sich, aus yD und einem Abschnitt von x. Am besten zeichnest du das mal. Male einen Block und die Kugel darunter und dann nochmal die Kugel an der Stelle, an die sie sich bewegen würde, wenn der Block nicht da wäre, also am besten in den Block. Lege alles so an, dass die Unterkante des Blockes die Strecke zwischen beiden Punkten (des Balles) schneidet. Wenn du jetzt achsenparallel StepX und StepY einzeichnest, bilden sie mit besagter Strecke ein Rechtwinkliges Dreieck. Die Unterkante des Blockes teilt nun die Kathete, die parallel zur Y-Achse liegt in zwei Teile, der untere davon ist yD. Ungefähr jetzt sollte der AhaEffekt einsetzen da du jetzt sicher siehst, wo die Strahlensatzfigur liegt, und dass du damit den Schnittpunkt von Hypothenuse und Unterkannte berechnen kannst. Da wir von der linken oberen Ecke des Balles ausgingen muss dieser Schnittpunkt noch um einen halben Durchmesser nach rechts verschoben werden, um den tatsächlichen Aufschlagspunkt zu erhalten. Das alles steht in dieser Zeile:
x = yD * Ball->StepX / abs( Ball->StepY ) + Ball->RX() + Ball_Durchmesser / 2;
Und mit diesem xWert kann man nun auswerten, an welcher Seite der Ball den Block trifft.
Wegen der Zettel mach dir keine Sorgen, das war ja in meinem Interesse... (Es sind mehr geworden)
Danke wegen des unterstellten MatheStudiums, aber ich bin noch Schüler, elfte Klasse... Allerdings habe ich einen ziemlich guten Durchschnitt von glatt 1.0 :p In welche Klasse gehst du denn und wie alt bist du?
mfG D1B
[ Dieser Beitrag wurde am 24.02.2003 um 22:17 Uhr von D1BAKEL editiert. ]
-
Ok also zuerst einmal Gratulation zu der 1.0 in Mathe...
Allerdings funktioniert es immer noch nicht.
Die Strahlensatzfigur habe ich jetzt allerdings gesehen.
Das ist gut gedacht. Aber wenn der Ball den Block trifft wird er trotzdem an die falsche Stelle gesetzt.
Wirklich schade.
Wie ich sehe kopierst du immer nur deinen Code mit den Veränderungen hinein, also poste ich hier einmal den Code mit meinem Vorschlag zur Verbesserung bei den ifs. Den kannst du ja dann kopieren und mit deinen Änderungen posten.void Block::Collision( Sprite* Ball, PointManager* PM, DirectXAudio* DXAudio, Sprite* Funken ) { for( int i = 0; i < BlocksAnzahl; ++i ) { if( !daweg[i] ) continue; if( Blocks[i].RX() < Ball->RX() - Block_Width && Blocks[i].RX() < Ball->RX() - Block_Width + Ball->StepX ) continue; if( Blocks[i].RY() < Ball->RY() - Block_Height && Blocks[i].RY() < Ball->RY() - Block_Height + Ball->StepY ) continue; if( Blocks[i].RX() > Ball->RX() + Ball_Durchmesser && Blocks[i].RX() > Ball->RX() + Ball_Durchmesser + Ball->StepX ) continue; if( Blocks[i].RY() > Ball->RY() + Ball_Durchmesser && Blocks[i].RY() > Ball->RY() + Ball_Durchmesser + Ball->StepY ) continue; daweg[i] = false; double yD, x; if( Ball->StepY ) yD = -Ball->RY() + Blocks[i].RY() - Ball_Durchmesser; else yD = Ball->RY() - Blocks[i].RY() - Block_Height; x = yD * Ball->StepX / abs( Ball->StepY ) + Ball->RX() + Ball_Durchmesser / 2; if( x <= Blocks[i].RX() && Ball->StepX >0 ) { Ball->SetX( 2 * Blocks[i].RX() - Ball->RX() - Ball->StepX - Ball_Durchmesser ); Ball->StepX *= -1; } else if( x >= Blocks[i].RX() + Block_Width && Ball->StepX <0 ) { Ball->SetX( 2 * Blocks[i].RX() - Ball->RX() - Ball->StepX - Ball_Durchmesser + 2 * Block_Width ); Ball->StepX *= -1; } else { if( Ball->StepY ) Ball->SetY( 2 * yD + Ball->RY() - Ball->StepY + Ball_Durchmesser ); else Ball->SetY( -2 * yD + Ball->RY() - Ball->StepY - Ball_Durchmesser ); Ball->StepY *= -1; } } }
Du hattest bei den ersten ifs auch noch einen kleinen Tippfehler.
Vielen Dank
P.S.: Ich gehe in die 9. Klass und bin 15 Jahre alt. Programmiere allerdings schon einer ganzen weile (zuerst html, js, php und jetzt c++ seit 1 Jahr).
[ Dieser Beitrag wurde am 25.02.2003 um 13:58 Uhr von Zero0Cool editiert. ]
-
Ich hab deine Änderungen durchaus schon beim ersten Mal gesehe, aber die sind keineswegs notwendig, sie werden nie zu einem anderen Verlauf der Funktion führen... Für den Tippfehler entschuldige ich mich...
Vielleicht kannst du mir sagen, wie der Ball falsch gesetzt wird, ist er wenigstens auf der richtigen Seite des Blocks? Ist dieser Fehler bei einer Kollision von oben/unten/links/rechts? Funktionierts überhaupt in manchen Fällen? Wird die Richtung richtig geändert? Ist der Fehler nur in der einen Koordinate des Balls oder in X und Y? Wenn ersteres, welche Koordinate? Wahrscheinlich nur die gespiegelte, oder?
-
Also die Richtung wird schon richtig geändert, aber die Position ist nicht einmal auf der richtigen Seite.
Allerdings, wenn der Winkel sehr klein ist, also wenn der Ball fast senkrecht fliegt, dann funktioniert es manchmal, dass der Ball nur relativ minimal falsch liegt.
Vielen Dank nochmals.
-
Es muss irgendein Missverständnis zwischen uns geben. Ich hab gestern fünf Beispiele von Hand durchgerechnet, und alles hat gestimmt. Und wenns bei dir überhauptnicht hinhaut, muss ich irgendwas falschverstanden haben. Irgendwas mit deinen Koordinaten. Ich tappe im Dunkteln, ich sehe in meinen Formeln keinen Fehler, jedenfalls nicht für das Problem, das sich mir hier offenbart. Vielleicht hab ich was grobes übersehen, aber möglicherweise bin ich auch minder informiert. Ich denke es würde sehr helfen, wenn mir dein ganzes Programm (Quellcode) schicken würdest, dann könnte ich hier zuhause mal n bisschen rumexperimentieren und du müsstes mir das, was du siehst nicht genaustens erklären, so dass ich mir das vorstellen kann, sondern ich kann selber sehen, wo der Fehler liegt... Wenn dir dein Code also nicht zu geheim ist, schicke ihn mir doch mal gepackt (WinZip, nicht RAR) an wellenbrock@web.de... Ich bin sicher, dass es dann nicht lange dauern wird, bis wir eine passende Lösung haben...
mfG D1B
-
Hast du meine e-mail bekommen???
Dann schreib mir bitte eine zurück, ansonsten sende ich sie dir erneut