The trick I used was to treat the player as a circle, and do a line-circle collision test.

I chose a circle since it fills out most of the ninja, while also leaving a bit of wiggle room to make the gameplay more forgiving. Alternatively, I could have done laser-box collision, but that one is a little more complicated.

Not to say that the circle one isn't.

The main idea is that you raycast an infinite line towards the circle, and then constrain the line to the correct segment length. If there is a hit, the line

Below is the line-circle collision test algorithm. The laser line is represented by the "start" and "end" points. The player is represented by "circlePos" and "radius". The results of the collision are complicated, so we store all the juicy details in the "result" object.

The main idea is that you raycast an infinite line towards the circle, and then constrain the line to the correct segment length. If there is a hit, the line

*usually*intersects with 2 points on the circle.Below is the line-circle collision test algorithm. The laser line is represented by the "start" and "end" points. The player is represented by "circlePos" and "radius". The results of the collision are complicated, so we store all the juicy details in the "result" object.

/** * Modifies a RayCircleResult object specifying the points of intersection (if they exist) * @param start * @param end * @param circlePos * @param rad * @param result Results of the collision are stored here. * */ public static function lineSegmentCircle(start:Point, end:Point, circlePos:Point, rad:Number, result:RayCircleResult):void { result.reset(); var dir:Point = end.subtract(start); var dirLength:Number = dir.length; dir.normalize(1); var m:Point = start.subtract(circlePos); var b:Number = RapidU.dot(m, dir); var c:Number = RapidU.dot(m, m) - (rad * rad); if(c > 0 && b > 0) { // ray's orgin is outside the circle (c > 0) // and ray is pointing away from the circle (b > 0) result.intersectCount = 0; return; } var disc:Number = b*b - c; var t:Number; if(disc < 0) { // no intersection result.intersectCount = 0; return; } // find earliest time of intersection t = -b - Math.sqrt(disc); if(t < 0) t = 0; if(t > dirLength) { // beyond the end of the line segment result.intersectCount = 0; return; } result.point1.x = start.x + dir.x * t; result.point1.y = start.y + dir.y * t; if(disc == 0) { // tangent intersection, make both points the same result.intersectCount = 1; result.point2.x = result.point1.x; result.point2.y = result.point1.y; return; } // second point result.intersectCount = 2; t = -b + Math.sqrt(disc); if(t > dirLength) { // the line segment partially penetrates the circle result.point2.x = end.x; result.point2.y = end.y; return; } // end of the line is outside of the circle result.point2.x = start.x + dir.x * t; result.point2.y = start.y + dir.y * t; return; }

This code is all part of the open-source Rapid Physics engine that I wrote in parallel with Bullet Time Ninja. Feel free to dig deeper into the collision code on github, if you're into that kind of thing.

## No comments:

## Post a Comment