The real secret lies in a bunch of geometric functions operating on line segments. Those are tests for intersection, cutting one segment with another, etc. In this case, the most crucial is function to calculate reflection of segment while it collides with another. I won’t get into the math details here as it is some basic algebra and there are plenty of tutorials on the web. Having this in each frame I just calculate the next position of ball (including gravity and user input). Before actually applying the new position I create line segment (or vector) starting at balls current pos and ending at destined pos. This segment is the reflected with all the solid lines in level (actual walls). BTW there is a small error in my code, there should be a loop iterating with all lines untill there is no intersection - but somehow I missed it.
There is code to download but I will post it here:
part of Player.as, earlier declarations
public var dx:Number = 0; //incremental step to next position
public var dy:Number = 0;
public var out:Vector3D = new Vector3D(); // temporary vector for getting line segment reflection calculations
public static var frictionFactor:Number = 0.99;
declaration of reflectOnSegment function
/* cuts second (q) segment with first (p) one then reflects cut off part by first (p) segment
* returns
* - unchanged q1 to q2 segment when no intersection
* - segment from intersection to reflected end
*/
public static function
reflectOnSegment(
p1x:Number, p1y:Number, p2x:Number, p2y:Number,
q1x:Number, q1y:Number, q2x:Number, q2y:Number,
output:Vector3D):void
{
...
// output's x,y are line segment's first coordinates, and z,w second
}
and finally checking for collisions
public function motion():Boolean
{
var lines:Vector.<Line> = new Vector.<Line>;
world.getType("line", lines );
for each (var l:Line in lines) {
Utils.reflectOnSegment(l.x1, l.y1, l.x2, l.y2, x, y, x + dx, y + dy, out);
if (out.w != y + dy) {
dy = out.w - y;
dy *= frictionFactor;
}
if (out.z != x + dx) {
dx = out.z - x;
dx *= frictionFactor;
}
}
if (out.w != y + dy || out.z != x + dx) return true;
return false;
}
So basically this is just a trick. Instead of a ball physics only single point is being bounced off the walls. Press F1 while playing to see it in action.