Wooo, ok so as I’m writing this I feel like a load has been lifted from my shoulders. Over the past few weeks I have been building a new game to promote MYFJ that has been using newly learned skills with Papervision3D.
One of the biggest challenges has been the collision detection between a point and a plane. With alot of research, playing with code and a few lengthy talks with fellow developers, I now have a piece of code that is working nicely. Below are some of the solutions which I have descovered.
I also want to say thanks to Seb Lee-Delisle and Marc Binsted for their help and code examples. Seb has written a few interesting articles about Predictive collision detection techniques and Predicting circle line collisions that I highly recomend. At first Vector Math blew my mind, but with some time, I have been able to get my head around it and get a better understanding of it.
Now I dont like to make things easy for myself, not only am I using a 3D engine, but my planes are rotated on the Z axis (they were rotating on the Y axis as well, but that was just causing way to many problems). So because of the Z axis rotation I couldn’t just work out if the point falls within an area using half the planes height and width. But first it was a case of working out the distance between the point and the plane, and to get there I needed to get the dot product. The below example uses the Number3D class within Papervision3D.
// GET THE DISTANCE FROM A POINT TO THE PLANE'S WORLD POSITION AS A DOT PRODUCT public function distanceToWorldPoint( p:Number3D ):Number { // TEMP BECOMES THE VECTOR BETWEEN THE POINT AND THE PLANES POSITION // copyFrom COPIES THE X,Y,Z PROPERTIES OF P this.temp.copyFrom( p ); // MINUS THE POSITION FROM TEMP - THE SAME AS -= OPERATOR this.temp.minusEq( this.w_position ); // RETURN THE DOT PRODUCT BETWEEN THE POINT AND THE PLANE return Number3D.dot( this.temp, this.normal ); }
Once I had the dot product of the current distance I then had to work out the distance in the next frame, by adding the points velocity of the points co-ordinates. With these two values you can get the time that collision will occur, but I only needed to know when the point was close to the plane. When I knew this I could then check to see if my point was within the planes triangle using the function below.
// CHECK TO SEE IF A POINT IS WITHIN A TRIANGLE static public function pointInTriangle2( p:Number3D, a:Number3D, b:Number3D, c:Number3D ):Boolean { // COMPUTE VECTORS var v0:Number3D = Number3D.sub( c, a ) var v1:Number3D = Number3D.sub( b, a ) var v2:Number3D = Number3D.sub( p, a ) // COMPUTE DOT PRODUCTS var dot00:Number = Number3D.dot( v0, v0 ) var dot01:Number = Number3D.dot( v0, v1 ) var dot02:Number = Number3D.dot( v0, v2 ) var dot11:Number = Number3D.dot( v1, v1 ) var dot12:Number = Number3D.dot( v1, v2 ) // COMPUTE BARYCENTRIC COORDINATES var invDenom:Number = 1 / ( dot00 * dot11 - dot01 * dot01 ) var u:Number = ( dot11 * dot02 - dot01 * dot12 ) * invDenom var v:Number = ( dot00 * dot12 - dot01 * dot02 ) * invDenom // Check if point is in triangle return (u > 0) && (v > 0) && (u + v < 1) }
I managed to find this and another technique of calculating whether a point was in a triangle and that can be found here. There is a nice little example on the site showing you how the calculations work. I also managed to find some nice little tips for speeding up Math calculations in Flash by using bitwise maths which I found on labs.polygonal.de. The Math.abs function was one of the most improved and helped speed things up.
static public function abs( x:Number ):Number { return (x ^ (x >> 31)) - (x >> 31); }
Another helpful tip Mark gave me was if you are making the same calculation over and over within the same class, then by declaring the Math function as a function, stops the Flash Player from continusly having to go and get that function. I was shocked at the difference it made.
private var math_sin:Function = Math.sin math_sin( angle )
