完善 colliderTriggerHelper 用于更新碰撞信息

This commit is contained in:
YHH
2020-06-16 09:10:09 +08:00
parent dba43b9773
commit 75301f7776
13 changed files with 471 additions and 41 deletions

View File

@@ -30,7 +30,7 @@ abstract class Component {
}
public initialize(){
}
public onAddedToEntity(){

View File

@@ -212,8 +212,8 @@ class Entity {
return this.components.getComponent(type, false) as T;
}
public getComponents<T extends Component>(type): T[]{
return this.components.getComponents<T>(type);
public getComponents(typeName: string, componentList?){
return this.components.getComponents(typeName, componentList);
}
public removeComponentForType<T extends Component>(type){

View File

@@ -120,18 +120,20 @@ class ComponentList {
return null;
}
public getComponents<T extends Component>(type): T[]{
let components = [];
public getComponents(typeName: string, components?){
if (!components)
components = [];
for (let i = 0; i < this._components.length; i ++){
let component = this._components[i];
if (component instanceof type)
components.push(components);
if (egret.is(component, typeName))
components.push(component);
}
for (let i = 0; i < this._componentsToAdd.length; i ++){
let component = this._componentsToAdd[i];
if (component instanceof type)
components.push(components);
if (egret.is(component, typeName))
components.push(component);
}
return components;

View File

@@ -1,21 +1,89 @@
class ColliderTriggerHelper {
private _entity: Entity;
/** 存储当前帧中发生的所有活动交集对 */
private _activeTriggerIntersections: Pair<Collider>[] = [];
/** 存储前一帧的交叉对,以便我们可以在移动该帧后检测出口 */
private _previousTriggerIntersections: Pair<Collider>[] = [];
private _tempTriggerList: ITriggerListener[] = [];
constructor(entity: Entity) {
this._entity = entity;
}
public update(){
let colliders = this._entity.getComponents<Collider>(Collider);
for (let i = 0; i < colliders.length; i ++){
/**
* 实体被移动后应该调用更新。它会处理碰撞器重叠的任何itriggerlistener。
*/
public update() {
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 i = 0; i < neighbors.length; i ++){
for (let i = 0; i < neighbors.length; i++) {
let neighbor = neighbors[i];
if (!collider.isTrigger && !neighbor.isTrigger)
continue;
if (collider.overlaps(neighbor)){
if (collider.overlaps(neighbor)) {
let pair = new Pair<Collider>(collider, neighbor);
let shouldReportTriggerEvent = !this._activeTriggerIntersections.contains(pair) &&
!this._previousTriggerIntersections.contains(pair);
if (shouldReportTriggerEvent)
this.notifyTriggerListeners(pair, true);
this._activeTriggerIntersections.push(pair);
}
}
}
ListPool.free(colliders);
this.checkForExitedColliders();
}
private checkForExitedColliders(){
let tempIntersections = [];
this._previousTriggerIntersections = this._previousTriggerIntersections.filter(value => {
for (let i = 0; i < this._activeTriggerIntersections.length; i ++){
if (value == this._activeTriggerIntersections[i]){
tempIntersections.push(value);
return true;
}
}
return false;
});
this._previousTriggerIntersections.forEach(pair => this.notifyTriggerListeners(pair, false));
this._previousTriggerIntersections.length = 0;
tempIntersections.forEach(value => this._previousTriggerIntersections.push(value));
this._activeTriggerIntersections.length = 0;
}
private notifyTriggerListeners(collisionPair: Pair<Collider>, isEntering: boolean) {
collisionPair.first.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){
if (isEntering){
this._tempTriggerList[i].onTriggerEnter(collisionPair.second, collisionPair.first);
} else {
this._tempTriggerList[i].onTriggerExit(collisionPair.second, collisionPair.first);
}
this._tempTriggerList.length = 0;
if (collisionPair.second.entity){
collisionPair.second.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){
if (isEntering){
this._tempTriggerList[i].onTriggerEnter(collisionPair.first, collisionPair.second);
} else {
this._tempTriggerList[i].onTriggerExit(collisionPair.first, collisionPair.second);
}
}
this._tempTriggerList.length = 0;
}
}
}
}

View File

@@ -1,4 +1,9 @@
class ShapeCollisions {
/**
* 检查两个多边形之间的碰撞
* @param first
* @param second
*/
public static polygonToPolygon(first: Polygon, second: Polygon) {
let result = new CollisionResult();
let isIntersecting = true;
@@ -56,6 +61,13 @@ class ShapeCollisions {
return result;
}
/**
* 计算[minA, maxA]和[minB, maxB]之间的距离。如果间隔重叠,距离是负的
* @param minA
* @param maxA
* @param minB
* @param maxB
*/
public static intervalDistance(minA: number, maxA: number, minB: number, maxB) {
if (minA < minB)
return minB - maxA;
@@ -63,6 +75,13 @@ class ShapeCollisions {
return minA - minB;
}
/**
* 计算一个多边形在一个轴上的投影,并返回一个[minmax]区间
* @param axis
* @param polygon
* @param min
* @param max
*/
public static getInterval(axis: Vector2, polygon: Polygon, min: number, max: number) {
let dot = Vector2.dot(polygon.points[0], axis);
min = max = dot;
@@ -79,6 +98,11 @@ class ShapeCollisions {
return { min: min, max: max };
}
/**
*
* @param circle
* @param polygon
*/
public static circleToPolygon(circle: Circle, polygon: Polygon) {
let result = new CollisionResult();
@@ -111,6 +135,11 @@ class ShapeCollisions {
return result;
}
/**
* 适用于圆心在方框内以及只与方框外圆心重叠的圆。
* @param circle
* @param box
*/
public static circleToBox(circle: Circle, box: Box): CollisionResult {
let result = new CollisionResult();
let closestPointOnBounds = box.bounds.getClosestPointOnRectangleBorderToPoint(circle.position).res;
@@ -139,6 +168,11 @@ class ShapeCollisions {
return null;
}
/**
*
* @param point
* @param circle
*/
public static pointToCircle(point: Vector2, circle: Circle) {
let result = new CollisionResult();
@@ -157,6 +191,12 @@ class ShapeCollisions {
return null;
}
/**
*
* @param lineA
* @param lineB
* @param closestTo
*/
public static closestPointOnLine(lineA: Vector2, lineB: Vector2, closestTo: Vector2) {
let v = Vector2.subtract(lineB, lineA);
let w = Vector2.subtract(closestTo, lineA);
@@ -166,6 +206,11 @@ class ShapeCollisions {
return Vector2.add(lineA, Vector2.multiply(v, new Vector2(t, t)));
}
/**
*
* @param point
* @param poly
*/
public static pointToPoly(point: Vector2, poly: Polygon) {
let result = new CollisionResult();
@@ -185,6 +230,11 @@ class ShapeCollisions {
return null;
}
/**
*
* @param first
* @param second
*/
public static circleToCircle(first: Circle, second: Circle){
let result = new CollisionResult();

View File

@@ -0,0 +1,54 @@
/**
* 可以用于列表池的简单类
*/
class ListPool {
private static readonly _objectQueue = [];
/**
* 预热缓存使用最大的cacheCount对象填充缓存
* @param cacheCount
*/
public static warmCache(cacheCount: number){
cacheCount -= this._objectQueue.length;
if (cacheCount > 0){
for (let i = 0; i < cacheCount; i ++){
this._objectQueue.unshift([]);
}
}
}
/**
* 将缓存修剪为cacheCount项目
* @param cacheCount
*/
public static trimCache(cacheCount){
while (cacheCount > this._objectQueue.length)
this._objectQueue.shift();
}
/**
* 清除缓存
*/
public static clearCache(){
this._objectQueue.length = 0;
}
/**
* 如果可以的话,从堆栈中弹出一个项
*/
public static obtain<T>(): Array<T>{
if (this._objectQueue.length > 0)
return this._objectQueue.shift();
return [];
}
/**
* 将项推回堆栈
* @param obj
*/
public static free<T>(obj: Array<T>){
this._objectQueue.unshift(obj);
obj.length = 0;
}
}

20
source/src/Utils/Pair.ts Normal file
View File

@@ -0,0 +1,20 @@
/**
* 用于管理一对对象的简单DTO
*/
class Pair<T> {
public first: T;
public second: T;
constructor(first: T, second: T){
this.first = first;
this.second = second;
}
public clear(){
this.first = this.second = null;
}
public equals(other: Pair<T>){
return this.first == other.first && this.second == other.second;
}
}