Files
esengine/source/src/Physics/Collision.ts
2020-07-28 16:25:20 +08:00

171 lines
6.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
module es {
export enum PointSectors {
center = 0,
top = 1,
bottom = 2,
topLeft = 9,
topRight = 5,
left = 8,
right = 4,
bottomLeft = 10,
bottomRight = 6
}
export class Collisions {
public static isLineToLine(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2): boolean {
let b = Vector2.subtract(a2, a1);
let d = Vector2.subtract(b2, b1);
let bDotDPerp = b.x * d.y - b.y * d.x;
// 如果b*d = 0表示这两条直线平行因此有无穷个交点
if (bDotDPerp == 0)
return false;
let c = Vector2.subtract(b1, a1);
let t = (c.x * d.y - c.y * d.x) / bDotDPerp;
if (t < 0 || t > 1)
return false;
let u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
return false;
return true;
}
public static lineToLineIntersection(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2): Vector2 {
let intersection = new Vector2(0, 0);
let b = Vector2.subtract(a2, a1);
let d = Vector2.subtract(b2, b1);
let bDotDPerp = b.x * d.y - b.y * d.x;
// 如果b*d = 0表示这两条直线平行因此有无穷个交点
if (bDotDPerp == 0)
return intersection;
let c = Vector2.subtract(b1, a1);
let t = (c.x * d.y - c.y * d.x) / bDotDPerp;
if (t < 0 || t > 1)
return intersection;
let u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
return intersection;
intersection = Vector2.add(a1, new Vector2(t * b.x, t * b.y));
return intersection;
}
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
let t = Vector2.dot(w, v) / Vector2.dot(v, v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, new Vector2(v.x * t, v.y * t));
}
public static isCircleToCircle(circleCenter1: Vector2, circleRadius1: number, circleCenter2: Vector2, circleRadius2: number): boolean {
return Vector2.distanceSquared(circleCenter1, circleCenter2) < (circleRadius1 + circleRadius2) * (circleRadius1 + circleRadius2);
}
public static isCircleToLine(circleCenter: Vector2, radius: number, lineFrom: Vector2, lineTo: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, this.closestPointOnLine(lineFrom, lineTo, circleCenter)) < radius * radius;
}
public static isCircleToPoint(circleCenter: Vector2, radius: number, point: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, point) < radius * radius;
}
public static isRectToCircle(rect: egret.Rectangle, cPosition: Vector2, cRadius: number): boolean {
let ew = rect.width * 0.5;
let eh = rect.height * 0.5;
let vx = Math.max(0, Math.max(cPosition.x - rect.x) - ew);
let vy = Math.max(0, Math.max(cPosition.y - rect.y) - eh);
return vx * vx + vy * vy < cRadius * cRadius;
}
public static isRectToLine(rect: Rectangle, lineFrom: Vector2, lineTo: Vector2) {
let fromSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineFrom);
let toSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineTo);
if (fromSector == PointSectors.center || toSector == PointSectors.center) {
return true;
} else if ((fromSector & toSector) != 0) {
return false;
} else {
let both = fromSector | toSector;
// 线对边进行检查
let edgeFrom: Vector2;
let edgeTo: Vector2;
if ((both & PointSectors.top) != 0) {
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.bottom) != 0) {
edgeFrom = new Vector2(rect.x, rect.y + rect.height);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.left) != 0) {
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
if ((both & PointSectors.right) != 0) {
edgeFrom = new Vector2(rect.x + rect.width, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.isLineToLine(edgeFrom, edgeTo, lineFrom, lineTo))
return true;
}
}
return false;
}
public static isRectToPoint(rX: number, rY: number, rW: number, rH: number, point: Vector2) {
return point.x >= rX && point.y >= rY && point.x < rX + rW && point.y < rY + rH;
}
/**
* 位标志和帮助使用CohenSutherland算法
*
* 位标志:
* 1001 1000 1010
* 0001 0000 0010
* 0101 0100 0110
* @param rX
* @param rY
* @param rW
* @param rH
* @param point
*/
public static getSector(rX: number, rY: number, rW: number, rH: number, point: Vector2): PointSectors {
let sector = PointSectors.center;
if (point.x < rX)
sector |= PointSectors.left;
else if (point.x >= rX + rW)
sector |= PointSectors.right;
if (point.y < rY)
sector |= PointSectors.top;
else if (point.y >= rY + rH)
sector |= PointSectors.bottom;
return sector;
}
}
}