碰撞檢測 (矩形、圓形、點、旋轉、矩形框、像素)


 

一、矩形碰撞

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

 

四、兩個不規則圖形碰撞

任意多邊形碰撞檢測及簡單2D光照演示

 

 

五、不規則圖形和規則圖形碰撞檢測

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM