@@ -7,7 +7,7 @@ module es {
|
|||||||
* 删除执行顺序
|
* 删除执行顺序
|
||||||
* - onRemovedFromEntity
|
* - onRemovedFromEntity
|
||||||
*/
|
*/
|
||||||
export abstract class Component {
|
export abstract class Component extends egret.HashObject {
|
||||||
/**
|
/**
|
||||||
* 此组件附加的实体
|
* 此组件附加的实体
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -3,55 +3,55 @@ declare interface Array<T> {
|
|||||||
* 获取满足表达式的数组元素索引
|
* 获取满足表达式的数组元素索引
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
findIndex(predicate: Function): number;
|
findIndex(predicate: (c: T)=>boolean): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否存在满足表达式的数组元素
|
* 是否存在满足表达式的数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
any(predicate: Function): boolean;
|
any(predicate: (c: T) => boolean): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的第一个或默认数组元素
|
* 获取满足表达式的第一个或默认数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
firstOrDefault(predicate: Function): T;
|
firstOrDefault(predicate: (c: T)=>boolean): T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的第一个数组元素
|
* 获取满足表达式的第一个数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
find(predicate: Function): T;
|
find(predicate: (c: T) => boolean): T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 筛选满足表达式的数组元素
|
* 筛选满足表达式的数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
where(predicate: Function): Array<T>;
|
where(predicate: (c: T) => boolean): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的数组元素的计数
|
* 获取满足表达式的数组元素的计数
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
count(predicate: Function): number;
|
count(predicate: (c: T) => boolean): number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取满足表达式的数组元素的数组
|
* 获取满足表达式的数组元素的数组
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
findAll(predicate: Function): Array<T>;
|
findAll(predicate: (c: T) => boolean): Array<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否有获取满足表达式的数组元素
|
* 是否有获取满足表达式的数组元素
|
||||||
* @param value 值
|
* @param value 值
|
||||||
*/
|
*/
|
||||||
contains(value): boolean;
|
contains(value: T): boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除满足表达式的数组元素
|
* 移除满足表达式的数组元素
|
||||||
* @param predicate 表达式
|
* @param predicate 表达式
|
||||||
*/
|
*/
|
||||||
removeAll(predicate: Function): void;
|
removeAll(predicate: (c: T) => boolean): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除数组元素
|
* 移除数组元素
|
||||||
@@ -63,14 +63,14 @@ declare interface Array<T> {
|
|||||||
* 移除特定索引数组元素
|
* 移除特定索引数组元素
|
||||||
* @param index 索引
|
* @param index 索引
|
||||||
*/
|
*/
|
||||||
removeAt(index): void;
|
removeAt(index: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 移除范围数组元素
|
* 移除范围数组元素
|
||||||
* @param index 开始索引
|
* @param index 开始索引
|
||||||
* @param count 删除的个数
|
* @param count 删除的个数
|
||||||
*/
|
*/
|
||||||
removeRange(index, count): void;
|
removeRange(index: number, count: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取通过选择器转换的数组
|
* 获取通过选择器转换的数组
|
||||||
@@ -102,7 +102,7 @@ declare interface Array<T> {
|
|||||||
* 求和
|
* 求和
|
||||||
* @param selector 选择器
|
* @param selector 选择器
|
||||||
*/
|
*/
|
||||||
sum(selector);
|
sum(selector: Function): number;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array.prototype.findIndex = function (predicate) {
|
Array.prototype.findIndex = function (predicate) {
|
||||||
@@ -189,6 +189,11 @@ Array.prototype.findAll = function (predicate) {
|
|||||||
Array.prototype.contains = function (value) {
|
Array.prototype.contains = function (value) {
|
||||||
function contains(array, value) {
|
function contains(array, value) {
|
||||||
for (let i = 0, len = array.length; i < len; i++) {
|
for (let i = 0, len = array.length; i < len; i++) {
|
||||||
|
if (array[i] instanceof egret.HashObject && value instanceof egret.HashObject){
|
||||||
|
if ((array[i] as egret.HashObject).hashCode == (value as egret.HashObject).hashCode)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (array[i] == value) {
|
if (array[i] == value) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,51 @@ module es {
|
|||||||
this.top < value.bottom;
|
this.top < value.bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public rayIntersects(ray: Ray2D): number{
|
||||||
|
let distance = 0;
|
||||||
|
let maxValue = Number.MAX_VALUE;
|
||||||
|
|
||||||
|
if (Math.abs(ray.direction.x) < 1E-06){
|
||||||
|
if ((ray.start.x < this.x) || (ray.start.x > this.x + this.width))
|
||||||
|
return distance;
|
||||||
|
}else{
|
||||||
|
let num11 = 1 / ray.direction.x;
|
||||||
|
let num8 = (this.x - ray.start.x) * num11;
|
||||||
|
let num7 = (this.x + this.width - ray.start.x) * num11;
|
||||||
|
if (num8 > num7){
|
||||||
|
let num14 = num8;
|
||||||
|
num8 = num7;
|
||||||
|
num7 = num14;
|
||||||
|
}
|
||||||
|
|
||||||
|
distance = Math.max(num8, distance);
|
||||||
|
maxValue = Math.min(num7, maxValue);
|
||||||
|
if (distance > maxValue)
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(ray.direction.y) < 1E-06){
|
||||||
|
if ((ray.start.y < this.y) || (ray.start.y > this.y + this.height))
|
||||||
|
return distance;
|
||||||
|
}else{
|
||||||
|
let num10 = 1 / ray.direction.y;
|
||||||
|
let num6 = (this.y - ray.start.y) * num10;
|
||||||
|
let num5 = (this.y + this.height - ray.start.y) * num10;
|
||||||
|
if (num6 > num5){
|
||||||
|
let num13 = num6;
|
||||||
|
num6 = num5;
|
||||||
|
num5 = num13;
|
||||||
|
}
|
||||||
|
|
||||||
|
distance = Math.max(num6, distance);
|
||||||
|
maxValue = Math.max(num5, maxValue);
|
||||||
|
if (distance > maxValue)
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所提供的矩形是否在此矩形的边界内
|
* 获取所提供的矩形是否在此矩形的边界内
|
||||||
* @param value
|
* @param value
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ module es {
|
|||||||
/** 接受layerMask的所有方法的默认值 */
|
/** 接受layerMask的所有方法的默认值 */
|
||||||
public static readonly allLayers: number = -1;
|
public static readonly allLayers: number = -1;
|
||||||
private static _spatialHash: SpatialHash;
|
private static _spatialHash: SpatialHash;
|
||||||
|
/**
|
||||||
|
* raycast是否检测配置为触发器的碰撞器
|
||||||
|
*/
|
||||||
|
public static raycastsHitTriggers: boolean = false;
|
||||||
|
|
||||||
public static reset() {
|
public static reset() {
|
||||||
this._spatialHash = new SpatialHash(this.spatialHashCellSize);
|
this._spatialHash = new SpatialHash(this.spatialHashCellSize);
|
||||||
|
|||||||
16
source/src/Physics/Ray2D.ts
Normal file
16
source/src/Physics/Ray2D.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
module es {
|
||||||
|
/**
|
||||||
|
* 不是真正的射线(射线只有开始和方向),作为一条线和射线。
|
||||||
|
*/
|
||||||
|
export class Ray2D {
|
||||||
|
public start: Vector2;
|
||||||
|
public end: Vector2;
|
||||||
|
public direction: Vector2;
|
||||||
|
|
||||||
|
constructor(position: Vector2, end: Vector2){
|
||||||
|
this.start = position;
|
||||||
|
this.end = end;
|
||||||
|
this.direction = Vector2.subtract(this.end, this.start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
source/src/Physics/Shapes/RealtimeCollisions.ts
Normal file
48
source/src/Physics/Shapes/RealtimeCollisions.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
module es {
|
||||||
|
export class RealtimeCollisions {
|
||||||
|
public static intersectMovingCircleToBox(s: Circle, b: Box, movement: Vector2): number {
|
||||||
|
// 计算用球面半径r inflate b得到的AABB
|
||||||
|
let e = b.bounds;
|
||||||
|
e.inflate(s.radius, s.radius);
|
||||||
|
|
||||||
|
// 射线与展开矩形e相交。如果射线错过了e,则退出不相交,否则得到相交点p和时间t
|
||||||
|
let ray = new Ray2D(Vector2.subtract(s.position, movement), s.position);
|
||||||
|
let time = e.rayIntersects(ray);
|
||||||
|
if (time > 1)
|
||||||
|
return time;
|
||||||
|
|
||||||
|
// 求交点
|
||||||
|
let point = Vector2.add(ray.start, Vector2.add(ray.direction, new Vector2(time)));
|
||||||
|
|
||||||
|
// 计算b的最小面和最大面p的交点在哪个面之外。注意,u和v不能有相同的位集,它们之间必须至少有一个位集。
|
||||||
|
let u, v = 0;
|
||||||
|
if (point.x < b.bounds.left)
|
||||||
|
u |= 1;
|
||||||
|
if (point.x > b.bounds.right)
|
||||||
|
v |= 1;
|
||||||
|
if (point.y < b.bounds.top)
|
||||||
|
u |= 2;
|
||||||
|
if (point.y > b.bounds.bottom)
|
||||||
|
v |= 2;
|
||||||
|
|
||||||
|
// 将所有位集合成位掩码(注意u + v == u | v)
|
||||||
|
let m = u + v;
|
||||||
|
|
||||||
|
// 如果所有的3位都被设置,那么点在一个顶点区域
|
||||||
|
if (m == 3){
|
||||||
|
// 现在必须相交的部分,如果一个或多个击中对胶囊的两边会合在斜面和返回的最佳时间
|
||||||
|
// TODO: 需要实现这个
|
||||||
|
console.log(`m == 3. corner ${Time.frameCount}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果m中只设置了一个位,那么点在一个面区域
|
||||||
|
if ((m & (m - 1)) == 0){
|
||||||
|
// 什么也不做。从扩展矩形交集的时间是正确的时间
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点在边缘区域上。与边缘相交。
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,9 @@
|
|||||||
module es {
|
module es {
|
||||||
|
/**
|
||||||
|
* 各种形状的碰撞例程
|
||||||
|
* 大多数人都希望第一个形状位于第二个形状的空间内(即shape1)
|
||||||
|
* pos应该设置为shape1。pos - shape2.pos)。
|
||||||
|
*/
|
||||||
export class ShapeCollisions {
|
export class ShapeCollisions {
|
||||||
/**
|
/**
|
||||||
* 检查两个多边形之间的碰撞
|
* 检查两个多边形之间的碰撞
|
||||||
@@ -306,5 +311,45 @@ module es {
|
|||||||
|
|
||||||
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y)
|
return new Rectangle(topLeft.x, topLeft.y, fullSize.x, fullSize.y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用second检查被deltaMovement移动的框的结果
|
||||||
|
* @param first
|
||||||
|
* @param second
|
||||||
|
* @param movement
|
||||||
|
* @param hit
|
||||||
|
*/
|
||||||
|
public static boxToBoxCast(first: Box, second: Box, movement: Vector2, hit: RaycastHit): boolean{
|
||||||
|
// 首先,我们检查是否有重叠。如果有重叠,我们就不做扫描测试
|
||||||
|
let minkowskiDiff = this.minkowskiDifference(first, second);
|
||||||
|
if (minkowskiDiff.contains(0, 0)){
|
||||||
|
// 计算MTV。如果它是零,我们就可以称它为非碰撞
|
||||||
|
let mtv = minkowskiDiff.getClosestPointOnBoundsToOrigin();
|
||||||
|
if (mtv.equals(Vector2.zero))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
hit.normal = new Vector2(-mtv.x);
|
||||||
|
hit.normal = hit.normal.normalize();
|
||||||
|
hit.distance = 0;
|
||||||
|
hit.fraction = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
// 射线投射移动矢量
|
||||||
|
let ray = new Ray2D(Vector2.zero, new Vector2(-movement.x));
|
||||||
|
let fraction: number = minkowskiDiff.rayIntersects(ray);
|
||||||
|
if (fraction <= 1){
|
||||||
|
hit.fraction = fraction;
|
||||||
|
hit.distance = movement.length() * fraction;
|
||||||
|
hit.normal = new Vector2(-movement.x);
|
||||||
|
hit.normal = hit.normal.normalize();
|
||||||
|
hit.centroid = Vector2.add(first.bounds.center, Vector2.multiply(movement, new Vector2(fraction)));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ module es {
|
|||||||
for (let x = p1.x; x <= p2.x; x++) {
|
for (let x = p1.x; x <= p2.x; x++) {
|
||||||
for (let y = p1.y; y <= p2.y; y++) {
|
for (let y = p1.y; y <= p2.y; y++) {
|
||||||
// 如果没有单元格,我们需要创建它
|
// 如果没有单元格,我们需要创建它
|
||||||
let c = this.cellAtPosition(x, y, true);
|
let c: Collider[] = this.cellAtPosition(x, y, true);
|
||||||
if (c.indexOf(collider) == -1)
|
if (!c.firstOrDefault(c => c.hashCode == collider.hashCode))
|
||||||
c.push(collider);
|
c.push(collider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +134,7 @@ module es {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (bounds.intersects(collider.bounds)) {
|
if (bounds.intersects(collider.bounds)) {
|
||||||
if (this._tempHashSet.indexOf(collider) == -1)
|
if (!this._tempHashSet.firstOrDefault(c => c.hashCode == collider.hashCode))
|
||||||
this._tempHashSet.push(collider);
|
this._tempHashSet.push(collider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,7 +202,7 @@ module es {
|
|||||||
* @param y
|
* @param y
|
||||||
* @param createCellIfEmpty
|
* @param createCellIfEmpty
|
||||||
*/
|
*/
|
||||||
private cellAtPosition(x: number, y: number, createCellIfEmpty: boolean = false) {
|
private cellAtPosition(x: number, y: number, createCellIfEmpty: boolean = false): Collider[] {
|
||||||
let cell: Collider[] = this._cellDict.tryGetValue(x, y);
|
let cell: Collider[] = this._cellDict.tryGetValue(x, y);
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
if (createCellIfEmpty) {
|
if (createCellIfEmpty) {
|
||||||
@@ -262,6 +262,55 @@ module es {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class RaycastResultParser {
|
export class RaycastResultParser {
|
||||||
|
public hitCounter: number;
|
||||||
|
public static compareRaycastHits = (a: RaycastHit, b: RaycastHit) => {
|
||||||
|
return a.distance - b.distance;
|
||||||
|
};
|
||||||
|
|
||||||
|
public _hits: RaycastHit[];
|
||||||
|
public _tempHit: RaycastHit;
|
||||||
|
public _checkedColliders: Collider[] = [];
|
||||||
|
public _cellHits: RaycastHit[] = [];
|
||||||
|
public _ray: Ray2D;
|
||||||
|
public _layerMask: number;
|
||||||
|
|
||||||
|
public start(ray: Ray2D, hits: RaycastHit[], layerMask: number){
|
||||||
|
this._ray = ray;
|
||||||
|
this._hits = hits;
|
||||||
|
this._layerMask = layerMask;
|
||||||
|
this.hitCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果hits数组被填充,返回true。单元格不能为空!
|
||||||
|
* @param cellX
|
||||||
|
* @param cellY
|
||||||
|
* @param cell
|
||||||
|
*/
|
||||||
|
public checkRayIntersection(cellX: number, cellY: number, cell: Collider[]): boolean{
|
||||||
|
let fraction: number;
|
||||||
|
for (let i = 0; i < cell.length; i ++) {
|
||||||
|
let potential = cell[i];
|
||||||
|
|
||||||
|
// 管理我们已经处理过的碰撞器
|
||||||
|
if (this._checkedColliders.contains(potential))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this._checkedColliders.push(potential);
|
||||||
|
// 只有当我们被设置为这样做时才会点击触发器
|
||||||
|
if (potential.isTrigger && !Physics.raycastsHitTriggers)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 确保碰撞器在图层蒙版上
|
||||||
|
if (!Flags.isFlagSet(this._layerMask, potential.physicsLayer))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// TODO: rayIntersects的性能够吗?需要测试它。Collisions.rectToLine可能更快
|
||||||
|
// TODO: 如果边界检查返回更多数据,我们就不需要为BoxCollider检查做任何事情
|
||||||
|
// 在做形状测试之前先做一个边界检查
|
||||||
|
let colliderBounds = potential.bounds;
|
||||||
|
if (colliderBounds.)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user