In my initial (basic collision example) posting above, the ball reflection was not really accurate, as it followed the normal vector–not the true reflection vector. I thought it might be helpful for (someone) to see an example of a more accurate reflection, using the equation: R = 2N(N•L)-L, where R is the reflection vector, N is the normal vector (really perpendicular vector in 2D), and L is the incidence vector (incoming vector). The (N•L) part of the equation is a dot product (also referred to as scaler product) calculation, which is solved simply by (N.x*L.x + N.y*L.y). What's not evident in the equation is that the vectors N and L need to be normalized, which simply means dividing each of them by their own length. the length of a vector can be found by: sqrt(v.x*v.x + v.y*v.y). The example is procedural, and if I get a minute I'll post a more "classy" OOP one - or (someone) else can
-ira
Code:
/* Example of reflection off a
non-orthogonal surface using
the equation: R = 2N(N•L)-L */
float x1, x2, y1, y2;
// arbitrary direction and speed values to begin
float directionX = .78, directionY = .83;
float speed = 2.5;
float velocityX, velocityY;
float r = 5, r2 = 50;
float startX = 100, startY = 100;
void setup(){
size(400, 400);
x1 = startX;
y1 = startY;
x2 = 200;
y2 = 200;
smooth();
}
void draw(){
fill(0, 10);
rect(0, 0, width, height);
stroke(255);
// calc ball's velocity as vector
velocityX = directionX*speed;
velocityY = directionY*speed;
// move ball
x1+=velocityX;
y1+=velocityY;
// create ball 1
ellipse(x1, y1, r*2, r*2);
// ball 2 - under mouse control
x2 = mouseX;
y2 = mouseY;
ellipse(x2, y2, r2*2, r2*2);
// collision between balls
float ballDist = dist(x1, y1, x2, y2);
if (ballDist < r+r2){
/* reflection calculations below
based on the equation R = 2N(N•L)-L */
/********** incidence vector **********/
float incidenceVectorDist = dist(startX, startY, x1, y1);
// calculate vector
float incidenceVectorX = (startX-x1);
float incidenceVectorY = (startY-y1);
// normalize vector
incidenceVectorX /= incidenceVectorDist;
incidenceVectorY /= incidenceVectorDist;
/********** normal vector **********/
// (in 2D really a perpendicular)
float normalVectorX = (x1-x2);
float normalVectorY = (y1-y2);
// normalize vector
normalVectorX /= ballDist;
normalVectorY /= ballDist;
/* draw normal just to illustrate how the
angle of incidence = angle of reflection */
stroke(255, 128, 0);
line(x1, y1, x2, y2);
// dot product calcuation part of the equation (N•L)
float dot = incidenceVectorX*normalVectorX + incidenceVectorY*normalVectorY;
// finish equation calcs
float reflectionVectorX = normalVectorX*2*dot - incidenceVectorX;
float reflectionVectorY = normalVectorY*2*dot - incidenceVectorY;
// reflection assignment
directionX = reflectionVectorX;
directionY = reflectionVectorY;
// keep balls from overlapping
x1 = x2+(r+r2)*normalVectorX;
y1 = y2+(r+r2)*normalVectorY;
/* resets incidence vector's starting point
(sort of a necessary hack to avoid more
complicated collision detection */
resetIncidenceVector();
}
// detect boundary collision
if (x1>width-r){
x1=width-r;
directionX*=-1;
resetIncidenceVector();
}
if (x1<r){
x1=r;
directionX*=-1;
resetIncidenceVector();
}
if (y1>height-r){
y1=height-r;
directionY*=-1;
resetIncidenceVector();
}
if (y1<r){
y1=r;
directionY*=-1;
resetIncidenceVector();
}
}
/* resets ball's start position each collision-
used in incidence vector calculation */
void resetIncidenceVector(){
startX = x1;
startY = y1;
}