优化triggerListener与ArrayUtils
This commit is contained in:
@@ -4,10 +4,10 @@ module es {
|
||||
*/
|
||||
export class ColliderTriggerHelper {
|
||||
private _entity: Entity;
|
||||
/** 存储当前帧中发生的所有活动交集对 */
|
||||
private _activeTriggerIntersections: Pair<Collider>[] = [];
|
||||
/** 存储前一帧的交叉对,以便我们可以在移动该帧后检测出口 */
|
||||
private _previousTriggerIntersections: Pair<Collider>[] = [];
|
||||
/** 存储当前帧中发生的所有活动交点对 */
|
||||
private _activeTriggerIntersections: Set<Pair<Collider>> = new Set();
|
||||
/** 存储前一帧的交点对,这样我们就可以在移动这一帧后检测到退出 */
|
||||
private _previousTriggerIntersections: Set<Pair<Collider>> = new Set();
|
||||
private _tempTriggerList: ITriggerListener[] = [];
|
||||
|
||||
constructor(entity: Entity) {
|
||||
@@ -15,32 +15,34 @@ module es {
|
||||
}
|
||||
|
||||
/**
|
||||
* 实体被移动后,应该调用更新。它会处理碰撞器重叠的任何itriggerlistener。
|
||||
* update应该在实体被移动后被调用,它将处理任何与Colllider重叠的ITriggerListeners。
|
||||
* 它将处理任何与Collider重叠的ITriggerListeners。
|
||||
*/
|
||||
public update() {
|
||||
// 对所有实体.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);
|
||||
for (let j = 0; j < neighbors.length; j++) {
|
||||
for (let j = 0; j < neighbors.size; j++) {
|
||||
let neighbor = neighbors[j];
|
||||
// 我们至少需要一个碰撞器作为触发器
|
||||
if (!collider.isTrigger && !neighbor.isTrigger)
|
||||
continue;
|
||||
|
||||
if (collider.overlaps(neighbor)) {
|
||||
let pair = new Pair<Collider>(collider, neighbor);
|
||||
let shouldReportTriggerEvent = this._activeTriggerIntersections.findIndex(value => {
|
||||
return value.first == pair.first && value.second == pair.second;
|
||||
}) == -1 && this._previousTriggerIntersections.findIndex(value => {
|
||||
return value.first == pair.first && value.second == pair.second;
|
||||
}) == -1;
|
||||
|
||||
// 如果我们的某一个集合中已经有了这个对子(前一个或当前的触发交叉点),就不要调用输入事件了
|
||||
let shouldReportTriggerEvent = !this._activeTriggerIntersections.has(pair) &&
|
||||
!this._previousTriggerIntersections.has(pair);
|
||||
|
||||
if (shouldReportTriggerEvent)
|
||||
this.notifyTriggerListeners(pair, true);
|
||||
|
||||
if (!this._activeTriggerIntersections.contains(pair))
|
||||
this._activeTriggerIntersections.push(pair);
|
||||
this._activeTriggerIntersections.add(pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,31 +53,42 @@ module es {
|
||||
}
|
||||
|
||||
private checkForExitedColliders() {
|
||||
for (let i = 0; i < this._activeTriggerIntersections.length; i++) {
|
||||
let index = this._previousTriggerIntersections.findIndex(value => {
|
||||
if (value.first == this._activeTriggerIntersections[i].first && value.second == this._activeTriggerIntersections[i].second)
|
||||
return true;
|
||||
// 删除所有与此帧交互的触发器,留下我们退出的触发器
|
||||
this.excepthWith(this._previousTriggerIntersections, this._activeTriggerIntersections);
|
||||
|
||||
return false;
|
||||
});
|
||||
if (index != -1)
|
||||
this._previousTriggerIntersections.removeAt(index);
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._previousTriggerIntersections.length; i++) {
|
||||
for (let i = 0; i < this._previousTriggerIntersections.size; i++) {
|
||||
this.notifyTriggerListeners(this._previousTriggerIntersections[i], false)
|
||||
}
|
||||
this._previousTriggerIntersections.length = 0;
|
||||
for (let i = 0; i < this._activeTriggerIntersections.length; i++) {
|
||||
if (!this._previousTriggerIntersections.contains(this._activeTriggerIntersections[i])) {
|
||||
this._previousTriggerIntersections.push(this._activeTriggerIntersections[i]);
|
||||
|
||||
this._previousTriggerIntersections.clear();
|
||||
|
||||
// 添加所有当前激活的触发器
|
||||
this.unionWith(this._previousTriggerIntersections, this._activeTriggerIntersections);
|
||||
|
||||
// 清空活动集,为下一帧做准备
|
||||
this._activeTriggerIntersections.clear();
|
||||
}
|
||||
|
||||
private excepthWith(previous: Set<Pair<Collider>>, active: Set<Pair<Collider>>){
|
||||
for (let i = 0; i < previous.size; i ++){
|
||||
let previousDATA: Pair<Collider> = previous[i];
|
||||
for (let j = 0; j < active.size; j ++){
|
||||
let activeDATA: Pair<Collider> = active[j];
|
||||
if (activeDATA.equals(previousDATA))
|
||||
previous.delete(previousDATA);
|
||||
}
|
||||
}
|
||||
this._activeTriggerIntersections.length = 0;
|
||||
}
|
||||
|
||||
private unionWith(previous: Set<Pair<Collider>>, active: Set<Pair<Collider>>) {
|
||||
for (let i = 0; i < this._activeTriggerIntersections.size; i ++) {
|
||||
if (!this._previousTriggerIntersections.has(this._activeTriggerIntersections[i]))
|
||||
this._previousTriggerIntersections.add(this._activeTriggerIntersections[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private notifyTriggerListeners(collisionPair: Pair<Collider>, isEntering: boolean) {
|
||||
collisionPair.first.entity.getComponents("ITriggerListener", this._tempTriggerList);
|
||||
TriggerListenerHelper.getITriggerListener(collisionPair.first.entity, this._tempTriggerList);
|
||||
for (let i = 0; i < this._tempTriggerList.length; i++) {
|
||||
if (isEntering) {
|
||||
this._tempTriggerList[i].onTriggerEnter(collisionPair.second, collisionPair.first);
|
||||
@@ -86,7 +99,7 @@ module es {
|
||||
this._tempTriggerList.length = 0;
|
||||
|
||||
if (collisionPair.second.entity) {
|
||||
collisionPair.second.entity.getComponents("ITriggerListener", this._tempTriggerList);
|
||||
TriggerListenerHelper.getITriggerListener(collisionPair.second.entity, this._tempTriggerList);
|
||||
for (let i = 0; i < this._tempTriggerList.length; i++) {
|
||||
if (isEntering) {
|
||||
this._tempTriggerList[i].onTriggerEnter(collisionPair.first, collisionPair.second);
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
///<reference path="./RaycastHit.ts" />
|
||||
module es {
|
||||
export class Physics {
|
||||
public static _spatialHash: SpatialHash;
|
||||
/** 调用reset并创建一个新的SpatialHash时使用的单元格大小 */
|
||||
public static spatialHashCellSize = 100;
|
||||
/** 接受layerMask的所有方法的默认值 */
|
||||
public static readonly allLayers: number = -1;
|
||||
private static _spatialHash: SpatialHash;
|
||||
/**
|
||||
* raycast是否检测配置为触发器的碰撞器
|
||||
*/
|
||||
@@ -120,13 +120,5 @@ module es {
|
||||
|
||||
return this._spatialHash.linecast(start, end, hits, layerMask);
|
||||
}
|
||||
|
||||
/**
|
||||
* debug绘制空间散列的内容
|
||||
* @param secondsToDisplay
|
||||
*/
|
||||
public static debugDraw(secondsToDisplay) {
|
||||
this._spatialHash.debugDraw(secondsToDisplay, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ module es {
|
||||
/**
|
||||
* 用于返回冲突信息的共享HashSet
|
||||
*/
|
||||
public _tempHashSet: Collider[] = [];
|
||||
public _tempHashSet: Set<Collider> = new Set<Collider>();
|
||||
|
||||
constructor(cellSize: number = 100) {
|
||||
this._cellSize = cellSize;
|
||||
@@ -53,8 +53,7 @@ module es {
|
||||
for (let y = p1.y; y <= p2.y; y++) {
|
||||
// 如果没有单元格,我们需要创建它
|
||||
let c: Collider[] = this.cellAtPosition(x, y, true);
|
||||
if (!c.firstOrDefault(c => c == collider))
|
||||
c.push(collider);
|
||||
c.push(collider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,29 +91,14 @@ module es {
|
||||
this._cellDict.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* debug绘制空间散列的内容
|
||||
* @param secondsToDisplay
|
||||
* @param textScale
|
||||
*/
|
||||
public debugDraw(secondsToDisplay: number, textScale: number = 1) {
|
||||
for (let x = this.gridBounds.x; x <= this.gridBounds.right; x++) {
|
||||
for (let y = this.gridBounds.y; y <= this.gridBounds.bottom; y++) {
|
||||
let cell = this.cellAtPosition(x, y);
|
||||
if (cell && cell.length > 0)
|
||||
this.debugDrawCellDetails(x, y, cell.length, secondsToDisplay, textScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回边框与单元格相交的所有对象
|
||||
* @param bounds
|
||||
* @param excludeCollider
|
||||
* @param layerMask
|
||||
*/
|
||||
public aabbBroadphase(bounds: Rectangle, excludeCollider: Collider, layerMask: number): Collider[] {
|
||||
this._tempHashSet.length = 0;
|
||||
public aabbBroadphase(bounds: Rectangle, excludeCollider: Collider, layerMask: number): Set<Collider> {
|
||||
this._tempHashSet.clear();
|
||||
|
||||
let p1 = this.cellCoords(bounds.x, bounds.y);
|
||||
let p2 = this.cellCoords(bounds.right, bounds.bottom);
|
||||
@@ -134,8 +118,7 @@ module es {
|
||||
continue;
|
||||
|
||||
if (bounds.intersects(collider.bounds)) {
|
||||
if (!this._tempHashSet.firstOrDefault(c => c == collider))
|
||||
this._tempHashSet.push(collider);
|
||||
this._tempHashSet.add(collider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +209,7 @@ module es {
|
||||
|
||||
let resultCounter = 0;
|
||||
let potentials = this.aabbBroadphase(bounds, null, layerMask);
|
||||
for (let i = 0; i < potentials.length; i++) {
|
||||
for (let i = 0; i < potentials.size; i++) {
|
||||
let collider = potentials[i];
|
||||
if (collider instanceof BoxCollider) {
|
||||
results[resultCounter] = collider;
|
||||
@@ -258,7 +241,7 @@ module es {
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
private cellCoords(x: number, y: number): Vector2 {
|
||||
public cellCoords(x: number, y: number): Vector2 {
|
||||
return new Vector2(Math.floor(x * this._inverseCellSize), Math.floor(y * this._inverseCellSize));
|
||||
}
|
||||
|
||||
@@ -269,7 +252,7 @@ module es {
|
||||
* @param y
|
||||
* @param createCellIfEmpty
|
||||
*/
|
||||
private cellAtPosition(x: number, y: number, createCellIfEmpty: boolean = false): Collider[] {
|
||||
public cellAtPosition(x: number, y: number, createCellIfEmpty: boolean = false): Collider[] {
|
||||
let cell: Collider[] = this._cellDict.tryGetValue(x, y);
|
||||
if (!cell) {
|
||||
if (createCellIfEmpty) {
|
||||
@@ -279,10 +262,6 @@ module es {
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
private debugDrawCellDetails(x: number, y: number, cellCount: number, secondsToDisplay = 0.5, textScale = 1) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user