新增renderablecomponent显示

优化返回值
This commit is contained in:
yhh
2020-07-27 16:10:36 +08:00
parent 149a3e5833
commit 506f8ddc0f
28 changed files with 631 additions and 512 deletions

View File

@@ -22,9 +22,7 @@ module es {
for (let i = 0; i < colliders.length; i++) {
let collider = colliders[i];
let boxcastResult = Physics.boxcastBroadphase(collider.bounds, collider.collidesWithLayers);
collider.bounds = boxcastResult.rect;
let neighbors = boxcastResult.colliders;
let neighbors = Physics.boxcastBroadphase(collider.bounds, collider.collidesWithLayers);
for (let j = 0; j < neighbors.length; j++) {
let neighbor = neighbors[j];
if (!collider.isTrigger && !neighbor.isTrigger)

View File

@@ -17,15 +17,37 @@ module es {
this._spatialHash.clear();
}
/**
* 获取位于指定圆内的所有碰撞器
* @param center
* @param randius
* @param results
* @param layerMask
*/
public static overlapCircleAll(center: Vector2, randius: number, results: any[], layerMask = -1){
if (results.length == 0){
console.error("An empty results array was passed in. No results will ever be returned.");
return;
}
return this._spatialHash.overlapCircle(center, randius, results, layerMask);
}
/**
* 返回所有碰撞器与边界相交的碰撞器。bounds。请注意这是一个broadphase检查所以它只检查边界不做单个碰撞到碰撞器的检查!
* @param rect
* @param layerMask
*/
public static boxcastBroadphase(rect: Rectangle, layerMask: number = this.allLayers){
let boxcastResult = this._spatialHash.aabbBroadphase(rect, null, layerMask);
return {colliders: boxcastResult.tempHashSet, rect: boxcastResult.bounds};
return this._spatialHash.aabbBroadphase(rect, null, layerMask);
}
/**
* 返回所有与边界相交的碰撞器,不包括传入的碰撞器(self)。如果您希望为其他查询自行创建扫过的边界,则此方法非常有用
* @param collider
* @param rect
* @param layerMask
*/
public static boxcastBroadphaseExcludingSelf(collider: Collider, rect: Rectangle, layerMask = this.allLayers){
return this._spatialHash.aabbBroadphase(rect, collider, layerMask);
}

View File

@@ -66,15 +66,15 @@ module es {
return super.overlaps(other);
}
public collidesWithShape(other: Shape){
public collidesWithShape(other: Shape, result: CollisionResult): boolean{
// 特殊情况这一个高性能方式实现其他情况则使用polygon方法检测
if (other instanceof Box && (other as Box).isUnrotated){
return ShapeCollisions.boxToBox(this, other);
return ShapeCollisions.boxToBox(this, other, result);
}
// TODO: 让 minkowski 运行于 cricleToBox
return super.collidesWithShape(other);
return super.collidesWithShape(other, result);
}
public containsPoint(point: Vector2){

View File

@@ -34,6 +34,7 @@ module es {
}
public overlaps(other: Shape) {
let result: CollisionResult = new CollisionResult();
if (other instanceof Box && (other as Box).isUnrotated)
return Collisions.isRectToCircle(other.bounds, this.position, this.radius);
@@ -41,29 +42,29 @@ module es {
return Collisions.isCircleToCircle(this.position, this.radius, other.position, (other as Circle).radius);
if (other instanceof Polygon)
return ShapeCollisions.circleToPolygon(this, other);
return ShapeCollisions.circleToPolygon(this, other, result);
throw new Error(`overlaps of circle to ${other} are not supported`);
}
public collidesWithShape(other: Shape): CollisionResult {
public collidesWithShape(other: Shape, result: CollisionResult): boolean {
if (other instanceof Box && (other as Box).isUnrotated) {
return ShapeCollisions.circleToBox(this, other);
return ShapeCollisions.circleToBox(this, other, result);
}
if (other instanceof Circle) {
return ShapeCollisions.circleToCircle(this, other);
return ShapeCollisions.circleToCircle(this, other, result);
}
if (other instanceof Polygon) {
return ShapeCollisions.circleToPolygon(this, other);
return ShapeCollisions.circleToPolygon(this, other, result);
}
throw new Error(`Collisions of Circle to ${other} are not supported`);
}
public pointCollidesWithShape(point: Vector2): CollisionResult {
return ShapeCollisions.pointToCircle(point, this);
public pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean {
return ShapeCollisions.pointToCircle(point, this, result);
}
}
}

View File

@@ -141,10 +141,12 @@ module es {
* 点应该在多边形的空间中(点-多边形.位置)
* @param points
* @param point
* @param distanceSquared
* @param edgeNormal
*/
public static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2): { closestPoint, distanceSquared, edgeNormal } {
let distanceSquared = Number.MAX_VALUE;
let edgeNormal = new Vector2(0, 0);
public static getClosestPointOnPolygonToPoint(points: Vector2[], point: Vector2, distanceSquared: number, edgeNormal: Vector2): Vector2 {
distanceSquared = Number.MAX_VALUE;
edgeNormal = new Vector2(0, 0);
let closestPoint = new Vector2(0, 0);
let tempDistanceSquared;
@@ -166,9 +168,9 @@ module es {
}
}
edgeNormal = Vector2.normalize(edgeNormal);
Vector2Ext.normalize(edgeNormal);
return { closestPoint: closestPoint, distanceSquared: distanceSquared, edgeNormal: edgeNormal };
return closestPoint;
}
public recalculateBounds(collider: Collider){
@@ -221,13 +223,12 @@ module es {
}
public overlaps(other: Shape){
let result: CollisionResult;
let result: CollisionResult = new CollisionResult();
if (other instanceof Polygon)
return ShapeCollisions.polygonToPolygon(this, other);
return ShapeCollisions.polygonToPolygon(this, other, result);
if (other instanceof Circle){
result = ShapeCollisions.circleToPolygon(other, this);
if (result){
if (ShapeCollisions.circleToPolygon(other, this, result)){
result.invertResult();
return true;
}
@@ -238,20 +239,18 @@ module es {
throw new Error(`overlaps of Pologon to ${other} are not supported`);
}
public collidesWithShape(other: Shape){
let result = new CollisionResult();
public collidesWithShape(other: Shape, result: CollisionResult): boolean{
if (other instanceof Polygon){
return ShapeCollisions.polygonToPolygon(this, other);
return ShapeCollisions.polygonToPolygon(this, other, result);
}
if (other instanceof Circle){
result = ShapeCollisions.circleToPolygon(other, this);
if (result){
if (ShapeCollisions.circleToPolygon(other, this, result)){
result.invertResult();
return result;
return true;
}
return null;
return false;
}
throw new Error(`overlaps of Polygon to ${other} are not supported`);
@@ -278,8 +277,8 @@ module es {
return isInside;
}
public pointCollidesWithShape(point: Vector2): CollisionResult {
return ShapeCollisions.pointToPoly(point, this);
public pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean {
return ShapeCollisions.pointToPoly(point, this, result);
}
}
}

View File

@@ -16,9 +16,9 @@ module es {
public bounds: Rectangle;
public abstract recalculateBounds(collider: Collider);
public abstract pointCollidesWithShape(point: Vector2): CollisionResult;
public abstract overlaps(other: Shape);
public abstract collidesWithShape(other: Shape): CollisionResult;
public abstract overlaps(other: Shape): boolean;
public abstract collidesWithShape(other: Shape, collisionResult: CollisionResult): boolean;
public abstract pointCollidesWithShape(point: Vector2, result: CollisionResult): boolean;
public clone(): Shape{
return ObjectUtils.clone<Shape>(this);

View File

@@ -4,9 +4,9 @@ module es {
* 检查两个多边形之间的碰撞
* @param first
* @param second
* @param result
*/
public static polygonToPolygon(first: Polygon, second: Polygon) {
let result = new CollisionResult();
public static polygonToPolygon(first: Polygon, second: Polygon, result: CollisionResult): boolean {
let isIntersecting = true;
let firstEdges = first.edgeNormals;
@@ -54,7 +54,7 @@ module es {
// 如果多边形不相交,也不会相交,退出循环
if (!isIntersecting)
return null;
return false;
// 检查当前间隔距离是否为最小值。如果是,则存储间隔距离和当前距离。这将用于计算最小平移向量
intervalDist = Math.abs(intervalDist);
@@ -71,7 +71,7 @@ module es {
result.normal = translationAxis;
result.minimumTranslationVector = Vector2.multiply(new Vector2(-translationAxis.x, -translationAxis.y), new Vector2(minIntervalDistance));
return result;
return true;
}
/**
@@ -115,20 +115,17 @@ module es {
*
* @param circle
* @param polygon
* @param result
*/
public static circleToPolygon(circle: Circle, polygon: Polygon) {
let result = new CollisionResult();
public static circleToPolygon(circle: Circle, polygon: Polygon, result: CollisionResult): boolean {
let poly2Circle = Vector2.subtract(circle.position, polygon.position);
let gpp = Polygon.getClosestPointOnPolygonToPoint(polygon.points, poly2Circle);
let closestPoint: Vector2 = gpp.closestPoint;
let distanceSquared: number = gpp.distanceSquared;
result.normal = gpp.edgeNormal;
let distanceSquared = 0;
let closestPoint = Polygon.getClosestPointOnPolygonToPoint(polygon.points, poly2Circle, distanceSquared, result.normal);
let circleCenterInsidePoly = polygon.containsPoint(circle.position);
if (distanceSquared > circle.radius * circle.radius && !circleCenterInsidePoly)
return null;
return false;
let mtv: Vector2;
if (circleCenterInsidePoly) {
@@ -145,17 +142,17 @@ module es {
result.minimumTranslationVector = mtv;
result.point = Vector2.add(closestPoint, polygon.position);
return result;
return true;
}
/**
* 适用于圆心在方框内以及只与方框外圆心重叠的圆。
* @param circle
* @param box
* @param result
*/
public static circleToBox(circle: Circle, box: Box): CollisionResult {
let result = new CollisionResult();
let closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position).res;
public static circleToBox(circle: Circle, box: Box, result: CollisionResult): boolean {
let closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position, result.normal);
if (box.containsPoint(circle.position)) {
result.point = closestPointOnBounds;
@@ -163,7 +160,7 @@ module es {
let safePlace = Vector2.add(closestPointOnBounds, Vector2.subtract(result.normal, new Vector2(circle.radius)));
result.minimumTranslationVector = Vector2.subtract(circle.position, safePlace);
return result;
return true;
}
let sqrDistance = Vector2.distanceSquared(closestPointOnBounds, circle.position);
@@ -172,23 +169,24 @@ module es {
} else if (sqrDistance <= circle.radius * circle.radius) {
result.normal = Vector2.subtract(circle.position, closestPointOnBounds);
let depth = result.normal.length() - circle.radius;
result.normal = Vector2Ext.normalize(result.normal);
result.point = closestPointOnBounds;
Vector2Ext.normalize(result.normal);
result.minimumTranslationVector = Vector2.multiply(new Vector2(depth), result.normal);
return result;
return true;
}
return null;
return false;
}
/**
*
* @param point
* @param circle
* @param result
*/
public static pointToCircle(point: Vector2, circle: Circle) {
let result = new CollisionResult();
public static pointToCircle(point: Vector2, circle: Circle, result: CollisionResult): boolean {
let distanceSquared = Vector2.distanceSquared(point, circle.position);
let sumOfRadii = 1 + circle.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
@@ -198,10 +196,10 @@ module es {
result.minimumTranslationVector = Vector2.multiply(new Vector2(-depth, -depth), result.normal);
result.point = Vector2.add(circle.position, Vector2.multiply(result.normal, new Vector2(circle.radius, circle.radius)));
return result;
return true;
}
return null;
return false;
}
/**
@@ -210,7 +208,7 @@ module es {
* @param lineB
* @param closestTo
*/
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
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);
@@ -223,24 +221,20 @@ module es {
*
* @param point
* @param poly
* @param result
*/
public static pointToPoly(point: Vector2, poly: Polygon) {
let result = new CollisionResult();
public static pointToPoly(point: Vector2, poly: Polygon, result: CollisionResult): boolean {
if (poly.containsPoint(point)) {
let distanceSquared: number;
let gpp = Polygon.getClosestPointOnPolygonToPoint(poly.points, Vector2.subtract(point, poly.position));
let closestPoint = gpp.closestPoint;
distanceSquared = gpp.distanceSquared;
result.normal = gpp.edgeNormal;
let distanceSquared: number = 0;
let closestPoint = Polygon.getClosestPointOnPolygonToPoint(poly.points, Vector2.subtract(point, poly.position), distanceSquared, result.normal);
result.minimumTranslationVector = Vector2.multiply(result.normal, new Vector2(Math.sqrt(distanceSquared), Math.sqrt(distanceSquared)));
result.point = Vector2.add(closestPoint, poly.position);
return result;
return true;
}
return null;
return false;
}
/**
@@ -248,9 +242,7 @@ module es {
* @param first
* @param second
*/
public static circleToCircle(first: Circle, second: Circle){
let result = new CollisionResult();
public static circleToCircle(first: Circle, second: Circle, result: CollisionResult): boolean{
let distanceSquared = Vector2.distanceSquared(first.position, second.position);
let sumOfRadii = first.radius + second.radius;
let collided = distanceSquared < sumOfRadii * sumOfRadii;
@@ -260,35 +252,34 @@ module es {
result.minimumTranslationVector = Vector2.multiply(new Vector2(-depth), result.normal);
result.point = Vector2.add(second.position, Vector2.multiply(result.normal, new Vector2(second.radius)));
return result;
return true;
}
return null;
return false;
}
/**
*
* @param first
* @param second
* @param result
*/
public static boxToBox(first: Box, second: Box){
let result = new CollisionResult();
public static boxToBox(first: Box, second: Box, result: CollisionResult): boolean{
let minkowskiDiff = this.minkowskiDifference(first, second);
if (minkowskiDiff.contains(0, 0)){
// 计算MTV。如果它是零我们就可以称它为非碰撞
result.minimumTranslationVector = minkowskiDiff.getClosestPointOnBoundsToOrigin();
if (result.minimumTranslationVector.x == 0 && result.minimumTranslationVector.y == 0)
return null;
if (result.minimumTranslationVector.equals(Vector2.zero))
return false;
result.normal = new Vector2(-result.minimumTranslationVector.x, -result.minimumTranslationVector.y);
result.normal.normalize();
return result;
return true;
}
return null;
return false;
}
private static minkowskiDifference(first: Box, second: Box){

View File

@@ -144,7 +144,7 @@ module es {
* @param excludeCollider
* @param layerMask
*/
public aabbBroadphase(bounds: Rectangle, excludeCollider: Collider, layerMask: number) {
public aabbBroadphase(bounds: Rectangle, excludeCollider: Collider, layerMask: number) : Collider[]{
this._tempHashSet.length = 0;
let p1 = this.cellCoords(bounds.x, bounds.y);
@@ -172,7 +172,7 @@ module es {
}
}
return {tempHashSet: this._tempHashSet, bounds: bounds};
return this._tempHashSet;
}
/**
@@ -182,16 +182,14 @@ module es {
* @param results
* @param layerMask
*/
public overlapCircle(circleCenter: Vector2, radius: number, results: Collider[], layerMask) {
public overlapCircle(circleCenter: Vector2, radius: number, results: Collider[], layerMask): number {
let bounds = new Rectangle(circleCenter.x - radius, circleCenter.y - radius, radius * 2, radius * 2);
this._overlapTestCircle.radius = radius;
this._overlapTestCircle.position = circleCenter;
let resultCounter = 0;
let aabbBroadphaseResult = this.aabbBroadphase(bounds, null, layerMask);
bounds = aabbBroadphaseResult.bounds;
let potentials = aabbBroadphaseResult.tempHashSet;
let potentials = this.aabbBroadphase(bounds, null, layerMask);
for (let i = 0; i < potentials.length; i++) {
let collider = potentials[i];
if (collider instanceof BoxCollider) {