FPS370 - Changes from Alpha5 to Alpha6
Bouncing Ball - arbitrary bouce

In the previous version, the ball bounced only if it hit the wall squarely. In this example, I have added the case where the ball hits the wall at an angle. There is a simple check for this after we calculate the dot product. If the dot product between the ball's velocity and the wall's surface normal < 0, then the angle is obtuse (>90 degrees). Meaning the vectors are facing each other.

Here is the majority of the code change.

             else  if (f<0.0f)  // obtuse angle dot product - headed towards object
              {
                /* now for the not so simple case of an arbitrary hit */
                /* dot < 0.0 means we are headed towards the object (obtuse angle) */

                /* what we do here is rotate the velocity vector around the
                 * cross product of the two vectors
                 */
                v3fTmp2.cross(v3fTmp,v3fTmp3);            
 
                // convert it to an angle
                f = (float) Math.toDegrees(Math.acos(f));

                // ret ang is the angle from the surface normal and the new bounce/return angle
                // draw some pictures to decide why 180-f
                float retang = 180.0f - f;

                // reflect the velocity as we will rotate that through the surface normal
                vSphereVel.negate();
                
                // rotate that the angle between the normal *2
                float frot = retang * 2.0f;

                // reusing the temporary AxisAngle that YPR uses
                aaYPR.set(v3fTmp2,(float)Math.toRadians(frot));

                // create a matrix then transform with this rotate
                m3fTmp1.set(aaYPR);
                t3dTmp.set(m3fTmp1);

                // multiply the current velocity by that rotation
                t3dTmp.transform(vSphereVel);

                // subtract a little friction to make up for the fact that the
                // sphere didn't actually touch the wall
                // otherwise the bounce gets larger and larger. This is a kludge
                vSphereVel.scale(0.90f);

                didHit = true;
              }

The cross product between the two vectors is parallel to the surface normal and perpendicular to the direction of travel. We will rotate the velocity vector around this vector. The next thing is to convert the dot product to an actual angle between the two vectors.

               f = (float) Math.toDegrees(Math.acos(f));

This will be an obtuse angle (>90 degrees) because the ball's velocity is headed towards the wall). We now subtract that angle from 180 to find the angle between the surface normal and the refelection of the ball's velocity.

              float retang = 180.0f - f;
	  
	            // reflect the velocity as we will rotate that through the surface normal
              vSphereVel.negate();
 

I could have calculated the retang from another dot product on the reflected velocity, but this is less compute intensive. This angle (retang) will be the angle we use to rotate the velocity by. If we used this value we would end up with a vector that is the same vector as the surface normal. If we use the angle times 2, we end up with a reflection around the surface normal.
	            // rotate that the angle between the normal *2
                float frot = retang * 2.0f;


                // reusing the temporary AxisAngle that YPR uses
                 aaYPR.set(v3fTmp2,(float)Math.toRadians(frot));


                // create a matrix then transform with this rotate
                m3fTmp1.set(aaYPR);
                t3dTmp.set(m3fTmp1);


                // multiply the current velocity by that rotation
                t3dTmp.transform(vSphereVel);

I'm reusing the the AxisAngle from the YPR calculations. It isn't the safest thing to do, but it takes less memory and it is well documented. The aaYPR is really just used in temporary calculations. Once the AxisAngle is created it is a simple matter of transforming the sphere velocity (vSphereVel).

I also moved all of this code form the tickSphere method to it's own checkSphereHit method. It was getting long and I also added while look around the entire check. If the sphere hits a wall, we need to recheck the new velocity vector for a collision as the next move may put it outside another wall. I keep a didHit boolean and don't exit out of the loop until it will not hit anything on the next loop. This is very dangerous and should also be wrapped by either a drastic velocity reduction or a maximum number of times through the while look. As it stands, this method will eventually cause an infinite loop when the map model get's a little more complex.

Note: This does not by any means use proper physics. It is not meant to. It is meant as an example as to how most games "fudge" this kind of effect. We may come back and do more of the physics later, but for now it is meant to be instructional and a distilled down simplification

I did find a pretty good article on Physics and Collision Response.

CPSC370 - Games Development
Chapman University
Instructor: W. Wood Harter
(c) copyright 2006 - W. Wood Harter - All Rights Reserved
Screen shots on banner (c) copyright their resprective owners