Skip to content

Commit

Permalink
新增RealtimeCollisions.testCircleBox用于检测园与方框是否重叠并返回point交点
Browse files Browse the repository at this point in the history
  • Loading branch information
esengine committed Dec 4, 2020
1 parent c8096e3 commit 8b3b645
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 21 deletions.
13 changes: 13 additions & 0 deletions source/bin/framework.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2691,6 +2691,19 @@ declare module es {
declare module es {
class RealtimeCollisions {
static intersectMovingCircleBox(s: Circle, b: Box, movement: Vector2, time: Ref<number>): boolean;
/**
* 支持函数,返回索引为n的矩形vert
* @param b
* @param n
*/
static corner(b: Rectangle, n: number): Vector2;
/**
* 检查圆是否与方框重叠,并返回point交点
* @param cirlce
* @param box
* @param point
*/
static testCircleBox(cirlce: Circle, box: Box, point: Vector2): boolean;
}
}
declare module es {
Expand Down
44 changes: 34 additions & 10 deletions source/bin/framework.js
Original file line number Diff line number Diff line change
Expand Up @@ -6656,16 +6656,16 @@ var es;
function RealtimeCollisions() {
}
RealtimeCollisions.intersectMovingCircleBox = function (s, b, movement, time) {
// 计算用球面半径r inflate b得到的AABB
// 计算将b按球面半径r扩大后的AABB
var e = b.bounds;
e.inflate(s.radius, s.radius);
// 射线与展开矩形e相交。如果射线错过了e,则退出不相交,否则得到相交点p和时间t
// 将射线与展开的矩形e相交,如果射线错过了e,则以无交点退出,否则得到交点p和时间t作为结果。
var ray = new es.Ray2D(es.Vector2.subtract(s.position, movement), s.position);
if (!e.rayIntersects(ray, time) && time.value > 1)
return false;
// 求交点
var point = es.Vector2.add(ray.start, es.Vector2.add(ray.direction, new es.Vector2(time.value)));
// 计算b的最小面和最大面p的交点在哪个面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。
// 计算交点p位于b的哪个最小面和最大面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。
var u, v = 0;
if (point.x < b.bounds.left)
u |= 1;
Expand All @@ -6675,22 +6675,46 @@ var es;
u |= 2;
if (point.y > b.bounds.bottom)
v |= 2;
// 将所有位集合成位掩码(注意u + v == u | v)
// 'or'将所有的比特集合在一起,形成一个比特掩码(注意u + v == u | v)
var m = u + v;
// 如果所有的3位都被设置,那么点在一个顶点区域
// 如果这3个比特都被设置,那么该点就在顶点区域内。
if (m == 3) {
// 现在必须相交的部分,如果一个或多个击中对胶囊的两边会合在斜面和返回的最佳时间
// TODO: 需要实现这个
// 如果有一条或多条命中,则必须在两条边的顶点相交,并返回最佳时间。
console.log("m == 3. corner " + es.Time.frameCount);
}
// 如果m中只设置了一个位,那么点在一个面区域
// 如果在m中只设置了一个位,那么该点就在一个面的区域。
if ((m & (m - 1)) == 0) {
// 什么也不做。从扩展矩形交集的时间是正确的时间
// 从扩大的矩形交点开始的时间就是正确的时间
return true;
}
// 点在边缘区域上。与边缘相交。
// 点在边缘区域,与边缘相交。
return true;
};
/**
* 支持函数,返回索引为n的矩形vert
* @param b
* @param n
*/
RealtimeCollisions.corner = function (b, n) {
var p = new es.Vector2();
p.x = (n & 1) == 0 ? b.right : b.left;
p.y = (n & 1) == 0 ? b.bottom : b.top;
return p;
};
/**
* 检查圆是否与方框重叠,并返回point交点
* @param cirlce
* @param box
* @param point
*/
RealtimeCollisions.testCircleBox = function (cirlce, box, point) {
// 找出离球心最近的点
point = box.bounds.getClosestPointOnRectangleToPoint(cirlce.position);
// 圆和方块相交,如果圆心到点的距离小于圆的半径,则圆和方块相交
var v = es.Vector2.subtract(point, cirlce.position);
var dist = es.Vector2.dot(v, v);
return dist <= cirlce.radius * cirlce.radius;
};
return RealtimeCollisions;
}());
es.RealtimeCollisions = RealtimeCollisions;
Expand Down
2 changes: 1 addition & 1 deletion source/bin/framework.min.js

Large diffs are not rendered by default.

48 changes: 38 additions & 10 deletions source/src/Physics/Shapes/RealtimeCollisions.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
module es {
export class RealtimeCollisions {
public static intersectMovingCircleBox(s: Circle, b: Box, movement: Vector2, time: Ref<number>): boolean {
// 计算用球面半径r inflate b得到的AABB
// 计算将b按球面半径r扩大后的AABB
let e = b.bounds;
e.inflate(s.radius, s.radius);

// 射线与展开矩形e相交。如果射线错过了e,则退出不相交,否则得到相交点p和时间t
// 将射线与展开的矩形e相交,如果射线错过了e,则以无交点退出,否则得到交点p和时间t作为结果。
let ray = new Ray2D(Vector2.subtract(s.position, movement), s.position);
if (!e.rayIntersects(ray, time) && time.value > 1)
return false;

// 求交点
let point = Vector2.add(ray.start, Vector2.add(ray.direction, new Vector2(time.value)));

// 计算b的最小面和最大面p的交点在哪个面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。
// 计算交点p位于b的哪个最小面和最大面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。
let u, v = 0;
if (point.x < b.bounds.left)
u |= 1;
Expand All @@ -24,24 +24,52 @@ module es {
if (point.y > b.bounds.bottom)
v |= 2;

// 将所有位集合成位掩码(注意u + v == u | v)
// 'or'将所有的比特集合在一起,形成一个比特掩码(注意u + v == u | v)
let m = u + v;

// 如果所有的3位都被设置,那么点在一个顶点区域
// 如果这3个比特都被设置,那么该点就在顶点区域内。
if (m == 3){
// 现在必须相交的部分,如果一个或多个击中对胶囊的两边会合在斜面和返回的最佳时间
// TODO: 需要实现这个
// 如果有一条或多条命中,则必须在两条边的顶点相交,并返回最佳时间。
console.log(`m == 3. corner ${Time.frameCount}`);
}

// 如果m中只设置了一个位,那么点在一个面区域
// 如果在m中只设置了一个位,那么该点就在一个面的区域。
if ((m & (m - 1)) == 0){
// 什么也不做。从扩展矩形交集的时间是正确的时间
// 从扩大的矩形交点开始的时间就是正确的时间
return true;
}

// 点在边缘区域上。与边缘相交。
// 点在边缘区域,与边缘相交。
return true;
}

/**
* 支持函数,返回索引为n的矩形vert
* @param b
* @param n
*/
public static corner(b: Rectangle, n: number){
let p = new Vector2();
p.x = (n & 1) == 0 ? b.right : b.left;
p.y = (n & 1) == 0 ? b.bottom : b.top;
return p;
}

/**
* 检查圆是否与方框重叠,并返回point交点
* @param cirlce
* @param box
* @param point
*/
public static testCircleBox(cirlce: Circle, box: Box, point: Vector2) {
// 找出离球心最近的点
point = box.bounds.getClosestPointOnRectangleToPoint(cirlce.position);

// 圆和方块相交,如果圆心到点的距离小于圆的半径,则圆和方块相交
let v = Vector2.subtract(point, cirlce.position);
let dist = Vector2.dot(v, v);

return dist <= cirlce.radius * cirlce.radius;
}
}
}

0 comments on commit 8b3b645

Please sign in to comment.