OBB碰撞检测,坐标点逆时针
class OBBTest extends egret.DisplayObjectContainer { private obb1:OBB; private obb2:OBB; private points1:Array<egret.Point>; private points2:Array<egret.Point>; private sprite1:egret.Sprite; private sprite2:egret.Sprite; private resPoint:egret.Point = new egret.Point(); constructor() { super(); this.touchEnabled = true; var stage = egret.MainContext.instance.stage; stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.onTouchBegin, this); stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.onTouchMove, this); stage.addEventListener(egret.TouchEvent.TOUCH_END, this.onTouchEnd, this); this.points1 = [new egret.Point(0,0),new egret.Point(100,200),new egret.Point(300,300),new egret.Point(300,100),new egret.Point(0,0)]; this.sprite1 = this.drawSprite(this.points1); this.addChild(this.sprite1); this.sprite1.x = 100; this.sprite1.y = 100; this.points2 = [new egret.Point(0,0),new egret.Point(100,200),new egret.Point(300,300),new egret.Point(300,100),new egret.Point(0,0)]; this.sprite2 = this.drawSprite(this.points2); this.addChild(this.sprite2); this.sprite2.x = 100; this.sprite2.y = 400; //创建两obb盒子 this.obb1 = new OBB(); this.obb2 = new OBB(); egret.startTick(this.onEnterFrame, this); } private pt:egret.Point = new egret.Point(0,0); private onEnterFrame():boolean { for (var i = 0; i < this.points1.length; i++) { var point1:egret.Point = this.points1[i]; this.sprite1.localToGlobal(point1.x, point1.y, this.pt); this.obb1.setVertex(i, this.pt.x, this.pt.y); } for (var j = 0; j < this.points2.length; j++) { var point2:egret.Point = this.points2[j]; this.sprite2.localToGlobal(point2.x, point2.y, this.pt); this.obb2.setVertex(j, this.pt.x, this.pt.y); } this.sprite1.visible = !this.obb1.isCollidWithOBB(this.obb2); return false; } private drawSprite(points:Array<egret.Point>):egret.Sprite { var startPoint:egret.Point = points[0]; var sprite = new egret.Sprite(); sprite.graphics.clear(); sprite.graphics.beginFill( 0xffffff, 0.5 ); sprite.graphics.moveTo( startPoint.x, startPoint.y ); for (var i = 1; i < points.length ; i++) { var point = points[i]; sprite.graphics.lineTo( point.x, point.y ); } sprite.graphics.endFill(); return sprite; } private onTouchBegin(evt:egret.TouchEvent):void { var posX = evt.stageX; var posY = evt.stageY; this.sprite2.x = posX; this.sprite2.y = posY; } private onTouchMove(evt:egret.TouchEvent):void { var posX = evt.stageX; var posY = evt.stageY; this.sprite2.x = posX; this.sprite2.y = posY; } private onTouchEnd(evt:egret.TouchEvent):void { var posX = evt.stageX; var posY = evt.stageY; this.sprite2.x = posX; this.sprite2.y = posY; } }
/** * 投影判断 */ class Projection { private min:number = 0; private max:number = 0; constructor(min, max) { this.min = min; this.max = max; } public getMin(){ return this.min; } public getMax(){ return this.max; } /** * 判断是否叠加 */ public overlap(proj:Projection):boolean { if(this.min > proj.getMax()) return false; if(this.max < proj.getMin()) return false; return true; } };
class OBB { private pList:Array<any> = [] //保存盒子顶点数 constructor() { this.pList = []; } public getVertex(idx):egret.Point { if (idx >= this.pList.length) { return null; } return this.pList[idx]; }; public setVertex(idx:number, x:number, y:number):void { if (!this.pList[idx]) { this.pList[idx] = new egret.Point(0, 0); } this.pList[idx].x = x; this.pList[idx].y = y; } /** * 计算分离轴 * 如果边向量为(x,y),那么法向量为(-y,x),你也可以设置为(y,-x)。结果没有什么变化。 */ public getAxies():Array<egret.Point> { var axies = []; var len = this.pList.length; var pOut = new egret.Point(0,0); for(var i = 0; i < len; i++) { var startPoint:egret.Point = this.pList[i]; var endPoint:egret.Point = this.pList[(i + 1) % len]; var point = startPoint.subtract(endPoint); var length = Math.sqrt(point.x * point.x + point.y * point.y); pOut.x = point.x / length; pOut.y = point.y / length; axies[i] = new egret.Point(); axies[i].x = -pOut.y ; axies[i].y = pOut.x ; } return axies; } /** * 计算投影 * 计算出一个投影线条 * 只是保存了两个float形的数据,分别表示OBB盒在分离轴上投影的最小值和最大值 */ public getProjection(axies:egret.Point):Projection { var min = this.pList[0].x * axies.x + this.pList[0].y * axies.y; var max = min ; var len = this.pList.length; for (var i = 1; i < len; i++) { var temp = this.pList[i].x * axies.x + this.pList[i].y * axies.y; if (temp > max) { max = temp; } else if (temp < min) { min = temp; } }// end for return new Projection(min, max); } //对传递进来的OBB判断是否与调用这个方法的OBB发生了交叉 public isCollidWithOBB(obb:OBB):boolean { //获取分离轴 var axies1 = this.getAxies(); var axies2 = obb.getAxies(); var p1:Projection = null; var p2:Projection = null; //Check for overlap for all of the axies for(var i = 0; i < axies1.length; i++) { p1 = this.getProjection(axies1[i]); p2 = obb.getProjection(axies1[i]); if(!p1.overlap(p2)) { return false ; } } for(var j = 0; j < axies2.length; j ++) { p1 = this.getProjection(axies2[j]); p2 = obb.getProjection(axies2[j]); if(!p1.overlap(p2)) { return false ; } } return true ; } }
测试,在Main中添加
var obb = new OBBTest(); this.addChild(obb);