框架优化

This commit is contained in:
yhh
2021-07-02 10:11:09 +08:00
parent ea482dab48
commit 3d9c8699e7
31 changed files with 1050 additions and 1105 deletions
@@ -127,8 +127,7 @@ module es {
*/
public addImpulse(force: Vector2) {
if (!this.isImmovable) {
this.velocity = Vector2.add(this.velocity, Vector2.multiplyScaler(force, 100000)
.multiplyScaler(this._inverseMass * Time.deltaTime * Time.deltaTime));
this.velocity.addEqual(force.scale(100000 * (this._inverseMass * (Time.deltaTime * Time.deltaTime))));
}
}
@@ -152,7 +151,7 @@ module es {
if (this.shouldUseGravity)
this.velocity.addEqual(Physics.gravity.scale(Time.deltaTime));
this.entity.position = Vector2.add(this.entity.position, Vector2.multiplyScaler(this.velocity, Time.deltaTime));
this.entity.position = this.entity.position.add(this.velocity.scale(Time.deltaTime));
let collisionResult = new CollisionResult();
@@ -175,7 +174,7 @@ module es {
this.processCollision(neighborRigidbody, collisionResult.minimumTranslationVector);
} else {
// 没有ArcadeRigidbody,所以我们假设它是不动的,只移动我们自己的
this.entity.position = Vector2.subtract(this.entity.position, collisionResult.minimumTranslationVector);
this.entity.position = this.entity.position.sub(collisionResult.minimumTranslationVector);
const relativeVelocity = this.calculateResponseVelocity(this.velocity, collisionResult.minimumTranslationVector);
this.velocity.addEqual(relativeVelocity);
}
@@ -208,7 +207,7 @@ module es {
// 我们计算两个相撞物体的响应。
// 计算的基础是沿碰撞表面法线反射的物体的相对速度。
// 然后,响应的一部分会根据质量加到每个物体上
let relativeVelocity = Vector2.subtract(this.velocity, other.velocity);
let relativeVelocity = this.velocity.sub(other.velocity);
relativeVelocity = this.calculateResponseVelocity(relativeVelocity, minimumTranslationVector);
@@ -218,8 +217,8 @@ module es {
const otherResponseFraction = other._inverseMass / totalinverseMass;
this.velocity = Vector2.add(this.velocity, relativeVelocity.scale(ourResponseFraction));
other.velocity = Vector2.subtract(other.velocity, relativeVelocity.scale(otherResponseFraction));
this.velocity = this.velocity.add(relativeVelocity.scale(ourResponseFraction));
other.velocity = other.velocity.sub(relativeVelocity.scale(otherResponseFraction));
}
/**
@@ -230,14 +229,14 @@ module es {
*/
public calculateResponseVelocity(relativeVelocity: Vector2, minimumTranslationVector: Vector2) {
// 首先,我们得到反方向的归一化MTV:表面法线
let inverseMTV = Vector2.multiplyScaler(minimumTranslationVector, -1);
let normal = Vector2.normalize(inverseMTV);
let inverseMTV = minimumTranslationVector.scale(-1);
let normal = inverseMTV.normalize();
// 速度是沿碰撞法线和碰撞平面分解的。
// 弹性将影响沿法线的响应(法线速度分量),摩擦力将影响速度的切向分量(切向速度分量)
let n = Vector2.dot(relativeVelocity, normal);
let n = relativeVelocity.dot(normal);
let normalVelocityComponent = Vector2.multiplyScaler(normal, n);
let tangentialVelocityComponent = Vector2.subtract(relativeVelocity, normalVelocityComponent);
let normalVelocityComponent = normal.scale(n);
let tangentialVelocityComponent = relativeVelocity.sub(normalVelocityComponent);
if (n > 0)
normalVelocityComponent = Vector2.zero;
@@ -301,16 +301,16 @@ module es {
this.supportSlopedOneWayPlatforms &&
this.collisionState.wasGroundedLastFrame
) {
this._raycastHit = Physics.linecastIgnoreCollider(
this._raycastHit = Physics.linecast(
ray,
ray.add(rayDirection.multiplyScaler(rayDistance)),
ray.add(rayDirection.scaleEqual(rayDistance)),
this.platformMask,
this.ignoredColliders
);
} else {
this._raycastHit = Physics.linecastIgnoreCollider(
this._raycastHit = Physics.linecast(
ray,
ray.add(rayDirection.multiplyScaler(rayDistance)),
ray.add(rayDirection.scaleEqual(rayDistance)),
this.platformMask & ~this.oneWayPlatformMask,
this.ignoredColliders
);
@@ -380,9 +380,9 @@ module es {
initialRayOriginX + i * this._horizontalDistanceBetweenRays,
initialRayOriginY
);
this._raycastHit = Physics.linecastIgnoreCollider(
this._raycastHit = Physics.linecast(
rayStart,
rayStart.add(rayDirection.multiplyScaler(rayDistance)),
rayStart.add(rayDirection.scaleEqual(rayDistance)),
mask,
this.ignoredColliders
);
@@ -439,9 +439,9 @@ module es {
this._raycastOrigins.bottomLeft.y
);
this._raycastHit = Physics.linecastIgnoreCollider(
this._raycastHit = Physics.linecast(
slopeRay,
slopeRay.add(rayDirection.multiplyScaler(slopeCheckRayDistance)),
slopeRay.add(rayDirection.scaleEqual(slopeCheckRayDistance)),
this.platformMask,
this.ignoredColliders
);
@@ -502,14 +502,14 @@ module es {
this.supportSlopedOneWayPlatforms &&
this.collisionState.wasGroundedLastFrame
) {
raycastHit = Physics.linecastIgnoreCollider(
raycastHit = Physics.linecast(
ray,
ray.add(deltaMovement),
this.platformMask,
this.ignoredColliders
);
} else {
raycastHit = Physics.linecastIgnoreCollider(
raycastHit = Physics.linecast(
ray,
ray.add(deltaMovement),
this.platformMask & ~this.oneWayPlatformMask,
@@ -1,5 +1,7 @@
module es {
export abstract class Collider extends Component {
public static readonly lateSortOrder = 999;
public castSortOrder: number = 0;
/**
* 对撞机的基本形状
*/
@@ -132,12 +134,12 @@ module es {
if (this instanceof CircleCollider) {
this.radius = Math.max(width, height) * 0.5;
this.localOffset = Vector2.subtract(renderableBounds.center, this.entity.transform.position);
this.localOffset = renderableBounds.center.sub(this.entity.transform.position);
} else if (this instanceof BoxCollider) {
this.width = width;
this.height = height;
this.localOffset = Vector2.subtract(renderableBounds.center, this.entity.transform.position);
this.localOffset = renderableBounds.center.sub(this.entity.transform.position);
}
}
}
@@ -264,8 +266,8 @@ module es {
continue;
if (this.collidesWithNonMotion(neighbor, result)) {
motion = Vector2.subtract(motion, result.minimumTranslationVector);
this.shape.position = Vector2.subtract(this.shape.position, result.minimumTranslationVector);
motion = motion.sub(result.minimumTranslationVector);
this.shape.position = this.shape.position.sub(result.minimumTranslationVector);
didCollide = true;
}
}
+13 -13
View File
@@ -347,9 +347,9 @@ module es {
* @param pos
*/
public lookAt(pos: Vector2) {
let sign = this.position.x > pos.x ? -1 : 1;
let vectorToAlignTo = Vector2.normalize(Vector2.subtract(this.position, pos));
this.rotation = sign * Math.acos(Vector2.dot(vectorToAlignTo, Vector2.unitY));
const sign = this.position.x > pos.x ? -1 : 1;
const vectorToAlignTo = this.position.sub(pos).normalize();
this.rotation = sign * Math.acos(vectorToAlignTo.dot(Vector2.unitY));
}
/**
@@ -412,22 +412,22 @@ module es {
if (this._localDirty) {
if (this._localPositionDirty) {
this._translationMatrix = Matrix2D.createTranslation(this._localPosition.x, this._localPosition.y);
Matrix2D.createTranslation(this._localPosition.x, this._localPosition.y, this._translationMatrix);
this._localPositionDirty = false;
}
if (this._localRotationDirty) {
this._rotationMatrix = Matrix2D.createRotation(this._localRotation);
Matrix2D.createRotation(this._localRotation, this._rotationMatrix);
this._localRotationDirty = false;
}
if (this._localScaleDirty) {
this._scaleMatrix = Matrix2D.createScale(this._localScale.x, this._localScale.y);
Matrix2D.createScale(this._localScale.x, this._localScale.y, this._scaleMatrix);
this._localScaleDirty = false;
}
es.Matrix2D.multiply(this._scaleMatrix, this._rotationMatrix, this._localTransform);
es.Matrix2D.multiply(this._localTransform, this._translationMatrix, this._localTransform);
Matrix2D.multiply(this._scaleMatrix, this._rotationMatrix, this._localTransform);
Matrix2D.multiply(this._localTransform, this._translationMatrix, this._localTransform);
if (this.parent == null) {
this._worldTransform = this._localTransform;
@@ -440,9 +440,9 @@ module es {
}
if (this.parent != null) {
es.Matrix2D.multiply(this._localTransform, this.parent._worldTransform, this._worldTransform);
Matrix2D.multiply(this._localTransform, this.parent._worldTransform, this._worldTransform);
this._rotation = this._localRotation + this.parent._rotation;
this._scale = Vector2.multiply(this.parent._scale, this._localScale);
this._scale = this.parent._scale.multiply(this._localScale);;
this._worldInverseDirty = true;
}
@@ -457,13 +457,13 @@ module es {
this.hierarchyDirty |= dirtyFlagType;
switch (dirtyFlagType) {
case es.DirtyType.positionDirty:
case DirtyType.positionDirty:
this.entity.onTransformChanged(transform.Component.position);
break;
case es.DirtyType.rotationDirty:
case DirtyType.rotationDirty:
this.entity.onTransformChanged(transform.Component.rotation);
break;
case es.DirtyType.scaleDirty:
case DirtyType.scaleDirty:
this.entity.onTransformChanged(transform.Component.scale);
break;
}
+12 -12
View File
@@ -44,8 +44,8 @@ module es {
* @param t
*/
public static getFirstDerivative(p0: Vector2, p1: Vector2, p2: Vector2, t: number) {
return new Vector2(2 * (1 - t)).multiply(Vector2.subtract(p1, p0))
.addEqual(new Vector2(2 * t).multiply(Vector2.subtract(p2, p1)));
return p1.sub(p0).scale(2 * (1 - t))
.addEqual(p2.sub(p1).scale(2 * t));
}
/**
@@ -60,9 +60,9 @@ module es {
end: Vector2, t: number) {
t = MathHelper.clamp01(t);
let oneMunusT = 1 - t;
return new Vector2(3 * oneMunusT * oneMunusT).multiply(Vector2.subtract(firstControlPoint, start))
.addEqual(new Vector2(6 * oneMunusT * t).multiply(Vector2.subtract(secondControlPoint, firstControlPoint)))
.addEqual(new Vector2(3 * t * t).multiply(Vector2.subtract(end, secondControlPoint)));
return firstControlPoint.sub(start).scale(3 * oneMunusT * oneMunusT)
.addEqual(secondControlPoint.sub(firstControlPoint).scale(6 * oneMunusT * t))
.addEqual(end.sub(secondControlPoint).scale(3 * t * t));
}
/**
@@ -96,19 +96,19 @@ module es {
private static recursiveGetOptimizedDrawingPoints(start: Vector2, firstCtrlPoint: Vector2, secondCtrlPoint: Vector2,
end: Vector2, points: Vector2[], distanceTolerance: number) {
// 计算线段的所有中点
let pt12 = Vector2.divideScaler(Vector2.add(start, firstCtrlPoint), 2);
let pt23 = Vector2.divideScaler(Vector2.add(firstCtrlPoint, secondCtrlPoint), 2);
let pt34 = Vector2.divideScaler(Vector2.add(secondCtrlPoint, end), 2);
let pt12 = Vector2.divideScaler(start.add(firstCtrlPoint), 2);
let pt23 = Vector2.divideScaler(firstCtrlPoint.add(secondCtrlPoint), 2);
let pt34 = Vector2.divideScaler(secondCtrlPoint.add(end), 2);
// 计算新半直线的中点
let pt123 = Vector2.divideScaler(Vector2.add(pt12, pt23), 2);
let pt234 = Vector2.divideScaler(Vector2.add(pt23, pt34), 2);
let pt123 = Vector2.divideScaler(pt12.add(pt23), 2);
let pt234 = Vector2.divideScaler(pt23.add(pt34), 2);
// 最后再细分最后两个中点。如果我们满足我们的距离公差,这将是我们使用的最后一点。
let pt1234 = Vector2.divideScaler(Vector2.add(pt123, pt234), 2);
let pt1234 = Vector2.divideScaler(pt123.add(pt234), 2);
// 试着用一条直线来近似整个三次曲线
let deltaLine = Vector2.subtract(end, start);
let deltaLine = end.sub(start);
let d2 = Math.abs(((firstCtrlPoint.x, end.x) * deltaLine.y - (firstCtrlPoint.y - end.y) * deltaLine.x));
let d3 = Math.abs(((secondCtrlPoint.x - end.x) * deltaLine.y - (secondCtrlPoint.y - end.y) * deltaLine.x));
+17 -14
View File
@@ -10,19 +10,20 @@ module es {
* 在这个过程中,t被修改为在曲线段的范围内。
* @param t
*/
public pointIndexAtTime(t: Ref<number>): number {
let i = 0;
if (t.value >= 1) {
t.value = 1;
i = this._points.length - 4;
public pointIndexAtTime(t: number): {time: number, range: number} {
const res = {time: 0, range: 0};
if (t >= 1) {
t = 1;
res.range = this._points.length - 4;
} else {
t.value = MathHelper.clamp01(t.value) * this._curveCount;
i = ~~t;
t.value -= i;
i *= 3;
t = MathHelper.clamp01(t) * this._curveCount;
res.range = Math.floor(t);
t -= res.range;
res.range *= 3;
}
return i;
res.time = t;
return res;
}
/**
@@ -32,7 +33,7 @@ module es {
*/
public setControlPoint(index: number, point: Vector2) {
if (index % 3 == 0) {
let delta = Vector2.subtract(point, this._points[index]);
const delta = point.sub(this._points[index]);
if (index > 0)
this._points[index - 1].addEqual(delta);
@@ -48,7 +49,8 @@ module es {
* @param t
*/
public getPointAtTime(t: number): Vector2{
let i = this.pointIndexAtTime(new Ref(t));
const res = this.pointIndexAtTime(t);
const i = res.range;
return Bezier.getPointThree(this._points[i], this._points[i + 1], this._points[i + 2],
this._points[i + 3], t);
}
@@ -58,7 +60,8 @@ module es {
* @param t
*/
public getVelocityAtTime(t: number): Vector2 {
let i = this.pointIndexAtTime(new Ref(t));
const res = this.pointIndexAtTime(t);
const i = res.range;
return Bezier.getFirstDerivativeThree(this._points[i], this._points[i + 1], this._points[i + 2],
this._points[i + 3], t);
}
@@ -68,7 +71,7 @@ module es {
* @param t
*/
public getDirectionAtTime(t: number) {
return Vector2.normalize(this.getVelocityAtTime(t));
return this.getVelocityAtTime(t).normalize();
}
/**
+7 -3
View File
@@ -390,8 +390,8 @@ module es {
* @param other
*/
public static project(self: Vector2, other: Vector2) {
let amt = Vector2.dot(self, other) / other.lengthSquared();
let vec = new Vector2(amt * other.x, amt * other.y);
let amt = self.dot(other) / other.lengthSquared();
let vec = other.scale(amt);
return vec;
}
@@ -606,7 +606,7 @@ module es {
return false;
}
return !Number.isFinite(x);
return x !== Infinity;
}
public static smoothDamp(current: number, target: number, currentVelocity: number, smoothTime: number, maxSpeed: number, deltaTime: number): { value: number; currentVelocity: number } {
@@ -671,5 +671,9 @@ module es {
public static mapMinMax(value: number, leftMin: number, leftMax: number, rightMin: number, rightMax): number {
return rightMin + ((MathHelper.clamp(value, leftMin, leftMax) - leftMin) * (rightMax - rightMin)) / (leftMax - leftMin);
}
public static fromAngle(angle: number) {
return new Vector2(Math.cos(angle), Math.sin(angle)).normalizeEqual();
}
}
}
+42 -54
View File
@@ -16,7 +16,28 @@ module es {
* 返回标识矩阵
*/
public static get identity(): Matrix2D {
return new Matrix2D(1, 0, 0, 1, 0, 0);
return new Matrix2D().setIdentity();
}
public setIdentity(): Matrix2D {
return this.setValues(1, 0, 0, 1, 0, 0);
}
public setValues(
m11: number,
m12: number,
m21: number,
m22: number,
m31: number,
m32: number
): Matrix2D {
this.m11 = m11;
this.m12 = m12;
this.m21 = m21;
this.m22 = m22;
this.m31 = m31;
this.m32 = m32;
return this;
}
/**
@@ -38,7 +59,7 @@ module es {
return Math.atan2(this.m21, this.m11);
}
public set rotation(value: number){
public set rotation(value: number) {
let val1 = Math.cos(value);
let val2 = Math.sin(value);
@@ -71,42 +92,18 @@ module es {
this.m22 = value.y;
}
/**
* 构建一个矩阵
* @param m11
* @param m12
* @param m21
* @param m22
* @param m31
* @param m32
*/
constructor(m11: number, m12: number, m21: number, m22: number, m31: number, m32: number){
this.m11 = m11;
this.m12 = m12;
this.m21 = m21;
this.m22 = m22;
this.m31 = m31;
this.m32 = m32;
}
/**
* 创建一个新的围绕Z轴的旋转矩阵2D
* @param radians
*/
public static createRotation(radians: number){
let result: Matrix2D = this.identity;
let val1 = Math.cos(radians);
let val2 = Math.sin(radians);
public static createRotation(radians: number, result: Matrix2D) {
result.setIdentity();
const val1 = Math.cos(radians);
const val2 = Math.sin(radians);
result.m11 = val1;
result.m12 = val2;
result.m21 = -val2;
result.m21 = val2 * -1;
result.m22 = val1;
return result;
}
public static createRotationOut(radians: number, result: Matrix2D) {
@@ -124,18 +121,13 @@ module es {
* @param xScale
* @param yScale
*/
public static createScale(xScale: number, yScale: number){
let result: Matrix2D = this.identity;
public static createScale(xScale: number, yScale: number, result: Matrix2D) {
result.m11 = xScale;
result.m12 = 0;
result.m21 = 0;
result.m22 = yScale;
result.m31 = 0;
result.m32 = 0;
return result;
}
public static createScaleOut(xScale: number, yScale: number, result: Matrix2D) {
@@ -154,14 +146,11 @@ module es {
* @param xPosition
* @param yPosition
*/
public static createTranslation(xPosition: number, yPosition: number) {
let result: Matrix2D = this.identity;
public static createTranslation(xPosition: number, yPosition: number, result: Matrix2D) {
result.m11 = 1;
result.m12 = 0;
result.m21 = 0;
result.m22 = 1;
result.m31 = xPosition;
result.m32 = yPosition;
@@ -261,14 +250,14 @@ module es {
}
public static multiply(matrix1: Matrix2D, matrix2: Matrix2D, result: Matrix2D) {
let m11 = (matrix1.m11 * matrix2.m11) + (matrix1.m12 * matrix2.m21);
let m12 = (matrix1.m11 * matrix2.m12) + (matrix1.m12 * matrix2.m22);
const m11 = (matrix1.m11 * matrix2.m11) + (matrix1.m12 * matrix2.m21);
const m12 = (matrix1.m11 * matrix2.m12) + (matrix1.m12 * matrix2.m22);
let m21 = (matrix1.m21 * matrix2.m11) + (matrix1.m22 * matrix2.m21);
let m22 = (matrix1.m21 * matrix2.m12) + (matrix1.m22 * matrix2.m22);
const m21 = (matrix1.m21 * matrix2.m11) + (matrix1.m22 * matrix2.m21);
const m22 = (matrix1.m21 * matrix2.m12) + (matrix1.m22 * matrix2.m22);
let m31 = (matrix1.m31 * matrix2.m11) + (matrix1.m32 * matrix2.m21) + matrix2.m31;
let m32 = (matrix1.m31 * matrix2.m12) + (matrix1.m32 * matrix2.m22) + matrix2.m32;
const m31 = (matrix1.m31 * matrix2.m11) + (matrix1.m32 * matrix2.m21) + matrix2.m31;
const m32 = (matrix1.m31 * matrix2.m12) + (matrix1.m32 * matrix2.m22) + matrix2.m32;
result.m11 = m11;
result.m12 = m12;
@@ -278,8 +267,6 @@ module es {
result.m31 = m31;
result.m32 = m32;
return result;
}
public determinant() {
@@ -292,10 +279,10 @@ module es {
* @param matrix2
* @param amount
*/
public static lerp(matrix1: Matrix2D, matrix2: Matrix2D, amount: number){
public static lerp(matrix1: Matrix2D, matrix2: Matrix2D, amount: number) {
matrix1.m11 = matrix1.m11 + ((matrix2.m11 - matrix1.m11) * amount);
matrix1.m12 = matrix1.m12 + ((matrix2.m12 - matrix1.m12) * amount);
matrix1.m21 = matrix1.m21 + ((matrix2.m21 - matrix1.m21) * amount);
matrix1.m22 = matrix1.m22 + ((matrix2.m22 - matrix1.m22) * amount);
@@ -321,8 +308,9 @@ module es {
return ret;
}
public mutiplyTranslation(x: number, y: number){
let trans = Matrix2D.createTranslation(x, y);
public mutiplyTranslation(x: number, y: number) {
let trans = new Matrix2D();
Matrix2D.createTranslation(x, y, trans);
return MatrixHelper.mutiply(this, trans);
}
@@ -330,7 +318,7 @@ module es {
* 比较当前实例是否等于指定的Matrix2D
* @param other
*/
public equals(other: Matrix2D){
public equals(other: Matrix2D) {
return this == other;
}
+23 -22
View File
@@ -107,8 +107,8 @@ module es {
}
// temp 用于计算边界的矩阵
public _tempMat: Matrix2D;
public _transformMat: Matrix2D;
public _tempMat: Matrix2D = new Matrix2D();
public _transformMat: Matrix2D = new Matrix2D();
/**
* 创建一个新的Rectanglestruct实例,指定位置、宽度和高度。
@@ -213,49 +213,50 @@ module es {
this.top < value.bottom;
}
public rayIntersects(ray: Ray2D, distance: Ref<number>): boolean {
distance.value = 0;
public rayIntersects(ray: Ray2D): { intersected: boolean; distance: number } {
const res = {intersected: false, distance: 0};
let maxValue = Number.MAX_VALUE;
if (Math.abs(ray.direction.x) < 1E-06) {
if ((ray.start.x < this.x) || (ray.start.x > this.x + this.width))
return false;
return res;
} else {
let num11 = 1 / ray.direction.x;
const num11 = 1 / ray.direction.x;
let num8 = (this.x - ray.start.x) * num11;
let num7 = (this.x + this.width - ray.start.x) * num11;
if (num8 > num7) {
let num14 = num8;
const num14 = num8;
num8 = num7;
num7 = num14;
}
distance.value = Math.max(num8, distance.value);
res.distance = Math.max(num8, res.distance);
maxValue = Math.min(num7, maxValue);
if (distance.value > maxValue)
return false;
if (res.distance > maxValue)
return res;
}
if (Math.abs(ray.direction.y) < 1E-06) {
if (Math.abs(ray.direction.y) < 1e-06) {
if ((ray.start.y < this.y) || (ray.start.y > this.y + this.height))
return false;
return res;
} else {
let num10 = 1 / ray.direction.y;
const num10 = 1 / ray.direction.y;
let num6 = (this.y - ray.start.y) * num10;
let num5 = (this.y + this.height - ray.start.y) * num10;
if (num6 > num5) {
let num13 = num6;
const num13 = num6;
num6 = num5;
num5 = num13;
}
distance.value = Math.max(num6, distance.value);
res.distance = Math.max(num6, res.distance);
maxValue = Math.max(num5, maxValue);
if (distance.value > maxValue)
return false;
if (res.distance > maxValue)
return res;
}
return true;
res.intersected = true;
return res;
}
/**
@@ -421,12 +422,12 @@ module es {
let worldPosY = parentPosition.y + position.y;
// 考虑到原点,将参考点设置为世界参考
this._transformMat = Matrix2D.createTranslation(-worldPosX - origin.x, -worldPosY - origin.y);
this._tempMat = Matrix2D.createScale(scale.x, scale.y);
Matrix2D.createTranslation(-worldPosX - origin.x, -worldPosY - origin.y, this._transformMat);
Matrix2D.createScale(scale.x, scale.y, this._tempMat);
this._transformMat = this._transformMat.multiply(this._tempMat);
this._tempMat = Matrix2D.createRotation(rotation);
Matrix2D.createRotation(rotation, this._tempMat);
this._transformMat = this._transformMat.multiply(this._tempMat);
this._tempMat = Matrix2D.createTranslation(worldPosX, worldPosY);
Matrix2D.createTranslation(worldPosX, worldPosY, this._tempMat);
this._transformMat = this._transformMat.multiply(this._tempMat);
// TODO: 我们可以把世界变换留在矩阵中,避免在世界空间中得到所有的四个角
+47 -90
View File
@@ -77,74 +77,13 @@ module es {
return result;
}
/**
*
* @param value1
* @param value2
*/
public static multiply(value1: Vector2, value2: Vector2) {
let result: Vector2 = es.Vector2.zero;
result.x = value1.x * value2.x;
result.y = value1.y * value2.y;
return result;
}
/**
*
* @param value1
* @param value2
* @returns
*/
public static multiplyScaler(value1: Vector2, value2: number) {
let result = es.Vector2.zero;
result.x = value1.x * value2;
result.y = value1.y * value2;
return result;
}
/**
*
* @param value1
* @param value2
*/
public static subtract(value1: Vector2, value2: Vector2) {
let result: Vector2 = es.Vector2.zero;
result.x = value1.x - value2.x;
result.y = value1.y - value2.y;
return result;
}
/**
* 创建一个新的Vector2
* 它包含来自另一个向量的标准化值。
* @param value
*/
public static normalize(value: Vector2) {
const d = value.distance();
if (d > 0) {
return new Vector2(value.x / d, value.y / d);
} else {
return new Vector2(0, 1);
}
}
/**
* 返回两个向量的点积
* @param value1
* @param value2
*/
public static dot(value1: Vector2, value2: Vector2): number {
return (value1.x * value2.x) + (value1.y * value2.y);
}
/**
* 返回两个向量之间距离的平方
* @param value1
* @param value2
*/
public static distanceSquared(value1: Vector2, value2: Vector2) {
let v1 = value1.x - value2.x, v2 = value1.y - value2.y;
return (v1 * v1) + (v2 * v2);
public static sqrDistance(value1: Vector2, value2: Vector2) {
return Math.pow(value1.x - value2.x, 2) + Math.pow(value1.y - value2.y, 2);
}
/**
@@ -207,9 +146,8 @@ module es {
* @param value2
* @returns 两个向量之间的距离
*/
public static distance(value1: Vector2, value2: Vector2): number {
let v1 = value1.x - value2.x, v2 = value1.y - value2.y;
return Math.sqrt((v1 * v1) + (v2 * v2));
public static distance(vec1: Vector2, vec2: Vector2): number {
return Math.sqrt(Math.pow(vec1.x - vec2.x, 2) + Math.pow(vec1.y - vec2.y, 2));
}
/**
@@ -218,9 +156,9 @@ module es {
* @param to
*/
public static angle(from: Vector2, to: Vector2): number {
from = Vector2.normalize(from);
to = Vector2.normalize(to);
return Math.acos(MathHelper.clamp(Vector2.dot(from, to), -1, 1)) * MathHelper.Rad2Deg;
from = from.normalize();
to = to.normalize();
return Math.acos(MathHelper.clamp(from.dot(to), -1, 1)) * MathHelper.Rad2Deg;
}
/**
@@ -266,6 +204,10 @@ module es {
this.y = y;
}
public negate(): Vector2 {
return this.scale(-1);
}
/**
*
* @param value
@@ -301,9 +243,7 @@ module es {
* @param value
*/
public multiply(value: Vector2): Vector2 {
this.x *= value.x;
this.y *= value.y;
return this;
return new Vector2(value.x * this.x, value.y * this.y);
}
/**
@@ -332,6 +272,10 @@ module es {
return this;
}
public dot(v: Vector2): number {
return this.x * v.x + this.y * v.y;
}
/**
*
* @param size
@@ -341,10 +285,32 @@ module es {
return new Vector2(this.x * size, this.y * size);
}
public scaleEqual(size: number): Vector2 {
this.x *= size;
this.y *= size;
return this;
}
public transform(matrix: Matrix2D): Vector2 {
return new Vector2(
this.x * matrix.m11 + this.y * matrix.m21 + matrix.m31,
this.x * matrix.m12 + this.y * matrix.m22 + matrix.m32
);
}
public normalize(): Vector2 {
const d = this.distance();
if (d > 0) {
return new Vector2(this.x / d, this.y / d);
} else {
return new Vector2(0, 1);
}
}
/**
* 将这个Vector2变成一个方向相同的单位向量
*/
public normalize() {
public normalizeEqual(): Vector2 {
const d = this.distance();
if (d > 0) {
this.setTo(this.x / d, this.y / d);
@@ -355,14 +321,9 @@ module es {
}
}
/** 返回它的长度 */
public length() {
return Math.sqrt((this.x * this.x) + (this.y * this.y));
}
public magnitude(): number {
return this.distance();
}
}
public distance(v?: Vector2): number {
if (!v) {
@@ -393,8 +354,8 @@ module es {
* @param right
*/
public angleBetween(left: Vector2, right: Vector2) {
let one = Vector2.subtract(left, this);
let two = Vector2.subtract(right, this);
let one = left.sub(this);
let two = right.sub(this);
return Vector2Ext.angle(one, two);
}
@@ -403,12 +364,8 @@ module es {
* @param other 要比较的对象
* @returns 如果实例相同true 否则false
*/
public equals(other: Vector2 | object): boolean {
if (other instanceof Vector2) {
return other.x == this.x && other.y == this.y;
}
return false;
public equals(other: Vector2, tolerance: number = 0.001): boolean {
return Math.abs(this.x - other.x) <= tolerance && Math.abs(this.y - other.y) <= tolerance;
}
public isValid(): boolean {
@@ -452,10 +409,10 @@ module es {
}
public static unsignedAngle(from: Vector2, to: Vector2, round: boolean = true) {
from.normalize();
to.normalize();
from.normalizeEqual();
to.normalizeEqual();
const angle =
Math.acos(MathHelper.clamp(Vector2.dot(from, to), -1, 1)) * MathHelper.Rad2Deg;
Math.acos(MathHelper.clamp(from.dot(to), -1, 1)) * MathHelper.Rad2Deg;
return round ? Math.round(angle) : angle;
}
+14 -6
View File
@@ -19,13 +19,14 @@ module es {
* 它将处理任何与Collider重叠的ITriggerListeners。
*/
public update() {
const lateColliders = [];
// 对所有实体.colliders进行重叠检查,这些实体.colliders是触发器,与所有宽相碰撞器,无论是否触发器。
// 任何重叠都会导致触发事件
let colliders = this._entity.getComponents(Collider);
for (let i = 0; i < colliders.length; i++) {
let collider = colliders[i];
let neighbors = Physics.boxcastBroadphase(collider.bounds, collider.collidesWithLayers);
let neighbors = Physics.boxcastBroadphaseExcludingSelf(collider.bounds, collider.collidesWithLayers);
for (let j = 0; j < neighbors.length; j++) {
let neighbor = neighbors[j];
// 我们至少需要一个碰撞器作为触发器
@@ -33,21 +34,28 @@ module es {
continue;
if (collider.overlaps(neighbor)) {
let pair = new Pair<Collider>(collider, neighbor);
const pair = new Pair<Collider>(collider, neighbor);
// 如果我们的某一个集合中已经有了这个对子(前一个或当前的触发交叉点),就不要调用输入事件了
let shouldReportTriggerEvent = !this._activeTriggerIntersections.contains(pair) &&
const shouldReportTriggerEvent = !this._activeTriggerIntersections.contains(pair) &&
!this._previousTriggerIntersections.contains(pair);
if (shouldReportTriggerEvent)
this.notifyTriggerListeners(pair, true);
if (shouldReportTriggerEvent) {
if (neighbor.castSortOrder >= Collider.lateSortOrder) {
lateColliders.push(pair);
} else {
this.notifyTriggerListeners(pair, true);
}
}
this._activeTriggerIntersections.add(pair);
}
}
}
ListPool.free(colliders);
for (const pair of lateColliders) {
this.notifyTriggerListeners(pair, true);
}
this.checkForExitedColliders();
}
+32 -30
View File
@@ -13,22 +13,24 @@ module es {
export class Collisions {
public static lineToLine(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;
const b = a2.sub(a1);
const d = b2.sub(b1);
const 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)
const c = b1.sub(a1);
const 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)
const u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1) {
return false;
}
return true;
}
@@ -37,24 +39,24 @@ module es {
intersection.x = 0;
intersection.y = 0;
let b = Vector2.subtract(a2, a1);
let d = Vector2.subtract(b2, b1);
let bDotDPerp = b.x * d.y - b.y * d.x;
const b = a2.sub(a1);
const d = b2.sub(b1);
const 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;
const c = b1.sub(a1);
const 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;
const u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
return false;
let temp = Vector2.add(a1, new Vector2(t * b.x, t * b.y));
const temp = a1.add(b.scale(t));
intersection.x = temp.x;
intersection.y = temp.y;
@@ -62,24 +64,24 @@ module es {
}
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);
const v = lineB.sub(lineA);
const w = closestTo.sub(lineA);
let t = w.dot(v) / v.dot(v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, new Vector2(v.x * t, v.y * t));
return lineA.add(v.scale(t));
}
public static circleToCircle(circleCenter1: Vector2, circleRadius1: number, circleCenter2: Vector2, circleRadius2: number): boolean {
return Vector2.distanceSquared(circleCenter1, circleCenter2) < (circleRadius1 + circleRadius2) * (circleRadius1 + circleRadius2);
return Vector2.sqrDistance(circleCenter1, circleCenter2) < (circleRadius1 + circleRadius2) * (circleRadius1 + circleRadius2);
}
public static circleToLine(circleCenter: Vector2, radius: number, lineFrom: Vector2, lineTo: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, this.closestPointOnLine(lineFrom, lineTo, circleCenter)) < radius * radius;
return Vector2.sqrDistance(circleCenter, this.closestPointOnLine(lineFrom, lineTo, circleCenter)) < radius * radius;
}
public static circleToPoint(circleCenter: Vector2, radius: number, point: Vector2): boolean {
return Vector2.distanceSquared(circleCenter, point) < radius * radius;
return Vector2.sqrDistance(circleCenter, point) < radius * radius;
}
public static rectToCircle(rect: Rectangle, cPosition: Vector2, cRadius: number): boolean {
@@ -90,30 +92,30 @@ module es {
// 对照相关边缘检查圆圈
let edgeFrom: Vector2;
let edgeTo: Vector2;
let sector = this.getSector(rect.x, rect.y, rect.width, rect.height, cPosition);
const sector = this.getSector(rect.x, rect.y, rect.width, rect.height, cPosition);
if ((sector & PointSectors.top) != 0){
if ((sector & PointSectors.top) !== 0) {
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x + rect.width, rect.y);
if (this.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
return true;
}
if ((sector & PointSectors.bottom) != 0){
if ((sector & PointSectors.bottom) !== 0) {
edgeFrom = new Vector2(rect.x, rect.y + rect.width);
edgeTo = new Vector2(rect.x + rect.width, rect.y + rect.height);
if (this.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
return true;
}
if ((sector & PointSectors.left) != 0){
if ((sector & PointSectors.left) !== 0) {
edgeFrom = new Vector2(rect.x, rect.y);
edgeTo = new Vector2(rect.x, rect.y + rect.height);
if (this.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
return true;
}
if ((sector & PointSectors.right) != 0) {
if ((sector & 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.circleToLine(cPosition, cRadius, edgeFrom, edgeTo))
@@ -124,15 +126,15 @@ module es {
}
public static rectToLine(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);
const fromSector = this.getSector(rect.x, rect.y, rect.width, rect.height, lineFrom);
const 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;
const both = fromSector | toSector;
// 线对边进行检查
let edgeFrom: Vector2;
let edgeTo: Vector2;
+17 -30
View File
@@ -150,23 +150,19 @@ module es {
* @param end
* @param layerMask
*/
public static linecast(start: Vector2, end: Vector2, layerMask: number = Physics.allLayers): RaycastHit{
public static linecast(start: Vector2, end: Vector2, layerMask: number = this.allLayers, ignoredColliders: Set<Collider> = null): RaycastHit {
this._hitArray[0].reset();
this.linecastAll(start, end, this._hitArray, layerMask);
return this._hitArray[0];
}
public static linecastIgnoreCollider(start: Vector2,end: Vector2,layerMask: number = this.allLayers,ignoredColliders: Set<Collider> = null): RaycastHit {
this._hitArray[0].reset();
Physics.linecastAllIgnoreCollider(
start,
end,
this._hitArray,
layerMask,
ignoredColliders
Physics.linecastAll(
start,
end,
this._hitArray,
layerMask,
ignoredColliders
);
return this._hitArray[0].clone();
}
}
/**
* 通过空间散列强制执行一行,并用该行命中的任何碰撞器填充hits数组
@@ -175,24 +171,15 @@ module es {
* @param hits
* @param layerMask
*/
public static linecastAll(start: Vector2, end: Vector2, hits: RaycastHit[], layerMask: number = Physics.allLayers){
if (hits.length == 0){
console.warn("传入了一个空的hits数组。没有点击会被返回");
return 0;
}
return this._spatialHash.linecast(start, end, hits, layerMask);
}
public static linecastAllIgnoreCollider(start: Vector2,end: Vector2,hits: RaycastHit[],layerMask: number = this.allLayers,ignoredColliders: Set<Collider> = null): number {
return this._spatialHash.linecastIgnoreCollider(
start,
end,
hits,
layerMask,
ignoredColliders
public static linecastAll(start: Vector2, end: Vector2, hits: RaycastHit[], layerMask: number = this.allLayers, ignoredColliders: Set<Collider> = null) {
return this._spatialHash.linecast(
start,
end,
hits,
layerMask,
ignoredColliders
);
}
}
/**
* 检查是否有对撞机落在一个矩形区域中
@@ -212,7 +199,7 @@ module es {
* @param layerMask
*/
public static overlapRectangleAll(rect: Rectangle, results: Collider[], layerMask: number = Physics.allLayers) {
if (results.length == 0){
if (results.length == 0) {
console.warn("传入了一个空的结果数组。不会返回任何结果");
return 0;
}
+20 -8
View File
@@ -3,14 +3,26 @@ module es {
* 线(线)线线
*/
export class Ray2D {
public start: Vector2;
public end: Vector2;
public direction: Vector2;
constructor(position: Vector2, end: Vector2){
this.start = position;
this.end = end;
this.direction = Vector2.subtract(this.end, this.start);
public get start(): Vector2 {
return this._start;
}
public get direction(): Vector2 {
return this._direction;
}
public get end(): Vector2 {
return this._end;
}
constructor(pos: Vector2, end: Vector2) {
this._start = pos.clone();
this._end = end.clone();
this._direction = this._end.sub(this._start);
}
private _start: Vector2;
private _direction: Vector2;
private _end: Vector2;
}
}
+2 -9
View File
@@ -38,22 +38,15 @@ module es {
this.centroid = Vector2.zero;
}
public setValues(collider: Collider, fraction: number, distance: number, point: Vector2) {
public setAllValues(collider: Collider, fraction: number, distance: number, point: Vector2, normal: Vector2) {
this.collider = collider;
this.fraction = fraction;
this.distance = distance;
this.point = point;
}
public setValuesNonCollider(fraction: number, distance: number, point: Vector2, normal: Vector2) {
this.fraction = fraction;
this.distance = distance;
this.point = point;
this.normal = normal;
}
public setAllValues(collider: Collider, fraction: number, distance: number, point: Vector2, normal: Vector2) {
this.collider = collider;
public setValues(fraction: number, distance: number, point: Vector2, normal: Vector2) {
this.fraction = fraction;
this.distance = distance;
this.point = point;
+16 -9
View File
@@ -16,20 +16,20 @@ module es {
if (collider.shouldColliderScaleAndRotateWithTransform) {
// 我们只将直线缩放为一个圆,所以我们将使用最大值
let scale = collider.entity.transform.scale;
let hasUnitScale = scale.x == 1 && scale.y == 1;
let maxScale = Math.max(scale.x, scale.y);
const scale = collider.entity.transform.scale;
const hasUnitScale = scale.x === 1 && scale.y === 1;
const maxScale = Math.max(scale.x, scale.y);
this.radius = this._originalRadius * maxScale;
if (collider.entity.transform.rotation != 0) {
if (collider.entity.transform.rotation !== 0) {
// 为了处理偏移原点的旋转,我们只需要将圆心围绕(0,0)在一个圆上移动,我们的偏移量就是0角
let offsetAngle = Math.atan2(collider.localOffset.y, collider.localOffset.x) * MathHelper.Rad2Deg;
let offsetLength = hasUnitScale ? collider._localOffsetLength : Vector2.multiply(collider.localOffset, collider.entity.transform.scale).length();
this.center = MathHelper.pointOnCirlce(Vector2.zero, offsetLength, collider.entity.transform.rotationDegrees + offsetAngle);
const offsetAngle = Math.atan2(collider.localOffset.y, collider.localOffset.x) * MathHelper.Rad2Deg;
const offsetLength = hasUnitScale ? collider._localOffsetLength : collider.localOffset.multiply(collider.entity.transform.scale).magnitude();
this.center = MathHelper.pointOnCirlce(Vector2.zero, offsetLength, collider.entity.transform.rotation + offsetAngle);
}
}
this.position = Vector2.add(collider.entity.transform.position, this.center);
this.position = collider.transform.position.add(this.center);
this.bounds = new Rectangle(this.position.x - this.radius, this.position.y - this.radius, this.radius * 2, this.radius * 2);
}
@@ -67,12 +67,19 @@ module es {
return ShapeCollisionsLine.lineToCircle(start, end, this, hit);
}
public getPointAlongEdge(angle: number): Vector2 {
return new Vector2(
this.position.x + this.radius * Math.cos(angle),
this.position.y + this.radius * Math.sin(angle)
);
}
/**
*
* @param point
*/
public containsPoint(point: Vector2) {
return (Vector2.subtract(point, this.position)).lengthSquared() <= this.radius * this.radius;
return (point.sub(this.position)).lengthSquared() <= this.radius * this.radius;
}
public pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean {
+30 -7
View File
@@ -17,15 +17,39 @@ module es {
*/
public point: Vector2 = Vector2.zero;
public reset() {
this.collider = null;
this.normal.setTo(0, 0);
this.minimumTranslationVector.setTo(0, 0);
if (this.point) {
this.point.setTo(0, 0);
}
}
public cloneTo(cr: CollisionResult) {
cr.collider = this.collider;
cr.normal.setTo(this.normal.x, this.normal.y);
cr.minimumTranslationVector.setTo(
this.minimumTranslationVector.x,
this.minimumTranslationVector.y
);
if (this.point) {
if (!cr.point) {
cr.point = new Vector2(0, 0);
}
cr.point.setTo(this.point.x, this.point.y);
}
}
/**
* x分量
* @param deltaMovement
*/
public removeHorizontal(deltaMovement: Vector2){
public removeHorizontalTranslation(deltaMovement: Vector2){
// 检查是否需要横向移动,如果需要,移除并固定响应
if (Math.sign(this.normal.x) != Math.sign(deltaMovement.x) || (deltaMovement.x == 0 && this.normal.x != 0)){
let responseDistance = this.minimumTranslationVector.length();
let fix = responseDistance / this.normal.y;
if (Math.sign(this.normal.x) !== Math.sign(deltaMovement.x) || (deltaMovement.x === 0 && this.normal.x !== 0)){
const responseDistance = this.minimumTranslationVector.magnitude();
const fix = responseDistance / this.normal.y;
// 检查一些边界情况。因为我们除以法线 使得x == 1和一个非常小的y这将导致一个巨大的固定值
if (Math.abs(this.normal.x) != 1 && Math.abs(fix) < Math.abs(deltaMovement.y * 3)){
@@ -35,9 +59,8 @@ module es {
}
public invertResult() {
this.minimumTranslationVector = Vector2.negate(this.minimumTranslationVector);
this.normal = Vector2.negate(this.normal);
return this;
this.minimumTranslationVector = this.minimumTranslationVector.negate();
this.normal = this.normal.negate();
}
public toString(){
+67 -44
View File
@@ -114,9 +114,9 @@ module es {
* @param points
*/
public static recenterPolygonVerts(points: Vector2[]) {
let center = this.findPolygonCenter(points);
const center = this.findPolygonCenter(points);
for (let i = 0; i < points.length; i++)
points[i] = Vector2.subtract(points[i], center);
points[i] = points[i].sub(center);
}
/**
@@ -139,13 +139,13 @@ module es {
* @param points
* @param direction
*/
public static getFarthestPointInDirection(points: Vector2[], direction: Vector2): Vector2{
public static getFarthestPointInDirection(points: Vector2[], direction: Vector2): Vector2 {
let index = 0;
let maxDot = Vector2.dot(points[index], direction);
let maxDot = points[index].dot(direction);
for (let i = 1; i < points.length; i ++){
let dot = Vector2.dot(points[i], direction);
if (dot > maxDot){
for (let i = 1; i < points.length; i++) {
let dot = points[i].dot(direction);
if (dot > maxDot) {
maxDot = dot;
index = i;
}
@@ -163,35 +163,35 @@ module es {
* @param distanceSquared
* @param edgeNormal
*/
public static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2, distanceSquared: Ref<number>, edgeNormal: Vector2): Vector2 {
distanceSquared.value = Number.MAX_VALUE;
edgeNormal.x = 0;
edgeNormal.y = 0;
let closestPoint = Vector2.zero;
public static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2): { distanceSquared: number; edgeNormal: Vector2; closestPoint: Vector2 } {
const res = {
distanceSquared: Number.MAX_VALUE,
edgeNormal: Vector2.zero,
closestPoint: Vector2.zero,
};
let tempDistanceSquared = 0;
for (let i = 0; i < points.length; i++) {
let j = i + 1;
if (j == points.length)
if (j === points.length)
j = 0;
let closest = ShapeCollisionsCircle.closestPointOnLine(points[i], points[j], point);
tempDistanceSquared = Vector2.distanceSquared(point, closest);
const closest = ShapeCollisionsCircle.closestPointOnLine(points[i], points[j], point);
tempDistanceSquared = Vector2.sqrDistance(point, closest);
if (tempDistanceSquared < distanceSquared.value) {
distanceSquared.value = tempDistanceSquared;
closestPoint = closest;
if (tempDistanceSquared < res.distanceSquared) {
res.distanceSquared = tempDistanceSquared;
res.closestPoint = closest;
// 求直线的法线
let line = Vector2.subtract(points[j], points[i]);
edgeNormal.x = -line.y;
edgeNormal.y = line.x;
const line = points[j].sub(points[i]);
res.edgeNormal.x = line.y;
res.edgeNormal.y = -line.x;
}
}
Vector2Ext.normalize(edgeNormal);
return closestPoint;
res.edgeNormal = res.edgeNormal.normalize();
return res;
}
/**
@@ -200,11 +200,11 @@ module es {
* @param originalPoints
* @param rotatedPoints
*/
public static rotatePolygonVerts(radians: number, originalPoints: Vector2[], rotatedPoints: Vector2[]){
public static rotatePolygonVerts(radians: number, originalPoints: Vector2[], rotatedPoints: Vector2[]) {
let cos = Math.cos(radians);
let sin = Math.sin(radians);
for (let i = 0; i < originalPoints.length; i ++){
for (let i = 0; i < originalPoints.length; i++) {
let position = originalPoints[i];
rotatedPoints[i] = new Vector2(position.x * cos + position.y * -sin, position.x * sin + position.y * cos);
}
@@ -212,40 +212,63 @@ module es {
public recalculateBounds(collider: Collider) {
// 如果我们没有旋转或不关心TRS我们使用localOffset作为中心,我们会从那开始
this.center = collider.localOffset.clone();
this.center = collider.localOffset;
if (collider.shouldColliderScaleAndRotateWithTransform) {
let hasUnitScale = true;
let tempMat: Matrix2D;
let combinedMatrix = Matrix2D.createTranslation(-this._polygonCenter.x, -this._polygonCenter.y);
const tempMat: Matrix2D = new Matrix2D();
const combinedMatrix: Matrix2D = new Matrix2D();
Matrix2D.createTranslation(
this._polygonCenter.x * -1,
this._polygonCenter.y * -1,
combinedMatrix
);
if (!collider.entity.transform.scale.equals(Vector2.one)) {
tempMat = Matrix2D.createScale(collider.entity.transform.scale.x, collider.entity.transform.scale.y);
combinedMatrix = combinedMatrix.multiply(tempMat);
Matrix2D.createScale(
collider.entity.scale.x,
collider.entity.scale.y,
tempMat
);
Matrix2D.multiply(combinedMatrix, tempMat, combinedMatrix);
hasUnitScale = false;
// 缩放偏移量并将其设置为中心。如果我们有旋转,它会在下面重置
this.center = Vector2.multiply(collider.localOffset, collider.entity.transform.scale);
const scaledOffset = new Vector2(
collider.localOffset.x * collider.entity.scale.x,
collider.localOffset.y * collider.entity.scale.y
);
this.center = scaledOffset;
}
if (collider.entity.transform.rotation != 0) {
tempMat = Matrix2D.createRotation(collider.entity.transform.rotation);
combinedMatrix = combinedMatrix.multiply(tempMat);
Matrix2D.createRotation(
MathHelper.Deg2Rad * collider.entity.rotation,
tempMat
);
Matrix2D.multiply(combinedMatrix, tempMat, combinedMatrix);
// 为了处理偏移原点的旋转我们只需要将圆心在(0,0)附近移动
// 我们的偏移使角度为0我们还需要处理这里的比例所以我们先对偏移进行缩放以得到合适的长度。
let offsetAngle = Math.atan2(collider.localOffset.y * collider.entity.transform.scale.y, collider.localOffset.x * collider.entity.transform.scale.x) * MathHelper.Rad2Deg;
let offsetLength = hasUnitScale ? collider._localOffsetLength :
Vector2.multiply(collider.localOffset, collider.entity.transform.scale).length();
const offsetAngle = Math.atan2(collider.localOffset.y * collider.entity.transform.scale.y, collider.localOffset.x * collider.entity.transform.scale.x) * MathHelper.Rad2Deg;
const offsetLength = hasUnitScale ? collider._localOffsetLength :
collider.localOffset.multiply(collider.entity.transform.scale).magnitude();
this.center = MathHelper.pointOnCirlce(Vector2.zero, offsetLength,
collider.entity.transform.rotationDegrees + offsetAngle);
}
tempMat = Matrix2D.createTranslation(this._polygonCenter.x, this._polygonCenter.y);
combinedMatrix = combinedMatrix.multiply(tempMat);
Matrix2D.createTranslation(
this._polygonCenter.x,
this._polygonCenter.y,
tempMat
);
Matrix2D.multiply(combinedMatrix, tempMat, combinedMatrix);
// 最后变换原始点
Vector2Ext.transform(this._originalPoints, combinedMatrix, this.points);
this.points = [];
this._originalPoints.forEach(p => {
this.points.push(p.transform(combinedMatrix));
});
this.isUnrotated = collider.entity.transform.rotation == 0;
@@ -254,9 +277,9 @@ module es {
this._areEdgeNormalsDirty = true;
}
this.position = Vector2.add(collider.entity.transform.position, this.center);
this.position = collider.transform.position.add(this.center);
this.bounds = Rectangle.rectEncompassingPoints(this.points);
this.bounds.location = Vector2.add(this.bounds.location, this.position);
this.bounds.location = this.bounds.location.add(this.position);
}
public overlaps(other: Shape) {
@@ -304,11 +327,11 @@ module es {
*/
public containsPoint(point: Vector2) {
// 将点归一化到多边形坐标空间中
point.sub(this.position);
point = point.sub(this.position);
let isInside = false;
for (let i = 0, j = this.points.length - 1; i < this.points.length; j = i++) {
if (((this.points[i].y > point.y) != (this.points[j].y > point.y)) &&
if (((this.points[i].y > point.y) !== (this.points[j].y > point.y)) &&
(point.x < (this.points[j].x - this.points[i].x) * (point.y - this.points[i].y) / (this.points[j].y - this.points[i].y) +
this.points[i].x)) {
isInside = !isInside;
@@ -1,20 +1,21 @@
module es {
export class RealtimeCollisions {
public static intersectMovingCircleBox(s: Circle, b: Box, movement: Vector2, time: Ref<number>): boolean {
public static intersectMovingCircleBox(s: Circle, b: Box, movement: Vector2, time: number): boolean {
// 计算将b按球面半径r扩大后的AABB
let e = b.bounds.clone();
const e = b.bounds;
e.inflate(s.radius, s.radius);
// 将射线与展开的矩形e相交,如果射线错过了e,则以无交点退出,否则得到交点p和时间t作为结果。
let ray = new Ray2D(Vector2.subtract(s.position, movement), s.position);
if (!e.rayIntersects(ray, time) && time.value > 1)
const ray = new Ray2D(s.position.sub(movement), s.position);
const res = e.rayIntersects(ray);
if (!res.intersected && res.distance > 1)
return false;
// 求交点
let point = Vector2.add(ray.start, Vector2.multiplyScaler(ray.direction, time.value));
const point = ray.start.add(ray.direction.scale(time));
// 计算交点p位于b的哪个最小面和最大面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。
let u, v = 0;
let u: number, v: number = 0;
if (point.x < b.bounds.left)
u |= 1;
if (point.x > b.bounds.right)
@@ -25,7 +26,7 @@ module es {
v |= 2;
// 'or'将所有的比特集合在一起,形成一个比特掩码(注意u + v == u | v)
let m = u + v;
const m = u + v;
// 如果这3个比特都被设置,那么该点就在顶点区域内。
if (m == 3){
@@ -66,8 +67,8 @@ module es {
point = box.bounds.getClosestPointOnRectangleToPoint(cirlce.position);
// 圆和方块相交,如果圆心到点的距离小于圆的半径,则圆和方块相交
let v = Vector2.subtract(point, cirlce.position);
let dist = Vector2.dot(v, v);
const v = point.sub(cirlce.position);
const dist = v.dot(v);
return dist <= cirlce.radius * cirlce.radius;
}
@@ -1,7 +1,7 @@
module es {
export class ShapeCollisionsBox {
public static boxToBox(first: Box, second: Box, result: CollisionResult): boolean {
let minkowskiDiff = this.minkowskiDifference(first, second);
const minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(0, 0)) {
// 计算MTV。如果它是零,我们就可以称它为非碰撞
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
@@ -9,8 +9,8 @@ module es {
if (result.minimumTranslationVector.equals(Vector2.zero))
return false;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
result.normal = result.minimumTranslationVector.scale(-1);
result.normal = result.normal.normalize();
return true;
}
@@ -27,29 +27,29 @@ module es {
*/
public static boxToBoxCast(first: Box, second: Box, movement: Vector2, hit: RaycastHit): boolean {
// 首先,我们检查是否有重叠。如果有重叠,我们就不做扫描测试
let minkowskiDiff = this.minkowskiDifference(first, second);
const minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(0, 0)) {
// 计算MTV。如果它是零,我们就可以称它为非碰撞
let mtv = minkowskiDiff.getClosestPointOnBoundsToOrigin();
const mtv = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (mtv.equals(Vector2.zero))
return false;
hit.normal = new Vector2(-mtv.x, -mtv.y);
hit.normal.normalize();
hit.normal = hit.normal.normalize();
hit.distance = 0;
hit.fraction = 0;
return true;
} else {
// 射线投射移动矢量
let ray = new Ray2D(Vector2.zero, new Vector2(-movement.x, -movement.y));
let fraction = new Ref(0);
if (minkowskiDiff.rayIntersects(ray, fraction) && fraction.value <= 1) {
hit.fraction = fraction.value;
hit.distance = movement.length() * fraction.value;
hit.normal = new Vector2(-movement.x, -movement.y);
hit.normal.normalize();
hit.centroid = Vector2.add(first.bounds.center, Vector2.multiplyScaler(movement, fraction.value));
const ray = new Ray2D(Vector2.zero, movement.scale(-1));
const res = minkowskiDiff.rayIntersects(ray);
if (res.intersected && res.distance <= 1) {
hit.fraction = res.distance;
hit.distance = movement.magnitude() * res.distance;
hit.normal = movement.scale(-1);
hit.normal = hit.normal.normalize();
hit.centroid = first.bounds.center.add(movement.scale(res.distance));
return true;
}
@@ -61,9 +61,9 @@ module es {
private static minkowskiDifference(first: Box, second: Box): Rectangle {
// 我们需要第一个框的左上角
// 碰撞器只会修改运动的位置所以我们需要用位置来计算出运动是什么。
let positionOffset = Vector2.subtract(first.position, Vector2.add(first.bounds.location, new Vector2(first.bounds.size.x / 2, first.bounds.size.y / 2)));
let topLeft = Vector2.subtract(Vector2.add(first.bounds.location, positionOffset), second.bounds.max);
let fullSize = Vector2.add(first.bounds.size, second.bounds.size);
const positionOffset = first.position.sub(first.bounds.center);
const topLeft = first.bounds.location.add(positionOffset.sub(second.bounds.max));
const fullSize = first.bounds.size.add(second.bounds.size);
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y)
}
@@ -1,19 +1,46 @@
module es {
export class ShapeCollisionsCircle {
public static circleToCircle(first: Circle, second: Circle, result: CollisionResult = new CollisionResult()): boolean {
let distanceSquared = Vector2.distanceSquared(first.position, second.position);
let sumOfRadii = first.radius + second.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided) {
result.normal = Vector2.normalize(Vector2.subtract(first.position, second.position));
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = Vector2.multiplyScaler(result.normal, -depth);
result.point = Vector2.add(second.position, Vector2.multiplyScaler(result.normal, second.radius));
public static circleToCircleCast(first: Circle,second: Circle,deltaMovement: Vector2,hit: RaycastHit): boolean {
let endPointOfCast = first.position.add(deltaMovement);
let d = this.closestPointOnLine(first.position,endPointOfCast,second.position);
// 这可以得到实际的碰撞点,可能有用也可能没用,所以我们暂时把它留在这里
// let collisionPointX = ((first.position.x * second.radius) + (second.position.x * first.radius)) / sumOfRadii;
// let collisionPointY = ((first.position.y * second.radius) + (second.position.y * first.radius)) / sumOfRadii;
// result.point = new Vector2(collisionPointX, collisionPointY);
let closestDistanceSquared = Vector2.sqrDistance(second.position, d);
const sumOfRadiiSquared = (first.radius + second.radius) * (first.radius + second.radius);
if (closestDistanceSquared <= sumOfRadiiSquared) {
const normalizedDeltaMovement = deltaMovement.normalize();
if (d === endPointOfCast) {
endPointOfCast = first.position.add(
deltaMovement.add(normalizedDeltaMovement.scale(second.radius))
);
d = this.closestPointOnLine(
first.position,
endPointOfCast,
second.position
);
closestDistanceSquared = Vector2.sqrDistance(second.position, d);
}
const backDist = Math.sqrt(sumOfRadiiSquared - closestDistanceSquared);
hit.centroid = d.sub(normalizedDeltaMovement.scale(backDist));
hit.normal = hit.centroid.sub(second.position).normalize();
hit.fraction = (hit.centroid.x - first.position.x) / deltaMovement.x;
hit.distance = Vector2.distance(first.position, hit.centroid);
hit.point = second.position.add(hit.normal.scale(second.radius));
return true;
}
return false;
}
public static circleToCircle(first: Circle, second: Circle, result: CollisionResult = new CollisionResult()): boolean {
const distanceSquared = Vector2.sqrDistance(first.position, second.position);
const sumOfRadii = first.radius + second.radius;
const collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided) {
result.normal = first.position.sub(second.position).normalize();
const depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = result.normal.scale(-depth);
result.point = second.position.add(result.normal.scale(second.radius));
return true;
}
@@ -28,31 +55,31 @@ module es {
* @param result
*/
public static circleToBox(circle: Circle, box: Box, result: CollisionResult = new CollisionResult()): boolean {
let closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position, result.normal);
const closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position, result.normal);
// 先处理中心在盒子里的圆,如果我们是包含的, 它的成本更低,
if (box.containsPoint(circle.position)) {
result.point = closestPointOnBounds.clone();
result.point = closestPointOnBounds;
// 计算MTV。找出安全的、非碰撞的位置,并从中得到MTV
let safePlace = Vector2.add(closestPointOnBounds, Vector2.multiplyScaler(result.normal, circle.radius));
result.minimumTranslationVector = Vector2.subtract(circle.position, safePlace);
const safePlace = closestPointOnBounds.add(result.normal.scale(circle.radius));
result.minimumTranslationVector = circle.position.sub(safePlace);
return true;
}
let sqrDistance = Vector2.distanceSquared(closestPointOnBounds, circle.position);
const sqrDistance = Vector2.sqrDistance(closestPointOnBounds, circle.position);
// 看框上的点距圆的半径是否小于圆的半径
if (sqrDistance == 0) {
result.minimumTranslationVector = Vector2.multiplyScaler(result.normal, circle.radius);
result.minimumTranslationVector = result.normal.scale(circle.radius);
} else if (sqrDistance <= circle.radius * circle.radius) {
result.normal = Vector2.subtract(circle.position, closestPointOnBounds);
let depth = result.normal.length() - circle.radius;
result.normal = circle.position.sub(closestPointOnBounds);
const depth = result.normal.magnitude() - circle.radius;
result.point = closestPointOnBounds;
Vector2Ext.normalize(result.normal);
result.minimumTranslationVector = Vector2.multiplyScaler(result.normal, depth);
result.normal = result.normal.normalize();
result.minimumTranslationVector = result.normal.scale(depth);
return true;
}
@@ -62,47 +89,47 @@ module es {
public static circleToPolygon(circle: Circle, polygon: Polygon, result: CollisionResult = new CollisionResult()): boolean {
// 圆圈在多边形中的位置坐标
let poly2Circle = Vector2.subtract(circle.position, polygon.position);
const poly2Circle = circle.position.sub(polygon.position);
// 首先,我们需要找到从圆到多边形的最近距离
let distanceSquared = new Ref(0);
let closestPoint = Polygon.getClosestPointOnPolygonToPoint(polygon.points, poly2Circle, distanceSquared, result.normal);
const res = Polygon.getClosestPointOnPolygonToPoint(polygon.points,poly2Circle);
result.normal = res.edgeNormal;
// 确保距离的平方小于半径的平方,否则我们不会相撞。
// 请注意,如果圆完全包含在多边形中,距离可能大于半径。
// 正因为如此,我们还要确保圆的位置不在多边形内。
let circleCenterInsidePoly = polygon.containsPoint(circle.position);
if (distanceSquared.value > circle.radius * circle.radius && !circleCenterInsidePoly)
const circleCenterInsidePoly = polygon.containsPoint(circle.position);
if (res.distanceSquared > circle.radius * circle.radius && !circleCenterInsidePoly)
return false;
// 算出MTV。我们要注意处理完全包含在多边形中的圆或包含其中心的圆
let mtv: Vector2;
if (circleCenterInsidePoly) {
mtv = Vector2.multiply(result.normal, new Vector2(Math.sqrt(distanceSquared.value) - circle.radius));
mtv = result.normal.scale(Math.sqrt(res.distanceSquared) - circle.radius);
} else {
// 如果我们没有距离,这意味着圆心在多边形的边缘上。只需根据它的半径移动它
if (distanceSquared.value == 0) {
mtv = new Vector2(result.normal.x * circle.radius, result.normal.y * circle.radius);
if (res.distanceSquared === 0) {
mtv = result.normal.scale(circle.radius);
} else {
let distance = Math.sqrt(distanceSquared.value);
mtv = Vector2.multiplyScaler(Vector2.subtract(poly2Circle, closestPoint), -1)
.multiply(new Vector2((circle.radius - distance) / distance));
const distance = Math.sqrt(res.distanceSquared);
mtv = poly2Circle
.sub(res.closestPoint)
.scale(((circle.radius - distance) / distance) * -1);
}
}
result.minimumTranslationVector = mtv;
result.point = Vector2.add(closestPoint, polygon.position);
result.point = res.closestPoint.add(polygon.position);
return true;
}
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2): Vector2 {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
let t = Vector2.dot(w, v) / Vector2.dot(v, v);
const v = lineB.sub(lineA);
const w = closestTo.sub(lineA);
let t = w.dot(v) / v.dot(v);
t = MathHelper.clamp(t, 0, 1);
return Vector2.add(lineA, Vector2.multiplyScaler(v, t));
return lineA.add(v.scaleEqual(t));
}
}
}
@@ -7,10 +7,10 @@ module es {
let hasIntersection = false;
for (let j = polygon.points.length - 1, i = 0; i < polygon.points.length; j = i, i ++){
let edge1 = Vector2.add(polygon.position, polygon.points[j]);
let edge2 = Vector2.add(polygon.position, polygon.points[i]);
let intersection: Vector2 = Vector2.zero;
if (this.lineToLine(edge1, edge2, start, end, intersection)){
const edge1 = Vector2.add(polygon.position, polygon.points[j]);
const edge2 = Vector2.add(polygon.position, polygon.points[i]);
const intersection: Vector2 = Vector2.zero;
if (ShapeCollisionsLine.lineToLine(edge1, edge2, start, end, intersection)){
hasIntersection = true;
// TODO: 这是得到分数的正确和最有效的方法吗?
@@ -20,7 +20,7 @@ module es {
distanceFraction = (intersection.y - start.y) / (end.y - start.y);
if (distanceFraction < fraction){
let edge = Vector2.subtract(edge2, edge1);
const edge = edge2.sub(edge1);
normal = new Vector2(edge.y, -edge.x);
fraction = distanceFraction;
intersectionPoint = intersection;
@@ -29,9 +29,9 @@ module es {
}
if (hasIntersection){
normal.normalize();
let distance = Vector2.distance(start, intersectionPoint);
hit.setValuesNonCollider(fraction, distance, intersectionPoint, normal);
normal = normal.normalize();
const distance = Vector2.distance(start, intersectionPoint);
hit.setValues(fraction, distance, intersectionPoint, normal);
return true;
}
@@ -39,24 +39,24 @@ module es {
}
public static lineToLine(a1: Vector2, a2: Vector2, b1: Vector2, b2: Vector2, intersection: Vector2){
let b = Vector2.subtract(a2, a1);
let d = Vector2.subtract(b2, b1);
let bDotDPerp = b.x * d.y - b.y * d.x;
const b = a2.sub(a1);
const d = b2.sub(b1);
const 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;
const c = b1.sub(a1);
const 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;
const u = (c.x * b.y - c.y * b.x) / bDotDPerp;
if (u < 0 || u > 1)
return false;
let r = Vector2.add(a1, Vector2.multiplyScaler(b, t));
const r = a1.add(b.scale(t));
intersection.x = r.x;
intersection.y = r.y;
@@ -65,11 +65,11 @@ module es {
public static lineToCircle(start: Vector2, end: Vector2, s: Circle, hit: RaycastHit): boolean{
// 计算这里的长度并分别对d进行标准化,因为如果我们命中了我们需要它来得到分数
let lineLength = Vector2.distance(start, end);
let d = Vector2.divideScaler(Vector2.subtract(end, start), lineLength);
let m = Vector2.subtract(start, s.position);
let b = Vector2.dot(m, d);
let c = Vector2.dot(m, m) - s.radius * s.radius;
const lineLength = Vector2.distance(start, end);
const d = Vector2.divideScaler(end.sub(start), lineLength);
const m = start.sub(s.position);
const b = m.dot(d);
const c = m.dot(m) - s.radius * s.radius;
// 如果r的原点在s之外,(c>0)和r指向s (b>0) 则返回
if (c > 0 && b > 0)
@@ -87,9 +87,9 @@ module es {
if (hit.fraction < 0)
hit.fraction = 0;
hit.point = Vector2.add(start, Vector2.multiplyScaler(d, hit.fraction));
hit.point = start.add(d.scale(hit.fraction));
hit.distance = Vector2.distance(start, hit.point);
hit.normal = Vector2.normalize(Vector2.subtract(hit.point, s.position));
hit.normal = hit.point.sub(s.position).normalize();
hit.fraction = hit.distance / lineLength;
return true;
@@ -1,14 +1,14 @@
module es {
export class ShapeCollisionsPoint {
public static pointToCircle(point: Vector2, circle: Circle, result: CollisionResult): boolean {
let distanceSquared = Vector2.distanceSquared(point, circle.position);
let distanceSquared = Vector2.sqrDistance(point, circle.position);
let sumOfRadii = 1 + circle.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided) {
result.normal = Vector2.normalize(Vector2.subtract(point, circle.position));
result.normal = point.sub(circle.position).normalize();
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = Vector2.multiplyScaler(result.normal, -depth);
result.point = Vector2.add(circle.position, Vector2.multiplyScaler(result.normal, circle.radius));
result.minimumTranslationVector = result.normal.scale(-depth);;
result.point = circle.position.add(result.normal.scale(circle.radius));
return true;
}
@@ -16,11 +16,11 @@ module es {
return false;
}
public static pointToBox(point: Vector2, box: Box, result: CollisionResult = new CollisionResult()){
if (box.containsPoint(point)){
public static pointToBox(point: Vector2, box: Box, result: CollisionResult = new CollisionResult()) {
if (box.containsPoint(point)) {
// 在方框的空间里找到点
result.point = box.bounds.getClosestPointOnRectangleBorderToPoint(point, result.normal);
result.minimumTranslationVector = Vector2.subtract(point, result.point);
result.minimumTranslationVector = point.sub(result.point);
return true;
}
@@ -30,12 +30,15 @@ module es {
public static pointToPoly(point: Vector2, poly: Polygon, result: CollisionResult = new CollisionResult()): boolean {
if (poly.containsPoint(point)) {
let distanceSquared = new Ref(0);
let closestPoint = Polygon.getClosestPointOnPolygonToPoint(poly.points, Vector2.subtract(point, poly.position), distanceSquared, result.normal);
result.minimumTranslationVector = new Vector2(result.normal.x * Math.sqrt(distanceSquared.value), result.normal.y * Math.sqrt(distanceSquared.value));
result.point = Vector2.add(closestPoint, poly.position);
const res = Polygon.getClosestPointOnPolygonToPoint(
poly.points,
point.sub(poly.position)
);
result.normal = res.edgeNormal;
result.minimumTranslationVector = result.normal.scale(
Math.sqrt(res.distanceSquared)
);
result.point = res.closestPoint.sub(poly.position);
return true;
}
@@ -12,8 +12,8 @@ module es {
const firstEdges = first.edgeNormals;
const secondEdges = second.edgeNormals;
let minIntervalDistance = Number.POSITIVE_INFINITY;
let translationAxis = es.Vector2.zero;
let polygonOffset = Vector2.subtract(first.position, second.position);
let translationAxis = Vector2.zero;
let polygonOffset = first.position.sub(second.position);
let axis: Vector2;
// 循环穿过两个多边形的所有边
@@ -28,7 +28,7 @@ module es {
const {min: minB, max: maxB} = this.getInterval(axis, second);
// 将区间设为第二个多边形的空间。由轴上投影的位置差偏移。
let relativeIntervalOffset = Vector2.dot(polygonOffset, axis);
const relativeIntervalOffset = polygonOffset.dot(axis);
minA += relativeIntervalOffset;
maxA += relativeIntervalOffset;
@@ -50,14 +50,14 @@ module es {
minIntervalDistance = intervalDist;
translationAxis.setTo(axis.x, axis.y);
if (Vector2.dot(translationAxis, polygonOffset) < 0)
if (translationAxis.dot(polygonOffset) < 0)
translationAxis = translationAxis.scale(-1);
}
}
// 利用最小平移向量对多边形进行推入。
result.normal = translationAxis;
result.minimumTranslationVector = translationAxis.scale(minIntervalDistance * -1);
result.minimumTranslationVector = translationAxis.scale(-minIntervalDistance);
return true;
}
@@ -72,11 +72,11 @@ module es {
public static getInterval(axis: Vector2, polygon: Polygon): {min: number, max: number} {
const res = {min: 0, max: 0};
let dot: number;
dot = Vector2.dot( polygon.points[0], axis);
dot = polygon.points[0].dot(axis);
res.max = dot;
res.min = dot;
for (let i = 1; i < polygon.points.length; i++) {
dot = Vector2.dot(polygon.points[i], axis);
dot = polygon.points[i].dot(axis);
if (dot < res.min) {
res.min = dot;
} else if (dot > res.max) {
+22 -81
View File
@@ -118,12 +118,12 @@ module es {
public aabbBroadphase(bounds: Rectangle, excludeCollider: Collider, layerMask: number): Collider[] {
this._tempHashSet.clear();
let p1 = this.cellCoords(bounds.x, bounds.y);
let p2 = this.cellCoords(bounds.right, bounds.bottom);
const p1 = this.cellCoords(bounds.x, bounds.y);
const p2 = this.cellCoords(bounds.right, bounds.bottom);
for (let x = p1.x; x <= p2.x; x++) {
for (let y = p1.y; y <= p2.y; y++) {
let cell = this.cellAtPosition(x, y);
const cell = this.cellAtPosition(x, y);
if (!cell)
continue;
@@ -154,9 +154,9 @@ module es {
* @param hits
* @param layerMask
*/
public linecast(start: Vector2, end: Vector2, hits: RaycastHit[], layerMask: number) {
public linecast(start: Vector2, end: Vector2, hits: RaycastHit[], layerMask: number, ignoredColliders: Set<Collider>) {
let ray = new Ray2D(start, end);
this._raycastParser.start(ray, hits, layerMask);
this._raycastParser.start(ray, hits, layerMask, ignoredColliders);
// 获取我们的起始/结束位置,与我们的网格在同一空间内
let currentCell = this.cellCoords(start.x, start.y);
@@ -217,67 +217,6 @@ module es {
return this._raycastParser.hitCounter;
}
public linecastIgnoreCollider(start: Vector2, end: Vector2, hits: RaycastHit[], layerMask: number, ignoredColliders: Set<Collider>): number {
start = start.clone();
const ray = new Ray2D(start, end);
this._raycastParser.startIgnoreCollider(ray, hits, layerMask, ignoredColliders);
start.x = start.x * this._inverseCellSize;
start.y = start.y * this._inverseCellSize;
const endCell = this.cellCoords(end.x, end.y);
let intX = Math.floor(start.x);
let intY = Math.floor(start.y);
let stepX = Math.sign(ray.direction.x);
let stepY = Math.sign(ray.direction.y);
if (intX === endCell.x) {
stepX = 0;
}
if (intY === endCell.y) {
stepY = 0;
}
const boundaryX = intX + (stepX > 0 ? 1 : 0);
const boundaryY = intY + (stepY > 0 ? 1 : 0);
let tMaxX = (boundaryX - start.x) / ray.direction.x;
let tMaxY = (boundaryY - start.y) / ray.direction.y;
if (ray.direction.x === 0 || stepX === 0) {
tMaxX = Number.POSITIVE_INFINITY;
}
if (ray.direction.y === 0 || stepY === 0) {
tMaxY = Number.POSITIVE_INFINITY;
}
const tDeltaX = stepX / ray.direction.x;
const tDeltaY = stepY / ray.direction.y;
let cell = this.cellAtPosition(intX, intY);
if (cell && this._raycastParser.checkRayIntersection(intX, intY, cell)) {
this._raycastParser.reset();
return this._raycastParser.hitCounter;
}
let n = 0;
while ((intX !== endCell.x || intY !== endCell.y) && n < 100) {
if (tMaxX < tMaxY) {
intX = intX + stepX;
tMaxX = tMaxX + tDeltaX;
} else {
intY = intY + stepY;
tMaxY = tMaxY + tDeltaY;
}
cell = this.cellAtPosition(intX, intY);
if (cell && this._raycastParser.checkRayIntersection(intX, intY, cell)) {
this._raycastParser.reset();
return this._raycastParser.hitCounter;
}
n++;
}
this._raycastParser.reset();
return this._raycastParser.hitCounter;
}
/**
*
@@ -425,7 +364,11 @@ module es {
export class RaycastResultParser {
public hitCounter: number;
public static compareRaycastHits = (a: RaycastHit, b: RaycastHit) => {
return a.distance - b.distance;
if (a.distance !== b.distance) {
return a.distance - b.distance;
} else {
return a.collider.castSortOrder - b.collider.castSortOrder;
}
};
public _hits: RaycastHit[];
@@ -436,14 +379,7 @@ module es {
public _layerMask: number;
private _ignoredColliders: Set<Collider>;
public start(ray: Ray2D, hits: RaycastHit[], layerMask: number) {
this._ray = ray;
this._hits = hits;
this._layerMask = layerMask;
this.hitCounter = 0;
}
public startIgnoreCollider(ray: Ray2D, hits: RaycastHit[], layerMask: number, ignoredColliders: Set<Collider>) {
public start(ray: Ray2D, hits: RaycastHit[], layerMask: number, ignoredColliders: Set<Collider>) {
this._ray = ray;
this._hits = hits;
this._layerMask = layerMask;
@@ -458,9 +394,8 @@ module es {
* @param cell
*/
public checkRayIntersection(cellX: number, cellY: number, cell: Collider[]): boolean {
let fraction: Ref<number> = new Ref(0);
for (let i = 0; i < cell.length; i++) {
let potential = cell[i];
const potential = cell[i];
// 管理我们已经处理过的碰撞器
if (new es.List(this._checkedColliders).contains(potential))
@@ -475,11 +410,16 @@ module es {
if (!Flags.isFlagSet(this._layerMask, potential.physicsLayer.value))
continue;
if (this._ignoredColliders && this._ignoredColliders.has(potential)) {
continue;
}
// TODO: rayIntersects的性能够吗?需要测试它。Collisions.rectToLine可能更快
// TODO: 如果边界检查返回更多数据,我们就不需要为BoxCollider检查做任何事情
// 在做形状测试之前先做一个边界检查
let colliderBounds = potential.bounds.clone();
if (colliderBounds.rayIntersects(this._ray, fraction) && fraction.value <= 1) {
const colliderBounds = potential.bounds;
const res = colliderBounds.rayIntersects(this._ray);
if (res.intersected && res.distance <= 1) {
if (potential.shape.collidesWithLine(this._ray.start, this._ray.end, this._tempHit)) {
// 检查一下,我们应该排除这些射线,射线cast是否在碰撞器中开始
if (!Physics.raycastsStartInColliders && potential.shape.containsPoint(this._ray.start))
@@ -493,7 +433,7 @@ module es {
}
}
if (this._cellHits.length == 0)
if (this._cellHits.length === 0)
return false;
// 所有处理单元完成。对结果进行排序并将命中结果打包到结果数组中
@@ -503,7 +443,7 @@ module es {
// 增加命中计数器,如果它已经达到数组大小的限制,我们就完成了
this.hitCounter++;
if (this.hitCounter == this._hits.length)
if (this.hitCounter === this._hits.length)
return true;
}
@@ -514,6 +454,7 @@ module es {
this._hits = null;
this._checkedColliders.length = 0;
this._cellHits.length = 0;
this._ignoredColliders = null;
}
}
}
+4 -4
View File
@@ -7,7 +7,7 @@ module es {
* @param c
*/
public static isTriangleCCW(a: Vector2, center: Vector2, c: Vector2) {
return this.cross(Vector2.subtract(center, a), Vector2.subtract(c, center)) < 0;
return this.cross(center.sub(a), c.sub(center)) < 0;
}
public static halfVector(): Vector2 {
@@ -48,7 +48,7 @@ module es {
public static angle(from: Vector2, to: Vector2) {
this.normalize(from);
this.normalize(to);
return Math.acos(MathHelper.clamp(Vector2.dot(from, to), -1, 1)) * MathHelper.Rad2Deg;
return Math.acos(MathHelper.clamp(from.dot(to), -1, 1)) * MathHelper.Rad2Deg;
}
/**
@@ -58,8 +58,8 @@ module es {
* @param right
*/
public static angleBetween(self: Vector2, left: Vector2, right: Vector2) {
let one = Vector2.subtract(left, self);
let two = Vector2.subtract(right, self);
const one = left.sub(self);
const two = right.sub(self);
return this.angle(one, two);
}
@@ -63,7 +63,7 @@ module es {
* @param radius
*/
public addCircleOccluder(position: Vector2, radius: number){
let dirToCircle = Vector2.subtract(position, this._origin);
let dirToCircle = position.sub(this._origin);
let angle = Math.atan2(dirToCircle.y, dirToCircle.x);
let stepSize = Math.PI / this.lineCountForCircleApproximation;
+3 -3
View File
@@ -13,15 +13,15 @@ module es {
public static testPointTriangle(point: Vector2, a: Vector2, b: Vector2, c: Vector2): boolean {
// 如果点在AB的右边,那么外边的三角形是
if (Vector2Ext.cross(Vector2.subtract(point, a), Vector2.subtract(b, a)) < 0)
if (Vector2Ext.cross(point.sub(a), b.sub(a)) < 0)
return false;
// 如果点在BC的右边,则在三角形的外侧
if (Vector2Ext.cross(Vector2.subtract(point, b), Vector2.subtract(c, b)) < 0)
if (Vector2Ext.cross(point.sub(b), c.sub(b)) < 0)
return false;
// 如果点在ca的右边,则在三角形的外面
if (Vector2Ext.cross(Vector2.subtract(point, c), Vector2.subtract(a, c)) < 0)
if (Vector2Ext.cross(point.sub(c), a.sub(c)) < 0)
return false;
// 点在三角形上