新增Out类

This commit is contained in:
YHH
2022-03-12 10:23:33 +08:00
parent 5dca337b92
commit ffddadd798
20 changed files with 371 additions and 304 deletions

View File

@@ -153,8 +153,6 @@ module es {
this.velocity.addEqual(Physics.gravity.scale(Time.deltaTime));
this.entity.position = this.entity.position.add(this.velocity.scale(Time.deltaTime));
let collisionResult = new CollisionResult();
// 捞取我们在新的位置上可能会碰撞到的任何东西
let neighbors = Physics.boxcastBroadphaseExcludingSelf(this._collider, this._collider.bounds, this._collider.collidesWithLayers.value);
if (neighbors.length > 0) {
@@ -168,16 +166,17 @@ module es {
continue;
}
const collisionResult = new Out<CollisionResult>();
if (this._collider.collidesWithNonMotion(neighbor, collisionResult)) {
// 如果附近有一个ArcadeRigidbody我们就会处理完整的碰撞响应。如果没有我们会根据附近是不可移动的来计算事情
let neighborRigidbody = neighbor.entity.getComponent(ArcadeRigidbody);
if (neighborRigidbody != null) {
this.processOverlap(neighborRigidbody, collisionResult.minimumTranslationVector);
this.processCollision(neighborRigidbody, collisionResult.minimumTranslationVector);
this.processOverlap(neighborRigidbody, collisionResult.value.minimumTranslationVector);
this.processCollision(neighborRigidbody, collisionResult.value.minimumTranslationVector);
} else {
// 没有ArcadeRigidbody所以我们假设它是不动的只移动我们自己的
this.entity.position = this.entity.position.sub(collisionResult.minimumTranslationVector);
const relativeVelocity = this.calculateResponseVelocity(this.velocity, collisionResult.minimumTranslationVector);
this.entity.position = this.entity.position.sub(collisionResult.value.minimumTranslationVector);
const relativeVelocity = this.calculateResponseVelocity(this.velocity, collisionResult.value.minimumTranslationVector);
this.velocity.addEqual(relativeVelocity);
}
}

View File

@@ -184,14 +184,14 @@ module es {
* @param motion
* @param result
*/
public collidesWith(collider: Collider, motion: Vector2, result: CollisionResult = new CollisionResult()): boolean {
public collidesWith(collider: Collider, motion: Vector2, result: Out<CollisionResult>): boolean {
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
const oldPosition = this.entity.position;
this.entity.position = this.entity.position.add(motion);
const didCollide = this.shape.collidesWithShape(collider.shape, result);
if (didCollide)
result.collider = collider;
result.value.collider = collider;
// 将图形位置返回到检查前的位置
this.entity.position = oldPosition;
@@ -204,13 +204,13 @@ module es {
* @param collider
* @param result
*/
public collidesWithNonMotion(collider: Collider, result: CollisionResult = new CollisionResult()): boolean {
public collidesWithNonMotion(collider: Collider, result: Out<CollisionResult>): boolean {
if (this.shape.collidesWithShape(collider.shape, result)) {
result.collider = collider;
result.value.collider = collider;
return true;
}
result.collider = null;
result.value.collider = null;
return false;
}
@@ -220,7 +220,9 @@ module es {
* @param motion
* @param result
*/
public collidesWithAny(motion: Vector2, result: CollisionResult) {
public collidesWithAny(motion: Vector2, result: Out<CollisionResult>) {
result.value = new CollisionResult();
// 在我们的新位置上获取我们可能会碰到的任何东西
let colliderBounds = this.bounds.clone();
colliderBounds.x += motion.x;
@@ -232,17 +234,15 @@ module es {
this.shape.position = Vector2.add(this.shape.position, motion);
let didCollide = false;
if (neighbors.length > 0) {
for (let i = 0; i < neighbors.length; i ++ ){
const neighbor = neighbors[i];
if (neighbor.isTrigger)
continue;
if (this.collidesWithNonMotion(neighbor, result)) {
motion = motion.sub(result.minimumTranslationVector);
this.shape.position = this.shape.position.sub(result.minimumTranslationVector);
didCollide = true;
}
for (let i = 0; i < neighbors.length; i ++ ){
const neighbor = neighbors[i];
if (neighbor.isTrigger)
continue;
if (this.collidesWithNonMotion(neighbor, result)) {
motion = motion.sub(result.value.minimumTranslationVector);
this.shape.position = this.shape.position.sub(result.value.minimumTranslationVector);
didCollide = true;
}
}
@@ -256,7 +256,8 @@ module es {
* 检查此碰撞器是否与场景中的其他碰撞器碰撞。它相交的第一个碰撞器将在碰撞结果中返回碰撞数据。
* @param result
*/
public collidesWithAnyNonMotion(result: CollisionResult = new CollisionResult()) {
public collidesWithAnyNonMotion(result: Out<CollisionResult>) {
result.value = new CollisionResult();
// 在我们的新位置上获取我们可能会碰到的任何东西
let neighbors = Physics.boxcastBroadphaseExcludingSelfNonRect(this, this.collidesWithLayers.value);

View File

@@ -18,7 +18,9 @@ module es {
* @param motion
* @param collisionResult
*/
public calculateMovement(motion: Vector2, collisionResult: CollisionResult): boolean {
public calculateMovement(motion: Vector2, collisionResult: Out<CollisionResult>): boolean {
collisionResult.value = new CollisionResult();
let collider = null;
if (this.entity.components.buffer.length > 0)
for (let i = 0; i < this.entity.components.buffer.length; i++) {
@@ -65,16 +67,16 @@ module es {
if (neighbor.isTrigger)
return;
let _internalcollisionResult: CollisionResult = new CollisionResult();
let _internalcollisionResult = new Out<CollisionResult>();
if (collider.collidesWith(neighbor, motion, _internalcollisionResult)) {
// 如果碰撞 则退回之前的移动量
motion.subEqual(_internalcollisionResult.minimumTranslationVector);
motion.subEqual(_internalcollisionResult.value.minimumTranslationVector);
// 如果我们碰到多个对象,为了简单起见,只取第一个。
if (_internalcollisionResult.collider != null) {
collisionResult.collider = _internalcollisionResult.collider;
collisionResult.minimumTranslationVector = _internalcollisionResult.minimumTranslationVector;
collisionResult.normal = _internalcollisionResult.normal;
collisionResult.point = _internalcollisionResult.point;
if (_internalcollisionResult.value.collider != null) {
collisionResult.value.collider = _internalcollisionResult.value.collider;
collisionResult.value.minimumTranslationVector = _internalcollisionResult.value.minimumTranslationVector;
collisionResult.value.normal = _internalcollisionResult.value.normal;
collisionResult.value.point = _internalcollisionResult.value.point;
}
}
}
@@ -83,7 +85,7 @@ module es {
}
ListPool.free(Collider, colliders);
return collisionResult.collider != null;
return collisionResult.value.collider != null;
}
/**
@@ -104,10 +106,10 @@ module es {
* @param motion
* @param collisionResult
*/
public move(motion: Vector2, collisionResult: CollisionResult) {
public move(motion: Vector2, collisionResult: Out<CollisionResult>) {
this.calculateMovement(motion, collisionResult);
this.applyMovement(motion);
return collisionResult.collider != null;
return collisionResult.value.collider != null;
}
}
}

View File

@@ -53,7 +53,7 @@ module es {
*/
public static checkEvery(interval: number) {
// 我们减去了delta因为timeSinceSceneLoad已经包含了这个update ticks delta
return this.timeSinceSceneLoad / interval > (this.timeSinceSceneLoad - this.deltaTime) / interval;
return MathHelper.toInt(this.timeSinceSceneLoad / interval) > MathHelper.toInt((this.timeSinceSceneLoad - this.deltaTime) / interval);
}
}
}

View File

@@ -318,9 +318,10 @@ module es {
* @param edgeNormal
* @returns 矩形边框上离点最近的点
*/
public getClosestPointOnRectangleBorderToPoint(point: Vector2, edgeNormal: Vector2): Vector2 {
public getClosestPointOnRectangleBorderToPoint(point: Vector2, edgeNormal: Out<Vector2>): Vector2 {
edgeNormal.value = Vector2.zero;
// 对于每条轴,如果点在框外,就把它限制在框内,否则就不要管它
let res = es.Vector2.zero;
const res = Vector2.zero;
res.x = MathHelper.clamp(point.x, this.left, this.right);
res.y = MathHelper.clamp(point.y, this.top, this.bottom);
@@ -334,22 +335,22 @@ module es {
let min = Math.min(dl, dr, dt, db);
if (min == dt) {
res.y = this.top;
edgeNormal.y = -1;
edgeNormal.value.y = -1;
} else if (min == db) {
res.y = this.bottom;
edgeNormal.y = 1;
edgeNormal.value.y = 1;
} else if (min == dl) {
res.x = this.left;
edgeNormal.x = -1;
edgeNormal.value.x = -1;
} else {
res.x = this.right;
edgeNormal.x = 1;
edgeNormal.value.x = 1;
}
} else {
if (res.x == this.left) edgeNormal.x = -1;
if (res.x == this.right) edgeNormal.x = 1;
if (res.y == this.top) edgeNormal.y = -1;
if (res.y == this.bottom) edgeNormal.y = 1;
if (res.x == this.left) edgeNormal.value.x = -1;
if (res.x == this.right) edgeNormal.value.x = 1;
if (res.y == this.top) edgeNormal.value.y = -1;
if (res.y == this.bottom) edgeNormal.value.y = 1;
}
return res;

View File

@@ -66,7 +66,7 @@ module es {
return super.overlaps(other);
}
public collidesWithShape(other: Shape, result: CollisionResult): boolean {
public collidesWithShape(other: Shape, result: Out<CollisionResult>): boolean {
// 特殊情况这一个高性能方式实现其他情况则使用polygon方法检测
if (other instanceof Box && (other as Box).isUnrotated) {
return ShapeCollisionsBox.boxToBox(this, other, result);
@@ -84,7 +84,7 @@ module es {
return super.containsPoint(point);
}
public pointCollidesWithShape(point: es.Vector2, result: es.CollisionResult): boolean {
public pointCollidesWithShape(point: Vector2, result: Out<CollisionResult>): boolean {
if (this.isUnrotated)
return ShapeCollisionsPoint.pointToBox(point, this, result);

View File

@@ -34,7 +34,7 @@ module es {
}
public overlaps(other: Shape) {
let result: CollisionResult = new CollisionResult();
const result = new Out<CollisionResult>();
if (other instanceof Box && (other as Box).isUnrotated)
return Collisions.rectToCircle(other.bounds, this.position, this.radius);
@@ -47,7 +47,7 @@ module es {
throw new Error(`overlaps of circle to ${other} are not supported`);
}
public collidesWithShape(other: Shape, result: CollisionResult): boolean {
public collidesWithShape(other: Shape, result: Out<CollisionResult>): boolean {
if (other instanceof Box && (other as Box).isUnrotated) {
return ShapeCollisionsCircle.circleToBox(this, other, result);
}
@@ -63,7 +63,7 @@ module es {
throw new Error(`Collisions of Circle to ${other} are not supported`);
}
public collidesWithLine(start: Vector2, end: Vector2, hit: RaycastHit): boolean {
public collidesWithLine(start: Vector2, end: Vector2, hit: Out<RaycastHit>): boolean {
return ShapeCollisionsLine.lineToCircle(start, end, this, hit);
}
@@ -82,7 +82,7 @@ module es {
return (point.sub(this.position)).lengthSquared() <= this.radius * this.radius;
}
public pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean {
public pointCollidesWithShape(point: Vector2, result: Out<CollisionResult>): boolean {
return ShapeCollisionsPoint.pointToCircle(point, this, result);
}
}

View File

@@ -287,13 +287,13 @@ module es {
}
public overlaps(other: Shape) {
let result: CollisionResult = new CollisionResult();
let result = new Out<CollisionResult>();
if (other instanceof Polygon)
return ShapeCollisionsPolygon.polygonToPolygon(this, other, result);
if (other instanceof Circle) {
if (ShapeCollisionsCircle.circleToPolygon(other, this, result)) {
result.invertResult();
result.value.invertResult();
return true;
}
@@ -303,14 +303,14 @@ module es {
throw new Error(`overlaps of Pologon to ${other} are not supported`);
}
public collidesWithShape(other: Shape, result: CollisionResult): boolean {
public collidesWithShape(other: Shape, result: Out<CollisionResult>): boolean {
if (other instanceof Polygon) {
return ShapeCollisionsPolygon.polygonToPolygon(this, other, result);
}
if (other instanceof Circle) {
if (ShapeCollisionsCircle.circleToPolygon(other, this, result)) {
result.invertResult();
result.value.invertResult();
return true;
}
@@ -320,7 +320,7 @@ module es {
throw new Error(`overlaps of Polygon to ${other} are not supported`);
}
public collidesWithLine(start: es.Vector2, end: es.Vector2, hit: es.RaycastHit): boolean {
public collidesWithLine(start: Vector2, end: Vector2, hit: Out<RaycastHit>): boolean {
return ShapeCollisionsLine.lineToPoly(start, end, this, hit);
}
@@ -345,7 +345,7 @@ module es {
return isInside;
}
public pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean {
public pointCollidesWithShape(point: Vector2, result: Out<CollisionResult>): boolean {
return ShapeCollisionsPoint.pointToPoly(point, this, result);
}
}

View File

@@ -19,12 +19,12 @@ module es {
public abstract overlaps(other: Shape): boolean;
public abstract collidesWithShape(other: Shape, collisionResult: CollisionResult): boolean;
public abstract collidesWithShape(other: Shape, collisionResult: Out<CollisionResult>): boolean;
public abstract collidesWithLine(start: Vector2, end: Vector2, hit: RaycastHit): boolean;
public abstract collidesWithLine(start: Vector2, end: Vector2, hit: Out<RaycastHit>): boolean;
public abstract containsPoint(point: Vector2);
public abstract pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean;
public abstract pointCollidesWithShape(point: Vector2, result: Out<CollisionResult>): boolean;
}
}

View File

@@ -1,16 +1,18 @@
module es {
export class ShapeCollisionsBox {
public static boxToBox(first: Box, second: Box, result: CollisionResult): boolean {
public static boxToBox(first: Box, second: Box, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
const minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(0, 0)) {
// 计算MTV。如果它是零我们就可以称它为非碰撞
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
result.value.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector.equals(Vector2.zero))
if (result.value.minimumTranslationVector.equals(Vector2.zero))
return false;
result.normal = result.minimumTranslationVector.scale(-1);
result.normal = result.normal.normalize();
result.value.normal = result.value.minimumTranslationVector.scale(-1);
result.value.normal = result.value.normal.normalize();
return true;
}

View File

@@ -1,46 +1,51 @@
module es {
export class ShapeCollisionsCircle {
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);
public static circleToCircleCast(first: Circle, second: Circle, deltaMovement: Vector2, hit: Out<RaycastHit>): boolean {
hit.value = new RaycastHit();
// 在动圆的运动矢量上找到离圆中心最近的点(第一个)
let endPointOfCast = first.position.add(deltaMovement);
let d = this.closestPointOnLine(first.position, endPointOfCast, second.position);
// 然后求最近点到圆心的距离
let closestDistanceSquared = Vector2.sqrDistance(second.position, d);
const sumOfRadiiSquared = (first.radius + second.radius) * (first.radius + second.radius);
// 如果它小于半径之和,则发生碰撞
if (closestDistanceSquared <= sumOfRadiiSquared) {
const normalizedDeltaMovement = deltaMovement.normalize();
// 边缘情况:如果端点等于线上最近的点,那么从它到 second.position 的线将不垂直于射线
if (d === endPointOfCast) {
endPointOfCast = first.position.add(
deltaMovement.add(normalizedDeltaMovement.scale(second.radius))
);
d = this.closestPointOnLine(
first.position,
endPointOfCast,
second.position
);
// 延长投射半径距离的终点,因此我们得到一个垂直的点
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));
hit.value.centroid = d.sub(normalizedDeltaMovement.scale(backDist));
hit.value.normal = hit.value.centroid.sub(second.position).normalize();
hit.value.fraction = (hit.value.centroid.x - first.position.x) / deltaMovement.x;
hit.value.distance = Vector2.distance(first.position, hit.value.centroid);
hit.value.point = second.position.add(hit.value.normal.scale(second.radius));
return true;
}
return false;
}
}
public static circleToCircle(first: Circle, second: Circle, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
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();
result.value.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));
result.value.minimumTranslationVector = result.value.normal.scale(-depth);
result.value.point = second.position.add(result.value.normal.scale(second.radius));
return true;
}
@@ -54,32 +59,35 @@ module es {
* @param box
* @param result
*/
public static circleToBox(circle: Circle, box: Box, result: CollisionResult = new CollisionResult()): boolean {
const closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position, result.normal);
public static circleToBox(circle: Circle, box: Box, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
const normal = new Out<Vector2>();
const closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position, normal);
result.value.normal = normal.value;
// 先处理中心在盒子里的圆,如果我们是包含的, 它的成本更低,
if (box.containsPoint(circle.position)) {
result.point = closestPointOnBounds;
result.value.point = closestPointOnBounds;
// 计算MTV。找出安全的、非碰撞的位置并从中得到MTV
const safePlace = closestPointOnBounds.add(result.normal.scale(circle.radius));
result.minimumTranslationVector = circle.position.sub(safePlace);
const safePlace = closestPointOnBounds.add(result.value.normal.scale(circle.radius));
result.value.minimumTranslationVector = circle.position.sub(safePlace);
return true;
}
const sqrDistance = Vector2.sqrDistance(closestPointOnBounds, circle.position);
// 看框上的点距圆的半径是否小于圆的半径
if (sqrDistance == 0) {
result.minimumTranslationVector = result.normal.scale(circle.radius);
result.value.minimumTranslationVector = result.value.normal.scale(circle.radius);
} else if (sqrDistance <= circle.radius * circle.radius) {
result.normal = circle.position.sub(closestPointOnBounds);
const depth = result.normal.magnitude() - circle.radius;
result.value.normal = circle.position.sub(closestPointOnBounds);
const depth = result.value.normal.magnitude() - circle.radius;
result.point = closestPointOnBounds;
result.normal = result.normal.normalize();
result.minimumTranslationVector = result.normal.scale(depth);
result.value.point = closestPointOnBounds;
result.value.normal = result.value.normal.normalize();
result.value.minimumTranslationVector = result.value.normal.scale(depth);
return true;
}
@@ -87,13 +95,15 @@ module es {
return false;
}
public static circleToPolygon(circle: Circle, polygon: Polygon, result: CollisionResult = new CollisionResult()): boolean {
public static circleToPolygon(circle: Circle, polygon: Polygon, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
// 圆圈在多边形中的位置坐标
const poly2Circle = circle.position.sub(polygon.position);
// 首先,我们需要找到从圆到多边形的最近距离
const res = Polygon.getClosestPointOnPolygonToPoint(polygon.points,poly2Circle);
result.normal = res.edgeNormal;
const res = Polygon.getClosestPointOnPolygonToPoint(polygon.points, poly2Circle);
result.value.normal = res.edgeNormal;
// 确保距离的平方小于半径的平方,否则我们不会相撞。
// 请注意,如果圆完全包含在多边形中,距离可能大于半径。
@@ -105,11 +115,11 @@ module es {
// 算出MTV。我们要注意处理完全包含在多边形中的圆或包含其中心的圆
let mtv: Vector2;
if (circleCenterInsidePoly) {
mtv = result.normal.scale(Math.sqrt(res.distanceSquared) - circle.radius);
mtv = result.value.normal.scale(Math.sqrt(res.distanceSquared) - circle.radius);
} else {
// 如果我们没有距离,这意味着圆心在多边形的边缘上。只需根据它的半径移动它
if (res.distanceSquared === 0) {
mtv = result.normal.scale(circle.radius);
mtv = result.value.normal.scale(circle.radius);
} else {
const distance = Math.sqrt(res.distanceSquared);
mtv = poly2Circle
@@ -118,8 +128,8 @@ module es {
}
}
result.minimumTranslationVector = mtv;
result.point = res.closestPoint.add(polygon.position);
result.value.minimumTranslationVector = mtv;
result.value.point = res.closestPoint.add(polygon.position);
return true;
}

View File

@@ -1,6 +1,8 @@
module es {
export class ShapeCollisionsLine {
public static lineToPoly(start: Vector2, end: Vector2, polygon: Polygon, hit: RaycastHit = new RaycastHit()): boolean {
public static lineToPoly(start: Vector2, end: Vector2, polygon: Polygon, hit: Out<RaycastHit>): boolean {
hit.value = new RaycastHit();
let normal = Vector2.zero;
let intersectionPoint = Vector2.zero;
let fraction = Number.MAX_VALUE;
@@ -31,7 +33,7 @@ module es {
if (hasIntersection){
normal = normal.normalize();
const distance = Vector2.distance(start, intersectionPoint);
hit.setValues(fraction, distance, intersectionPoint, normal);
hit.value.setValues(fraction, distance, intersectionPoint, normal);
return true;
}
@@ -63,7 +65,9 @@ module es {
return true;
}
public static lineToCircle(start: Vector2, end: Vector2, s: Circle, hit: RaycastHit): boolean{
public static lineToCircle(start: Vector2, end: Vector2, s: Circle, hit: Out<RaycastHit>): boolean{
hit.value = new RaycastHit();
// 计算这里的长度并分别对d进行标准化因为如果我们命中了我们需要它来得到分数
const lineLength = Vector2.distance(start, end);
const d = Vector2.divideScaler(end.sub(start), lineLength);
@@ -81,16 +85,16 @@ module es {
return false;
// 射线相交圆
hit.fraction = -b - Math.sqrt(discr);
hit.value.fraction = -b - Math.sqrt(discr);
// 如果分数为负数,射线从圈内开始,
if (hit.fraction < 0)
hit.fraction = 0;
if (hit.value.fraction < 0)
hit.value.fraction = 0;
hit.point = start.add(d.scale(hit.fraction));
hit.distance = Vector2.distance(start, hit.point);
hit.normal = hit.point.sub(s.position).normalize();
hit.fraction = hit.distance / lineLength;
hit.value.point = start.add(d.scale(hit.value.fraction));
hit.value.distance = Vector2.distance(start, hit.value.point);
hit.value.normal = hit.value.point.sub(s.position).normalize();
hit.value.fraction = hit.value.distance / lineLength;
return true;
}

View File

@@ -1,14 +1,16 @@
module es {
export class ShapeCollisionsPoint {
public static pointToCircle(point: Vector2, circle: Circle, result: CollisionResult): boolean {
public static pointToCircle(point: Vector2, circle: Circle, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
let distanceSquared = Vector2.sqrDistance(point, circle.position);
let sumOfRadii = 1 + circle.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
if (collided) {
result.normal = point.sub(circle.position).normalize();
result.value.normal = point.sub(circle.position).normalize();
let depth = sumOfRadii - Math.sqrt(distanceSquared);
result.minimumTranslationVector = result.normal.scale(-depth);;
result.point = circle.position.add(result.normal.scale(circle.radius));
result.value.minimumTranslationVector = result.value.normal.scale(-depth);;
result.value.point = circle.position.add(result.value.normal.scale(circle.radius));
return true;
}
@@ -16,11 +18,15 @@ module es {
return false;
}
public static pointToBox(point: Vector2, box: Box, result: CollisionResult = new CollisionResult()) {
public static pointToBox(point: Vector2, box: Box, result: Out<CollisionResult>) {
result.value = new CollisionResult();
if (box.containsPoint(point)) {
// 在方框的空间里找到点
result.point = box.bounds.getClosestPointOnRectangleBorderToPoint(point, result.normal);
result.minimumTranslationVector = point.sub(result.point);
const normal = new Out<Vector2>();
result.value.point = box.bounds.getClosestPointOnRectangleBorderToPoint(point, normal);
result.value.normal = normal.value;
result.value.minimumTranslationVector = point.sub(result.value.point);
return true;
}
@@ -28,17 +34,17 @@ module es {
return false;
}
public static pointToPoly(point: Vector2, poly: Polygon, result: CollisionResult = new CollisionResult()): boolean {
public static pointToPoly(point: Vector2, poly: Polygon, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
if (poly.containsPoint(point)) {
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);
result.value.normal = res.edgeNormal;
result.value.minimumTranslationVector = result.value.normal.scale(Math.sqrt(res.distanceSquared));
result.value.point = res.closestPoint.sub(poly.position);
return true;
}

View File

@@ -6,7 +6,8 @@ module es {
* @param second
* @param result
*/
public static polygonToPolygon(first: Polygon, second: Polygon, result: CollisionResult): boolean {
public static polygonToPolygon(first: Polygon, second: Polygon, result: Out<CollisionResult>): boolean {
result.value = new CollisionResult();
let isIntersecting = true;
const firstEdges = first.edgeNormals;
@@ -24,8 +25,8 @@ module es {
// 求多边形在当前轴上的投影
let intervalDist = 0;
let {min: minA, max: maxA} = this.getInterval(axis, first);
const {min: minB, max: maxB} = this.getInterval(axis, second);
let { min: minA, max: maxA } = this.getInterval(axis, first);
const { min: minB, max: maxB } = this.getInterval(axis, second);
// 将区间设为第二个多边形的空间。由轴上投影的位置差偏移。
const relativeIntervalOffset = polygonOffset.dot(axis);
@@ -56,8 +57,8 @@ module es {
}
// 利用最小平移向量对多边形进行推入。
result.normal = translationAxis;
result.minimumTranslationVector = translationAxis.scale(-minIntervalDistance);
result.value.normal = translationAxis;
result.value.minimumTranslationVector = translationAxis.scale(-minIntervalDistance);
return true;
}
@@ -69,8 +70,8 @@ module es {
* @param min
* @param max
*/
public static getInterval(axis: Vector2, polygon: Polygon): {min: number, max: number} {
const res = {min: 0, max: 0};
public static getInterval(axis: Vector2, polygon: Polygon): { min: number, max: number } {
const res = { min: 0, max: 0 };
let dot: number;
dot = polygon.points[0].dot(axis);
res.max = dot;
@@ -93,7 +94,7 @@ module es {
* @param minB
* @param maxB
*/
public static intervalDistance(minA: number, maxA: number, minB: number, maxB: number) {
public static intervalDistance(minA: number, maxA: number, minB: number, maxB: number) {
if (minA < minB)
return minB - maxA;

View File

@@ -213,7 +213,7 @@ module es {
*/
public overlapRectangle(rect: Rectangle, results: Collider[], layerMask: number) {
this._overlapTestBox.updateBox(rect.width, rect.height);
this._overlapTestBox.position = rect.location.clone();
this._overlapTestBox.position = rect.location;
let resultCounter = 0;
let potentials = this.aabbBroadphase(rect, null, layerMask);
@@ -410,15 +410,16 @@ module es {
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)) {
let tempHit = new Out<RaycastHit>(this._tempHit);
if (potential.shape.collidesWithLine(this._ray.start, this._ray.end, tempHit)) {
// 检查一下我们应该排除这些射线射线cast是否在碰撞器中开始
if (!Physics.raycastsStartInColliders && potential.shape.containsPoint(this._ray.start))
continue;
// TODO: 确保碰撞点在当前单元格中,如果它没有保存它以供以后计算
this._tempHit.collider = potential;
this._cellHits.push(this._tempHit);
tempHit.value.collider = potential;
this._cellHits.push(tempHit.value);
}
}
}

View File

@@ -265,8 +265,8 @@ module es {
public static getClosestPointOnRectangleBorderToPoint(rect: Rectangle, point: Vector2) {
// 对于每个轴,如果该点在盒子外面,则将在盒子上,否则不理会它
let res = es.Vector2.zero;
res.x = MathHelper.clamp(Math.trunc(point.x), rect.left, rect.right)
res.y = MathHelper.clamp(Math.trunc(point.y), rect.top, rect.bottom);
res.x = MathHelper.clamp(MathHelper.toInt(point.x), rect.left, rect.right)
res.y = MathHelper.clamp(MathHelper.toInt(point.y), rect.top, rect.bottom);
// 如果点在矩形内我们需要将res推到边框因为它将在矩形内
if (rect.contains(res.x, res.y)) {
@@ -327,16 +327,16 @@ module es {
maxY = pt.y;
}
return this.fromMinMaxVector(new Vector2(Math.trunc(minX), Math.trunc(minY)), new Vector2(Math.trunc(maxX), Math.trunc(maxY)));
return this.fromMinMaxVector(new Vector2(MathHelper.toInt(minX), MathHelper.toInt(minY)), new Vector2(MathHelper.toInt(maxX), MathHelper.toInt(maxY)));
}
public static calculateBounds(rect: Rectangle, parentPosition: Vector2, position: Vector2, origin: Vector2, scale: Vector2,
rotation: number, width: number, height: number) {
if (rotation == 0) {
rect.x = Math.trunc(parentPosition.x + position.x - origin.x * scale.x);
rect.y = Math.trunc(parentPosition.y + position.y - origin.y * scale.y);
rect.width = Math.trunc(width * scale.x);
rect.height = Math.trunc(height * scale.y);
rect.x = MathHelper.toInt(parentPosition.x + position.x - origin.x * scale.x);
rect.y = MathHelper.toInt(parentPosition.y + position.y - origin.y * scale.y);
rect.width = MathHelper.toInt(width * scale.x);
rect.height = MathHelper.toInt(height * scale.y);
} else {
// 我们需要找到我们的绝对最小/最大值,并据此创建边界
let worldPosX = parentPosition.x + position.x;
@@ -366,14 +366,14 @@ module es {
Vector2Ext.transformR(bottomRight, transformMatrix, bottomRight);
// 找出最小值和最大值,这样我们就可以计算出我们的边界框。
let minX = Math.trunc(Math.min(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x));
let maxX = Math.trunc(Math.max(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x));
let minY = Math.trunc(Math.min(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y));
let maxY = Math.trunc(Math.max(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y));
let minX = MathHelper.toInt(Math.min(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x));
let maxX = MathHelper.toInt(Math.max(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x));
let minY = MathHelper.toInt(Math.min(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y));
let maxY = MathHelper.toInt(Math.max(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y));
rect.location = new Vector2(minX, minY);
rect.width = Math.trunc(maxX - minX);
rect.height = Math.trunc(maxY - minY);
rect.width = MathHelper.toInt(maxX - minX);
rect.height = MathHelper.toInt(maxY - minY);
}
}
@@ -383,10 +383,10 @@ module es {
* @param scale
*/
public static scale(rect: Rectangle, scale: Vector2) {
rect.x = Math.trunc(rect.x * scale.x);
rect.y = Math.trunc(rect.y * scale.y);
rect.width = Math.trunc(rect.width * scale.x);
rect.height = Math.trunc(rect.height * scale.y);
rect.x = MathHelper.toInt(rect.x * scale.x);
rect.y = MathHelper.toInt(rect.y * scale.y);
rect.width = MathHelper.toInt(rect.width * scale.x);
rect.height = MathHelper.toInt(rect.height * scale.y);
}
public static translate(rect: Rectangle, vec: Vector2) {

9
source/src/Utils/Out.ts Normal file
View File

@@ -0,0 +1,9 @@
module es {
export class Out<T> {
public value: T;
constructor(value: T = null) {
this.value = value;
}
}
}