diff --git a/source/src/Physics/Shapes/RealtimeCollisions.ts b/source/src/Physics/Shapes/RealtimeCollisions.ts new file mode 100644 index 00000000..47314dc5 --- /dev/null +++ b/source/src/Physics/Shapes/RealtimeCollisions.ts @@ -0,0 +1,48 @@ +module es { + export class RealtimeCollisions { + public static intersectMovingCircleToBox(s: Circle, b: Box, movement: Vector2): number { + // 计算用球面半径r inflate b得到的AABB + let e = b.bounds; + e.inflate(s.radius, s.radius); + + // 射线与展开矩形e相交。如果射线错过了e,则退出不相交,否则得到相交点p和时间t + let ray = new Ray2D(Vector2.subtract(s.position, movement), s.position); + let time = e.rayIntersects(ray); + if (time > 1) + return time; + + // 求交点 + let point = Vector2.add(ray.start, Vector2.add(ray.direction, new Vector2(time))); + + // 计算b的最小面和最大面p的交点在哪个面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。 + let u, v = 0; + if (point.x < b.bounds.left) + u |= 1; + if (point.x > b.bounds.right) + v |= 1; + if (point.y < b.bounds.top) + u |= 2; + if (point.y > b.bounds.bottom) + v |= 2; + + // 将所有位集合成位掩码(注意u + v == u | v) + let m = u + v; + + // 如果所有的3位都被设置,那么点在一个顶点区域 + if (m == 3){ + // 现在必须相交的部分,如果一个或多个击中对胶囊的两边会合在斜面和返回的最佳时间 + // TODO: 需要实现这个 + console.log(`m == 3. corner ${Time.frameCount}`); + } + + // 如果m中只设置了一个位,那么点在一个面区域 + if ((m & (m - 1)) == 0){ + // 什么也不做。从扩展矩形交集的时间是正确的时间 + return time; + } + + // 点在边缘区域上。与边缘相交。 + return time; + } + } +} \ No newline at end of file diff --git a/source/src/Physics/Shapes/ShapeCollisions/ShapeCollisions.ts b/source/src/Physics/Shapes/ShapeCollisions/ShapeCollisions.ts index ebf4d570..451c61fb 100644 --- a/source/src/Physics/Shapes/ShapeCollisions/ShapeCollisions.ts +++ b/source/src/Physics/Shapes/ShapeCollisions/ShapeCollisions.ts @@ -1,4 +1,9 @@ module es { + /** + * 各种形状的碰撞例程 + * 大多数人都希望第一个形状位于第二个形状的空间内(即shape1) + * pos应该设置为shape1。pos - shape2.pos)。 + */ export class ShapeCollisions { /** * 检查两个多边形之间的碰撞 @@ -306,5 +311,45 @@ module es { return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y) } + + /** + * 用second检查被deltaMovement移动的框的结果 + * @param first + * @param second + * @param movement + * @param hit + */ + public static boxToBoxCast(first: Box, second: Box, movement: Vector2, hit: RaycastHit): boolean{ + // 首先,我们检查是否有重叠。如果有重叠,我们就不做扫描测试 + let minkowskiDiff = this.minkowskiDifference(first, second); + if (minkowskiDiff.contains(0, 0)){ + // 计算MTV。如果它是零,我们就可以称它为非碰撞 + let mtv = minkowskiDiff.getClosestPointOnBoundsToOrigin(); + if (mtv.equals(Vector2.zero)) + return false; + + hit.normal = new Vector2(-mtv.x); + hit.normal = hit.normal.normalize(); + hit.distance = 0; + hit.fraction = 0; + + return true; + }else{ + // 射线投射移动矢量 + let ray = new Ray2D(Vector2.zero, new Vector2(-movement.x)); + let fraction: number = minkowskiDiff.rayIntersects(ray); + if (fraction <= 1){ + hit.fraction = fraction; + hit.distance = movement.length() * fraction; + hit.normal = new Vector2(-movement.x); + hit.normal = hit.normal.normalize(); + hit.centroid = Vector2.add(first.bounds.center, Vector2.multiply(movement, new Vector2(fraction))); + + return true; + } + } + + return false; + } } }