新增射线检测
This commit is contained in:
48
source/src/Physics/Shapes/RealtimeCollisions.ts
Normal file
48
source/src/Physics/Shapes/RealtimeCollisions.ts
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user