新增Physics.linecast/linecastAll方法

This commit is contained in:
YHH
2020-08-22 12:21:40 +08:00
parent 73f0f54ba7
commit 6c1cfec928
16 changed files with 537 additions and 145 deletions

View File

@@ -1,3 +1,4 @@
///<reference path="./RaycastHit.ts" />
module es {
export class Physics {
/** 调用reset并创建一个新的SpatialHash时使用的单元格大小 */
@@ -13,6 +14,12 @@ module es {
* 在碰撞器中开始的射线/直线是否强制转换检测到那些碰撞器
*/
public static raycastsStartInColliders = false;
/**
* 我们保留它以避免在每次raycast发生时分配它
*/
public static _hitArray: RaycastHit[] = [
new RaycastHit()
];
public static reset() {
this._spatialHash = new SpatialHash(this.spatialHashCellSize);
@@ -85,6 +92,34 @@ module es {
this._spatialHash.register(collider);
}
/**
* 返回与layerMask匹配的碰撞器的第一次命中
* @param start
* @param end
* @param layerMask
*/
public static linecast(start: Vector2, end: Vector2, layerMask: number = Physics.allLayers): RaycastHit{
this._hitArray[0].reset();
this.linecastAll(start, end, this._hitArray, layerMask);
return this._hitArray[0];
}
/**
* 通过空间散列强制执行一行并用该行命中的任何碰撞器填充hits数组
* @param start
* @param end
* @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);
}
/**
* debug绘制空间散列的内容
* @param secondsToDisplay

View File

@@ -30,7 +30,7 @@ module es {
*/
public centroid: Vector2;
constructor(collider: Collider, fraction: number, distance: number, point: Vector2, normal: Vector2){
constructor(collider?: Collider, fraction?: number, distance?: number, point?: Vector2, normal?: Vector2){
this.collider = collider;
this.fraction = fraction;
this.distance = distance;

View File

@@ -144,6 +144,73 @@ module es {
return this._tempHashSet;
}
/**
* 通过空间散列强制执行一行并用该行命中的任何碰撞器填充hits数组。
* @param start
* @param end
* @param hits
* @param layerMask
*/
public linecast(start: Vector2, end: Vector2, hits: RaycastHit[], layerMask: number){
let ray = new Ray2D(start, end);
this._raycastParser.start(ray, hits, layerMask);
// 在与网格相同的空间中获取起始/结束位置
let currentCell = this.cellCoords(start.x, start.y);
let lastCell = this.cellCoords(end.x, end.y);
let stepX = Math.sign(ray.direction.x);
let stepY = Math.sign(ray.direction.y);
// 我们要确保,如果我们在同一行或同一行,我们不会步进不必要的方向
if (currentCell.x == lastCell.x) stepX = 0;
if (currentCell.y == lastCell.y) stepY = 0;
// 计算单元边界。当这一步是正的下一个单元格在这一步之后意味着我们加1。
// 如果为负,则单元格在此之前,这种情况下不添加边界
let xStep = stepX < 0 ? 0 : stepX;
let yStep = stepY < 0 ? 0 : stepY;
let nextBoundaryX = (currentCell.x + xStep) * this._cellSize;
let nextBoundaryY = (currentCell.y + yStep) * this._cellSize;
// 确定射线穿过第一个垂直体素边界时的t值。y/horizontal。
// 这两个值的最小值将表明我们可以沿着射线走多少而仍然保持在当前体素中对于接近vertical/horizontal的射线来说可能是无限的
let tMaxX = ray.direction.x != 0 ? (nextBoundaryX - ray.start.x) / ray.direction.x : Number.MAX_VALUE;
let tMaxY = ray.direction.y != 0 ? (nextBoundaryY - ray.start.y) / ray.direction.y : Number.MAX_VALUE;
let tDeltaX = ray.direction.x != 0 ? this._cellSize / (ray.direction.x * stepX) : Number.MAX_VALUE;
let tDeltaY = ray.direction.y != 0 ? this._cellSize / (ray.direction.y * stepY) : Number.MAX_VALUE;
// 开始遍历并返回交叉单元格。
let cell = this.cellAtPosition(currentCell.x, currentCell.y);
if (cell && this._raycastParser.checkRayIntersection(currentCell.x, currentCell.y, cell)){
this._raycastParser.reset();
return this._raycastParser.hitCounter;
}
while (currentCell.x != lastCell.x || currentCell.y != lastCell.y){
if (tMaxX < tMaxY){
currentCell.x = MathHelper.approach(currentCell.x, lastCell.x, Math.abs(stepX));
tMaxX += tDeltaX;
}else{
currentCell.y = MathHelper.approach(currentCell.y, lastCell.y, Math.abs(stepY));
tMaxY += tDeltaY;
}
cell = this.cellAtPosition(currentCell.x, currentCell.y);
if (cell && this._raycastParser.checkRayIntersection(currentCell.x, currentCell.y, cell)){
this._raycastParser.reset();
return this._raycastParser.hitCounter;
}
}
this._raycastParser.reset();
return this._raycastParser.hitCounter;
}
/**
* 获取位于指定圆内的所有碰撞器
* @param circleCenter
@@ -268,7 +335,7 @@ module es {
};
public _hits: RaycastHit[];
public _tempHit: RaycastHit;
public _tempHit: RaycastHit = new RaycastHit();
public _checkedColliders: Collider[] = [];
public _cellHits: RaycastHit[] = [];
public _ray: Ray2D;