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!


  • Mod

    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.


Anmelden zum Antworten