Kollisionsproblem
-
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
-
Hallo, ich hab mein Internet kaputtgekriegt, und nach ner Menge Anstrengung bin ich jetzt seit ner halben Stunde endlich wieder online. Deine Mail hab ich ja schon aus der Schule beantwortet, hab dein Spiel auch schon runtergeladen. Werds gleich ma ausprobieren, dann schreib ich dir wieder... (ob hier oder eMail hängt davon ab, obs Forummitgliedern helfen kann...)
mfG D1B
-
hmm, ich hab jetzt oben net gelesen, worums genau geht, aber ich dachte mir, ich könnte nochmal meine breakout-kolli posten, vielleicht hilft sie ja irgendwie weiter, is nämlich recht kurz und überschaubar. hat zwar net steigungswinkel usw, aber is für 45° auf jeden fall sinnvoll, und der winkel ändert sich ja eigentlich auch nicht, wenn man von der bewegung des "paddle" einmal absieht.
//////////////////////////////////////////////////////// //Prüfen auf Kollision //////////////////////////////////////////////////////// BOOL Object::TestCollision(Object* Object,int distanceX,int distanceY) { //Prüfen, ob das Objekt innerhalb eines bestimmten Bereiches liegt, in // dem Kollisionen auftreten können. Bereich ist das Rechteck // distanceX*distanceY if(((abs(CenterX-Object->CenterX))<=distanceX) && (abs(CenterY-Object->CenterY)<=distanceY)) { //Objekt trifft auf eine Ecke: rechts unten if(((Object->x==x2)&&(Object->y==y2)) &&(Object-StepX<0) &&(Object->StepY<0)) { CollisionPosition = CORNER_COLLISION; return TRUE; } //Objekt trifft auf eine Ecke: rechts oben else if(((Object->x==x2)&&(Object->y2==y)) && (Object->StepX<0) &&(Object->StepY>0)) { CollisionPosition = CORNER_COLLISION; return TRUE; } //Objekt trifft auf eine Ecke: links oben else if(((Object->x2==x)&&(Object->y2==y)) && (Object->StepX>0) &&(Object->StepY>0)) { CollisionPosition = CORNER_COLLISION; return TRUE; } //Objekt trifft auf eine Ecke: links unten else if(((Object->x2==x)&&(Object->y==y2)) && (Object->StepX>0) &&(Object->StepY<0)) { CollisionPosition = CORNER_COLLISION; return TRUE; } // Objekt kommt von oben else if(((Object->CenterY+Object->FrameHeight/2)== (CenterY-FrameHeight/2)) && (Object->CenterY<(CenterY-FrameHeight/2)) && ( ((Object->x2>=x)&&(Object->x2<=x2)) || ((Object->x<=x2)&&(Object->x>=x)))) { Object->CollisionPosition=VERTICAL_COLLISION; Beep(500,30); //Nur zum Test return TRUE; } // Objekt kommt von unten else if((((Object->CenterY-Object->FrameHeight/2)== (CenterY+FrameHeight/2)) && (Object->CenterY>(CenterY+FrameHeight/2)) && (((Object->x2>=x)&&(Object->x2<=x2)) || ((Object->x<=x2)&&(Object->x>=x))))) { Object->CollisionPosition=VERTICAL_COLLISION; Beep(500,30); return TRUE; } //Wenn Objekt nicht von Oben oder Unten und auch keine Ecke //trifft, es aber trotzdem // im Kollisionsbereich liegt, muss es entweder von links oder //rechts treffen else { Object->CollisionPosition = HORIZONTAL_COLLISION; Beep(800,30); return TRUE; } } //wenn es nicht imKollisionsbereich liegt, keine Kollision (logisch) else { return FALSE; } return FALSE; }
Ich reagiere auf die Kollision, indem ich einer int-Variable CollisionPosition
verschieden Werte für vertikale(von oben oder unten), horizontale oder Eck-Kollisionen zuweise. Je nachdem, welchen Wert sie hat, wird in der Funktion für die Bewegung des Balls entweder bei
a) vertikaler Kollision: der "y-Geschwindigkeit"- des Balls ihr Gegenwert zugewiesen
b) horizontaler Kollision: der "x-Geschwindigkeit"- des Balls ihr Gegenwert zugewiesen
c) Eck-Kollisionen: beiden Geschwindigkeiten ihr jeweiliger Gegenwert zugewiesen.gruß
--------------------