一、矩形碰撞
1. 使用rectangle的intersects判斷碰撞
let rectA:egret.Rectangle = this.red.getBounds(); let rectB:egret.Rectangle = this.blue.getBounds(); //獲得的rect不包含x,y位置 console.log(rectA); //x=0,y=0,width=200,height=200 console.log(rectB); //x=0,y=0,width=200,height=200 //必須加上方塊所在的x,y rectA.x += this.red.x; rectA.y += this.red.y; rectB.x += this.blue.x; rectB.y += this.blue.y; let startTime = egret.getTimer(); for(let i=0;i<1000;i++){ if(rectA.intersects(rectB)){ console.log("hit"); }else{ console.log("no hit"); } } console.log(egret.getTimer() - startTime); //檢測1000次,耗時215ms
下圖:no hit
下圖:hit
矩形旋轉后,還能正確判斷碰撞嗎?
下圖:no hit
下圖:no hit
下圖:hit
矩形旋轉后,並不能正確的判斷碰撞了。查看源代碼,可知並沒有計算rotation這樣的算法。
/** * 確定在 toIntersect 參數中指定的對象是否與此 Rectangle 對象相交。此方法檢查指定的 Rectangle * 對象的 x、y、width 和 height 屬性,以查看它是否與此 Rectangle 對象相交。 * @param toIntersect 要與此 Rectangle 對象比較的 Rectangle 對象。 * @returns 如果兩個矩形相交,返回true,否則返回false * @version Egret 2.4 * @platform Web,Native * @language zh_CN */ public intersects(toIntersect:Rectangle):boolean { return Math.max(this.x, toIntersect.x) <= Math.min(this.right, toIntersect.right) && Math.max(this.y, toIntersect.y) <= Math.min(this.bottom, toIntersect.bottom); }
所以intersects的碰撞檢測適用:
1. 用於矩形(未旋轉)
2. eui對象(才有right、bottom屬性)
3. 修改了錨點也能正常檢測
2. 自定義的矩形碰撞檢測
protected childrenCreated(){ let startTime = egret.getTimer(); for(let i=0;i<1000;i++){ if(this.checkRect(this.red, this.blue)){ console.log("hit"); }else{ console.log("no hit"); } } console.log(egret.getTimer() - startTime); //檢測1000次,耗時220ms } /** * 檢測碰撞矩形 * @objA 對象A * @objB 對象B
*/ public checkRect(objA: egret.DisplayObject,objB: egret.DisplayObject) { var x1 = objA.x - objA.anchorOffsetX; var y1 = objA.y - objA.anchorOffsetY; var x2 = objB.x - objB.anchorOffsetX; var y2 = objB.y - objB.anchorOffsetY; if(y1 > (y2 - objA.height) && y1 < (y2 + objB.height)) { if(x1 > (x2 - objA.width) && x1 < (x2 + objB.width)) { return true; } } return false; }
適用范圍:
1. 只要是矩形顯示對象就可以,對比intersects不要求必須是eui對象
2. 對於旋轉對象,同樣沒法碰撞檢測
3. 對象修改了錨點也能正確檢測
3. 旋轉后的圖形,也能正確碰撞。比如坦克大戰中,坦克和牆等地形的碰撞檢測方法
給坦克周圍增加碰撞點
然后用hitTestPoint方法去檢測碰撞點和矩形的碰撞。
這種方法,在主對象旋轉后,依附於這個對象的紅點的位置是會隨着旋轉變化的,這樣可以判斷旋轉對象的碰撞了。
注意:使用hitTestPoint時,將紅點的坐標使用localToGlobal或者其他方式轉成和需要碰撞檢測的物體同一坐標系。
物體objA,objA上有多個碰撞點,hitPointList就是碰撞點列表,上圖中的坦克紅點。
物體objB,需要檢測的和坦克碰撞的矩形,rect是objB的矩形框
//碰撞檢測 let rect = new egret.Rectangle(objB.x - objB.anchorOffsetX, objB.y - objB.anchorOffsetY, objB.width, objB.height); let hitPointList = objA.hitPointList; let len = hitPointList.length; let p:egret.Point = new egret.Point(); //遍歷碰撞點和矩形碰撞 for(let i=0;i<len;i++){ p = objA.localToGlobal(hitPointList[i].x, hitPointList[i].y); if(rect.containsPoint(p)){ console.log("hit"); break; } }
二、圓形碰撞
protected childrenCreated(){ let startTime = egret.getTimer(); for(let i=0;i<1000;i++){ if(this.checkCircle(this.red, this.blue, 100)){ console.log("hit"); }else{ console.log("no hit"); } } console.log(egret.getTimer() - startTime); //檢測1000次,耗時250ms } /** * 根據圓形的半徑,檢查圓形是否碰撞 * @ballA 圓形A * @ballB 圓形B * @radius 半徑 * @return 是否碰撞 */ public checkCircle(circleA:egret.DisplayObject, circleB:egret.DisplayObject, radius:number){ var pA:egret.Point = new egret.Point(circleA.x, circleA.y); var pB:egret.Point = new egret.Point(circleB.x, circleB.y); if(egret.Point.distance(pA, pB) <= radius*2){ return true; } return false; }
下圖:no hit
下圖:hit
適用:
1. 圓形碰撞
2. 錨點需另行計算
3. 錨點在中心的話,旋轉后也能正常碰撞檢測。
三、點碰撞檢測
protected childrenCreated(){ //不加這個,無法檢測 this.validateNow(); let startTime = egret.getTimer(); for(let i=0;i<1000;i++){ if(this.red.hitTestPoint(this.blue.x, this.blue.y, false)){ console.log("hit"); }else{ console.log("no hit"); } } console.log(egret.getTimer() - startTime); //檢測1000次,耗時260ms }
因為hitTestPoint第三個參數false,所以不是檢測像素,而是檢測邊框碰撞。所以藍點沒碰到圓,但是在圓的矩形框內,也算是hit。
下圖:hit
下圖:藍色點在紅色圓的矩形框范圍內
hitTestPoint第三個參數為true,檢測像素。非常耗時。檢測1000次,耗時2100ms。
下圖:no hit
下圖:hit 檢測1000次,耗時4000ms
四、兩個不規則圖形碰撞
五、不規則圖形和規則圖形碰撞檢測