2d Ball Kollisiopn - Bälle werden immer langsamer, hilfe!
-
Hallo
-
Crymes schrieb:
Hallo
Erstmal sorry für den sinnlosen Post.
Ich hab mir ein OpenGL Programm geschrieben, dass 2 Bälle miteinander kollidieren lässt.
Das Problem ist, dass mit der Zeit die Geschwindigkeit verloren geht und irgendwann sich gar nichts mehr bewegt.Hier der Code, indem ich den Fehler vermute:
void kollisionball() { //Gewicht der Bälle errechnen float gball1 = 0, gball2 = 0; gball1 = (ball1.radius*ball1.radius) * Pi; gball2 = (ball2.radius*ball2.radius) * Pi; //Abstand ausrechnen if( sqrt( pow( ball2.position[0]-ball1.position[0], 2) + pow( ball2.position[1]-ball1.position[1], 2) ) <= (ball1.radius+ball2.radius) ) { //Bälle dürfen sich nicht berühren if(sqrt( pow( ball2.position[0]-ball1.position[0], 2) + pow( ball2.position[1]-ball1.position[1], 2) ) < (ball1.radius+ball2.radius) ) { do { for(int c=0;c<=1;c++) { ball1.position[c] = ball1.position[c] - 0.01 * ball1.geschwindigkeit[c]; ball2.position[c] = ball2.position[c] - 0.01 * ball2.geschwindigkeit[c]; } } while(sqrt( pow( ball2.position[0]-ball1.position[0], 2) + pow( ball2.position[1]-ball1.position[1], 2) ) < (ball1.radius+ball2.radius) ); } //Linie zwischen den Mittelpunkten (Zentralvektor) float vlinie[2]; vlinie[0] = ball2.position[0] - ball1.position[1]; vlinie[1] = ball2.position[1] - ball1.position[1]; //Linie auf Einheitsvektor nominieren: vlinie / bertag(vlinie) float vliniee[2]; vliniee[0] = vlinie[0]/sqrt(vlinie[0] * vlinie[0] + vlinie[1] * vlinie[1]); vliniee[1] = vlinie[1]/sqrt(vlinie[0] * vlinie[0] + vlinie[1] * vlinie[1]); //Tangentialvektor errechnen: vt = (-vliniee(y), vliniee(x) ) float vtan[2]; vtan[0] = -1 * vliniee[1]; vtan[1] = vliniee[0]; //Geschwindigkeitsvektoren zerlegen (tangential, normal Richtung), es kommen Skalare raus float gnormb1, gnormb2, gtanb1, gtanb2; gnormb1 = (vliniee[0] * ball1.geschwindigkeit[0]) + (vliniee[1] * ball1.geschwindigkeit[1]); gnormb2 = (vliniee[0] * ball2.geschwindigkeit[0]) + (vliniee[1] * ball2.geschwindigkeit[1]); gtanb1 = (vtan[0] * ball1.geschwindigkeit[0]) + (vtan[1] + ball1.geschwindigkeit[1]); gtanb2 = (vtan[0] * ball2.geschwindigkeit[0]) + (vtan[1] + ball2.geschwindigkeit[1]); //Neue Geschwindigkeit errechnen //tangentiale Geschwindigkeiten verändern sich nicht! //Geschwindigkeitsvektoren nach Kollision //Masse ist Radius! float gnormb1n, gnormb2n; /*gnormb1n = ( (gnormb1*(gball1 - gball2) + ((2*gball2) * gnormb2))) / (gball1 + gball2); gnormb2n = ( (gnormb2*(gball2 - gball1) + ((2*gball1) * gnormb1))) / (gball1 + gball2); */ //Ander Formel /*gnormb1n = (gball1*gnormb1 + (gball2*(2*gnormb2-gnormb1))) / (gball1 + gball2); gnormb2n = (gball2*gnormb2 + (gball1*(2*gnormb1-gnormb2))) / (gball1 + gball2);*/ //Formel ohne Masse gnormb1n = gnormb2; gnormb2n = gnormb1; //Einheitsvektoren zu normalvektoren konvertieren (normal richtung) float b1nn[2], b2nn[2], b1tn[2], b2tn[2]; b1nn[0] = gnormb1n * vliniee[0]; b1nn[1] = gnormb1n * vliniee[1]; b2nn[0] = gnormb2n * vliniee[0]; b2nn[1] = gnormb2n * vliniee[1]; b1tn[0] = gnormb1n * vtan[0]; b1tn[1] = gnormb1n * vtan[1]; b2tn[0] = gnormb2n * vtan[0]; b2tn[1] = gnormb2n * vtan[1]; //Finale Geschwindigkeiten ausrechnen ball1.geschwindigkeit[0] = b1nn[0] + b1tn[0]; ball1.geschwindigkeit[1] = b1nn[1] + b1tn[1]; ball2.geschwindigkeit[0] = b2nn[0] + b2tn[0]; ball2.geschwindigkeit[1] = b2nn[1] + b2tn[1]; } }
(edit by rapso, end tag eingefuegt)
Wisst ihr, woran das liegen könnte?
-
Bitte benutze cpp-tags und formatiere deinen Code ordentlich!
-
bleiben es nur 2 baelle, oder werden es mehr?
ansonsten, benutz doch einfach einen profiler wie z.b. codeanalyst, dann bekommst du genau raus wo das problem ist. ich wuerde auf die einzige schleife im code tippen, aber ohne profiler ist das glueckspiel und nicht software engineering.
-
Ich hab hier mal den ganzen Code des Projekts, wird dann übersichtlicher:
// Ball Simulation.cpp : Definiert den Einstiegspunkt für die Konsolenanwendung. // #include "stdafx.h" #include <iostream> #include <stdlib.h> #include <stdio.h> #include <math.h> #include <string.h> #include <Windows.h> #include <GL/glew.h> #include <GL/freeglut.h> #define Pi 3,14159265358979323846 using namespace std; //Bildschirmauflösung ermitteln unsigned int blänge = GetSystemMetrics(SM_CXSCREEN), bbreite = GetSystemMetrics(SM_CYSCREEN); struct kugel { float position[2]; float geschwindigkeit[2]; float radius; }ball1, ball2; void ballinit() { //Klasse initialisieren Ball1 ball1.position[0]=110; ball1.position[1]=110; ball1.geschwindigkeit[0]=31; ball1.geschwindigkeit[1]=6; ball1.radius=100; //Ball2 ball2.position[0]=500; ball2.position[1]=500; ball2.geschwindigkeit[0]=3; ball2.geschwindigkeit[1]=9; ball2.radius=100 ; }; void ballupdate() { for(int stelle = 0; stelle<=1; stelle++) { ball1.position[stelle] = ball1.position[stelle] + ball1.geschwindigkeit[stelle]; ball2.position[stelle] = ball2.position[stelle] + ball2.geschwindigkeit[stelle]; } } void kollisionrand() { //Nicht über Rand hinaus oben/unten if(ball1.position[1] + ball1.geschwindigkeit[1] < ball1.radius) { ball1.position[1] = ball1.radius; } if(ball1.position[1] + ball1.geschwindigkeit[1] > bbreite - ball1.radius) { ball1.position[1] = bbreite - ball1.radius; } //links rechts if(ball1.position[0] + ball1.geschwindigkeit[0] < ball1.radius) { ball1.position[0] = ball1.radius; } if(ball1.position[0] + ball1.geschwindigkeit[0] > blänge - ball1.radius) { ball1.position[0] = blänge - ball1.radius; } //Ball1 //rechts /links kollidieren if( (ball1.position[0] >= (blänge-ball1.radius)) || (ball1.position[0] <= ball1.radius) ) { ball1.geschwindigkeit[0] = ball1.geschwindigkeit[0] * (-1); } //oben /unten else if( (ball1.position[1] >= (bbreite-ball1.radius)) || (ball1.position[1] <= ball1.radius) ) { ball1.geschwindigkeit[1] = ball1.geschwindigkeit[1] * (-1); } //Nicht über den Rand hinaus fliegen oben/unten if(ball2.position[1] + ball2.geschwindigkeit[1] < ball2.radius) { ball2.position[1] = ball2.radius; } if(ball2.position[1] + ball2.geschwindigkeit[1] > bbreite - ball2.radius) { ball2.position[1] = bbreite - ball2.radius; } //links/rechts if(ball2.position[0] + ball2.geschwindigkeit[0] < ball2.radius) { ball2.position[0] = ball2.radius; } if(ball2.position[0] + ball2.geschwindigkeit[0] > blänge - ball2.radius) { ball2.position[0] = blänge - ball2.radius; } //Ball2 //rechts /links if( (ball2.position[0] >= (blänge-ball2.radius)) || (ball2.position[0] <= ball2.radius) ) { ball2.geschwindigkeit[0] = ball2.geschwindigkeit[0] * (-1); } //oben /unten else if( (ball2.position[1] >= (bbreite-ball2.radius)) || (ball2.position[1] <= ball2.radius) ) { ball2.geschwindigkeit[1] = ball2.geschwindigkeit[1] * (-1); } } void kollisionball() { //Gewicht der Bälle errechnen float gball1 = 0, gball2 = 0; gball1 = (ball1.radius*ball1.radius) * Pi; gball2 = (ball2.radius*ball2.radius) * Pi; //Abstand ausrechnen if( sqrt( pow( ball2.position[0]-ball1.position[0], 2) + pow( ball2.position[1]-ball1.position[1], 2) ) <= (ball1.radius+ball2.radius) ) { //Bälle dürfen sich nicht berühren if(sqrt( pow( ball2.position[0]-ball1.position[0], 2) + pow( ball2.position[1]-ball1.position[1], 2) ) < (ball1.radius+ball2.radius) ) { do { for(int c=0;c<=1;c++) { ball1.position[c] = ball1.position[c] - 0.01 * ball1.geschwindigkeit[c]; ball2.position[c] = ball2.position[c] - 0.01 * ball2.geschwindigkeit[c]; } } while(sqrt( pow( ball2.position[0]-ball1.position[0], 2) + pow( ball2.position[1]-ball1.position[1], 2) ) < (ball1.radius+ball2.radius) ); } //Linie zwischen den Mittelpunkten (Zentralvektor) float vlinie[2]; vlinie[0] = ball2.position[0] - ball1.position[1]; vlinie[1] = ball2.position[1] - ball1.position[1]; //Linie auf Einheitsvektor nominieren: vlinie / bertag(vlinie) float vliniee[2]; vliniee[0] = vlinie[0]/sqrt(vlinie[0] * vlinie[0] + vlinie[1] * vlinie[1]); vliniee[1] = vlinie[1]/sqrt(vlinie[0] * vlinie[0] + vlinie[1] * vlinie[1]); //Tangentialvektor errechnen: vt = (-vliniee(y), vliniee(x) ) float vtan[2]; vtan[0] = -1 * vliniee[1]; vtan[1] = vliniee[0]; //Geschwindigkeitsvektoren zerlegen (tangential, normal Richtung), es kommen Skalare raus float gnormb1, gnormb2, gtanb1, gtanb2; gnormb1 = (vliniee[0] * ball1.geschwindigkeit[0]) + (vliniee[1] * ball1.geschwindigkeit[1]); gnormb2 = (vliniee[0] * ball2.geschwindigkeit[0]) + (vliniee[1] * ball2.geschwindigkeit[1]); gtanb1 = (vtan[0] * ball1.geschwindigkeit[0]) + (vtan[1] + ball1.geschwindigkeit[1]); gtanb2 = (vtan[0] * ball2.geschwindigkeit[0]) + (vtan[1] + ball2.geschwindigkeit[1]); //Neue Geschwindigkeit errechnen //tangentiale Geschwindigkeiten verändern sich nicht! //Geschwindigkeitsvektoren nach Kollision //Masse ist Radius! float gnormb1n, gnormb2n; /*gnormb1n = ( (gnormb1*(gball1 - gball2) + ((2*gball2) * gnormb2))) / (gball1 + gball2); gnormb2n = ( (gnormb2*(gball2 - gball1) + ((2*gball1) * gnormb1))) / (gball1 + gball2); */ //Ander Formel /*gnormb1n = (gball1*gnormb1 + (gball2*(2*gnormb2-gnormb1))) / (gball1 + gball2); gnormb2n = (gball2*gnormb2 + (gball1*(2*gnormb1-gnormb2))) / (gball1 + gball2);*/ //Formel ohne Masse gnormb1n = gnormb2; gnormb2n = gnormb1; //Einheitsvektoren zu normalvektoren konvertieren (normal richtung) float b1nn[2], b2nn[2], b1tn[2], b2tn[2]; b1nn[0] = gnormb1n * vliniee[0]; b1nn[1] = gnormb1n * vliniee[1]; b2nn[0] = gnormb2n * vliniee[0]; b2nn[1] = gnormb2n * vliniee[1]; b1tn[0] = gnormb1n * vtan[0]; b1tn[1] = gnormb1n * vtan[1]; b2tn[0] = gnormb2n * vtan[0]; b2tn[1] = gnormb2n * vtan[1]; //Finale Geschwindigkeiten ausrechnen ball1.geschwindigkeit[0] = b1nn[0] + b1tn[0]; ball1.geschwindigkeit[1] = b1nn[1] + b1tn[1]; ball2.geschwindigkeit[0] = b2nn[0] + b2tn[0]; ball2.geschwindigkeit[1] = b2nn[1] + b2tn[1]; } } void ball(float x, float y, float radius, float rot, float grün, float blau) { glBegin(GL_LINE_LOOP); glColor3d(rot,grün,blau); for(float s=0;s<=360;s++) { glVertex2f( (x + (radius*cos(s*(Pi/180)))), (y + (radius*sin(s*(Pi/180)))) ); } glEnd(); } void fenster() { //Glut aufrufen und initialisieren glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); glutInitWindowPosition(0,0); glutInitWindowSize(blänge, bbreite); glutCreateWindow("Ball Simulation"); //Farbe fürs löschen festlegen glClearColor(0,0,0,0); } void zeichnen() { //Bildschirm bereinigen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); //Bälle zeichnen ball(ball1.position[0],ball1.position[1],ball1.radius,1,0,0); ball(ball2.position[0],ball2.position[1],ball2.radius,0,0,1); //Position aktualisieren kollisionrand(); kollisionball(); ballupdate(); //Debug in Konsole //Bildschirmgröße cout << blänge << bbreite << endl; //Position der Bälle cout << "Ball1: (" << ball1.position[0] << ", " << ball1.position[1] << ")" << endl; cout << "Ball2: (" << ball2.position[0] << ", " << ball2.position[1] << ")" << endl; cout << "Geschwindigkeit Ball1: " << ball1.geschwindigkeit[0] << " " << ball1.geschwindigkeit[1] << endl; cout << "Geschwindigkeit Ball2: " << ball2.geschwindigkeit[0] << " " << ball2.geschwindigkeit[1] << endl; //Alles anzeigen glutSwapBuffers(); glutPostRedisplay(); } void änderung(int länge, int breite) { double verhältnis; //Nicht durch 0 teilen if(breite == 0) { breite = 1; } verhältnis = 1.0*länge/breite; //Projektionsmodus glMatrixMode(GL_PROJECTION); //Reset glLoadIdentity(); //Sichtfeld fürs ganze Fenstere glViewport(0,0,länge,breite); //Korrekte Perspektive gluPerspective(0,verhältnis,1,100); //Zeichenbereich an Bildschirm anpassen glOrtho(0,blänge,0,bbreite,0,1); //Wieder Szene anzeigen glMatrixMode(GL_MODELVIEW); } int _tmain(int argc, char *argv[]) { //Bälle initialisieren ballinit(); //Glut aufrufen glutInit(&argc, argv); //Fenster zeichnen fenster(); //Renderfunktion festlegen glutDisplayFunc(zeichnen); //Fenster darf verändert werden glutReshapeFunc(änderung); //immer auf neuen Event warten; glutMainLoop(); return(0); }
Zum testen bleibts erst bei 2 Bällen.
Ich werd mir ma so nen profiler anschauen.
-
Es ist vlt irrelevant aber:
#define Pi 3,14159265358979323846
ist falsch da C++ "." und nicht "," als Dezimaltrennzeichen benutzt.
(es sei denn es ist noch eine Sinnlose Spracherweiterung von M$)
-
Ok, werde ich ändern.
Aber hat jemand die Lösung für das eigentliche Problem?
Ihr könnt den Code ja ma kompilieren, dann wisst ihr, was ich meine.
-
Durch die Änderung von der Pi Definition wird jetzt der Ball endlich korrekt gezeichnet.
Mit dem Code analyser von AMD kommr ich überhaupt nicht zurecht.
Ist das vielleicht das falsche Unterforum für das Problem?
-
Also bei dem Wust habe ich kL das durchzusehen, aber wieso benutzt du keine Vektorklasse? Würde das ganze vermutlich wesentlich übersichtlicher machen und damit auch zugleich weniger Fehleranfällig.