PDA

View Full Version : Trouble with circle collision detection



JRoop
10-20-2005, 10:55 PM
.. well, moreso I don't know where to go with my code for now.

I'm currently taking an introduction to CG and have an assignment that involves a polygon corral (5 sided) in which a ball bounces. After much effort, I finally got it to work correctly and smoothly (figured out an error with how I used Double Buffering), but now I must manipulate my code so that it inclides 3 interior sphere (well, for my purposes, circles) obstacles upon which the ball must bounce upon. I understand the concept and believed that I had it implemented correctly, but the code does not work as intended, merely passes through the obstacles while continuing to correctly ricochet off the polygon's inner walls.

Here is the main cpp code. It calls an external class Tigger that does the calculations for dot product, normal, unit normal, etc. as needed by the problem.


/*
Written and designed by Me
This is the OpenGL implementation of the
ball bounce program.

*/

#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>

#include <math.h>
#include <stdlib.h>
#include <iostream.h>
#include "Tigger.h"



void display(void) {

float A[2] = { 2.0, 7.0};//point A on boundary of ball
float B[2] = {12.0, 1.0};//point B on boundary of ball
float C[2] = {23.0,11.0};//point C on boundary of ball
float D[2] = { 9.0,20.0};//point D on boundary of ball
float E[2] = { 1.0,20.0};//point E on boundary of ball

// Radii of Circle obstacles
float Radius[3]={ 2.0, 2.5, 2.5 };

// X Coordinates of Circle obstacles
float CenterX[3]={ 12.0, 15.0, 5.0 };

// Y Coordinates of Circle obstacles
float CenterY[3]={ 5.0, 12.5, 17.5 };


// Radius of Ball
float radius=0.125;

// Coordinates of center of ball
float center[2] = { 8.0, 11.0 };

// Velocity vector
float velocity[2] = { 6.0, 5.0 };

// Clear the entire display
glClear( GL_COLOR_BUFFER_BIT );



glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

float T=0.001;

while ( T < 100 )
{
//Set initial time

//Setup distance array for Circle obstacle collision
float distance[3], x,y;

// Erase the ball by drawing the surface again

glColor3f( 20.0, 20.0, 20.0 );
glBegin(GL_POLYGON);
glVertex3f( 2.0, 7.0, 0.0);
glVertex3f(12.0, 1.0, 0.0);
glVertex3f(23.0,11.0, 0.0);
glVertex3f( 9.0,20.0, 0.0);
glVertex3f( 1.0,20.0, 0.0);
glEnd();
glFlush();

// Draw the ball (red)
glColor3f( 1.0, 0.0, 0.0 );
glPushMatrix();
glTranslatef(center[0], center[1], 0.0);
glutSolidSphere( radius, 25, 25);
glPopMatrix();

// Make sure the ball has been displayed
glFlush();

// Circle Obstacle 1
glColor3f( 0.0, 2.0, 0.0 );
glPushMatrix();
glTranslatef( CenterX[0], CenterY[0], 1.0 );
glutSolidSphere( Radius[0], 25, 25);
glPopMatrix();
glFlush();

// Circle Obstacle 2
glColor3f( 0.0, 2.0, 0.0 );
glPushMatrix();
glTranslatef( CenterX[1], CenterY[1], 2.0 );
glutSolidSphere( Radius[1], 25, 25);
glPopMatrix();
glFlush();

// Circle Obstacle 3
glColor3f( 0.0, 2.0, 0.0 );
glPushMatrix();
glTranslatef( CenterX[2], CenterY[2], 2.0 );
glutSolidSphere( Radius[2], 25, 25);
glPopMatrix();
glFlush();



// Slow the simulation down
//Sleep( 0.00003 );

// Set up Ball object through external class Tigger
// This does computations for new CENTER and VELOCITY
Tigger Ball(center,velocity);


// Find current distance from each Circle obstacle
for (int i=0; i<3; i++) {
x = (CenterX[i]-center[0]);
y = (CenterY[i]-center[1]);
distance[i] = sqrt( (x*x) + (y*y) );
}

//What happens when an obstacle impact occurs
if (distance[0]==Radius[0]){
Ball.normC(CenterX[0],CenterY[0]);

// Calculate Bounce Velocity
velocity[0]=Ball.newVx();
velocity[1]=Ball.newVy();

// Calculate Bounce center
center[0]=Ball.newCx();
center[1]=Ball.newCy();
}

else if (distance[1]==Radius[1]){
Ball.normC(CenterX[1],CenterY[1]);

// Calculate Bounce Velocity
velocity[0]=Ball.newVx();
velocity[1]=Ball.newVy();

// Calculate Bounce center
center[0]=Ball.newCx();
center[1]=Ball.newCy();
}

else if (distance[2]==Radius[2]){
Ball.normC(CenterX[2],CenterY[2]);

// Calculate Bounce Velocity
velocity[0]=Ball.newVx();
velocity[1]=Ball.newVy();

// Calculate Bounce center
center[0]=Ball.newCx();
center[1]=Ball.newCy();
}



// What happens when a perimeter impact occurs
else if (T==Ball.Time(A,B,C,D,E))
{
// Calculate Bounce Velocity
velocity[0]=Ball.newVx();
velocity[1]=Ball.newVy();

// Calculate Bounce center
center[0]=Ball.newCx();
center[1]=Ball.newCy();

T=0.001;
}
else
{
// Calculate the new center
center[0] += (velocity[0]*(T));
center[1] += (velocity[1]*(T));
}

glutSwapBuffers();
}

}

void
main(int argc, char **argv) {

glutInit(&amp;argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100,100);
glutInitWindowSize(600,600);
glutCreateWindow("Sphere In Irregular Pentagon");
glClearColor( 20.0, 0.0, 0.0, 0.0 );
glOrtho(0,25,0,25,-1,1);
glutDisplayFunc(display);
glutMainLoop();
}If it helps, I'll describe what I tried to do. My problem is set up that I start with a Ball of given center and velocity vector enclosed within the pentagon. What I did to get it to bounce is set up a while loop of infinity (while (1) ), in which the scene iterates by .001 seconds. I find the minimum time the ball will take to hit a surface (thus, the smallest non negatively timed surface collision) and have it reflect off that surface, else just increment the center by velocity times time ( C += V*T ).

For circle detection, established that for a collision to occur, the ball must be Radius distance from the center of the obstacle, and say that if at the given time in the loop that distance equals the radius of the obstacle, reflect, with the normal being the line from the center of the obstacle through the point of contact on the circumference. I am assuming that the way I impliment my code prevents me from being able to use the distance as a proof when the time is the variable, but if I prove according to Time, I would have 2 uknowns: Time and the position of the Hit, and I can't seem to work with that right now.

Also, can someone help me use my code successfully using an glutIdleFunc() rather than the while loop?

Thanks alot in advance.

memfr0b
10-22-2005, 04:33 AM
From a quick glance at your code, the problem is that your collision test only triggers when the spheres exactly touch, but ignores any overlapping.

You're working with discrete time increments, so while in one frame the moving sphere doesn't touch any object yet, in the next frame it might already be nearer to one of the obstacle spheres than it is allowed to.

Your test should probably look more like


if (distance[0] < radius[0]) { ... } ...

JRoop
10-24-2005, 08:01 PM
Thanks, that helped a little, in terms of the logic behind the problem. However, the results are similar to implementing it without the case of if the object already penetrates the obstacles (I had assumed before, since the ball was moving in increments of time, that there would be a distance of hit where the distance and radius were equal and therefore caught the problem of it penetrating before). What occurs now is the same error I had once had when I initially tackled this assignment, where the ball somehow escaped from the pentagon it was bouncing in, and instead bounced along the extended lines of the pentagon (my setup for time in the Tigger class uses a minimum time of impact of the object with all of the lines involved in the perimeter it bounces within, and found that float numbers were cumbersome and thus created a function that rounded to the nearest thousandth rather than the float's hundred thousandth) outside of the pentagon itself.

Is there a better way to test collision, one that would involve the time rather than distance, since I test for time in the polygon/ball collision?