zoukankan      html  css  js  c++  java
  • 碰撞检测 (矩形、圆形、点、旋转、矩形框、像素)

    一、矩形碰撞

    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光照演示

    五、不规则图形和规则图形碰撞检测

  • 相关阅读:
    CF1324F Maximum White Subtree
    CF1204C Anna, Svyatoslav and Maps
    CF1187E Tree Painting
    CF1304E 1-Trees and Queries
    深入探究jvm之类装载器
    深入探究jvm之GC的算法及种类
    深入探究jvm之GC的参数调优
    spring源码解析之AOP原理
    spring注解扫描组件注册
    cas-client单点登录客户端拦截请求和忽略/排除不需要拦截的请求URL的问题
  • 原文地址:https://www.cnblogs.com/gamedaybyday/p/9414260.html
Copyright © 2011-2022 走看看