zoukankan      html  css  js  c++  java
  • Android碰撞检测——多矩形检查

      在之前说过,像素检测是最精确的一种方式,但是一般为了性能方面的考虑,因为很少用到,但是游戏中很少会有这种纯粹的圆或矩形做检测,这个时候我们就会考虑用多矩形的方式来做检测。

      多矩形的原理是:将一个物体A分解成多个矩形组成A组,将另外一个物体B分解成多个矩形组成B组,然后通过A组中的矩形和B组中的矩形是否发生了碰撞就可得知物体A与物体B是否发生了碰撞。

    /**
         * 
         * @param rectArray
         *            物体1的数组
         * @param rect2Array
         *            物体2的数组
         * @param rectX1
         * @param rectY1
         * @param rectX2
         * @param rectY2
         * @return
         */
        public boolean CheckRectCollsion(Rect[] rectArray, Rect[] rect2Array,
                int rectX1, int rectY1, int rectX2, int rectY2) {
            Rect rect = null;
            Rect rect2 = null;
            for (int i = 0; i < rectArray.length; i++) {
                // 依次取出第一个矩形数组的每个矩形实例
                rect = rectArray[i];
                // 获取到第一个矩形数组中每个矩形元素的属性值
                int x1 = rect.left + rectX1;
                int y1 = rect.top + rectY1;
                int w1 = rect.right - rect.left;
                int h1 = rect.bottom - rect.top;
                for (int j = 0; j < rect2Array.length; j++) {
                    // 依次取出第二个矩形数组的每个矩形实例
                    rect2 = rect2Array[j];
                    // 获取到第二个矩形数组中每个矩形元素的属性值
                    int x2 = rect2.left + rectX2;
                    int y2 = rect2.top + rectY2;
                    int w2 = rect2.right - rect2.left;
                    int h2 = rect2.bottom - rect2.top;
                    // 进行循环遍历两个矩形碰撞数组所有元素之间的位置关系
                    if (x1 >= x2 && x1 >= x2 + w2) {
                    } else if (x1 <= x2 && x1 + w1 <= x2) {
                    } else if (y1 >= y2 && y1 >= y2 + h2) {
                    } else if (y1 <= y2 && y1 + h1 <= y2) {
                    } else {
                        // 只要有一个碰撞矩形数组与另一碰撞矩形数组发生碰撞则认为碰撞
                        return true;
                    }
                }
            }
            return false;
        }

     下面来一个完整的例子:

    public class MoreRectView extends SurfaceView implements Callback, Runnable {
    
        int sleeptime = 100;
        private SurfaceHolder surfaceHolder;
        private Paint paint;
        private Thread thread;
        private boolean flag;
        // 定义两个矩形图形的宽高坐标
        private int rectX1 = 10, rectY1 = 10, rectW1 = 40, rectH1 = 40;
        private int rectX2 = 100, rectY2 = 110, rectW2 = 40, rectH2 = 40;
        // 便于观察是否发生了碰撞设置一个标识位
        private boolean isCollsion;
        // 定义第一个矩形的矩形碰撞数组
        private Rect clipRect1 = new Rect(0, 0, 15, 15);
        private Rect clipRect2 = new Rect(rectW1 - 15, rectH1 - 15, rectW1, rectH1);
        private Rect[] arrayRect1 = new Rect[] { clipRect1, clipRect2 };
        // 定义第二个矩形的矩形碰撞数组
        private Rect clipRect3 = new Rect(0, 0, 15, 15);
        private Rect clipRect4 = new Rect(rectW2 - 15, rectH2 - 15, rectW2, rectH2);
        private Rect[] arrayRect2 = new Rect[] { clipRect3, clipRect4 };
    
        public MoreRectView(Context context) {
            super(context);
            surfaceHolder = this.getHolder();
            surfaceHolder.addCallback(this);
            paint = new Paint();
            paint.setColor(Color.WHITE);
            paint.setAntiAlias(true);
            setFocusable(true); // 设置焦点
        }
    
        /**
         * 游戏绘图
         */
        public void draw(Canvas canvas) {
            canvas.drawColor(Color.BLACK);
            paint.setColor(Color.WHITE);
            paint.setStyle(Style.FILL);
            if (isCollsion) {
                paint.setTextSize(20);
                canvas.drawText("碰撞了!", 0, 30, paint);
            }
            // 绘制两个矩形
            canvas.drawRect(rectX1, rectY1, rectX1 + rectW1, rectY1 + rectH1, paint);
            canvas.drawRect(rectX2, rectY2, rectX2 + rectW2, rectY2 + rectH2, paint);
            // ---绘制碰撞区域使用非填充,并设置画笔颜色白色
            paint.setStyle(Style.STROKE);
            paint.setColor(Color.RED);
            // 绘制第一个矩形的所有矩形碰撞区域
            for (int i = 0; i < arrayRect1.length; i++) {
                canvas.drawRect(arrayRect1[i].left + this.rectX1, arrayRect1[i].top
                        + this.rectY1, arrayRect1[i].right + this.rectX1,
                        arrayRect1[i].bottom + this.rectY1, paint);
            }
            // 绘制第二个矩形的所有矩形碰撞区域
            for (int i = 0; i < arrayRect2.length; i++) {
                canvas.drawRect(arrayRect2[i].left + this.rectX2, arrayRect2[i].top
                        + this.rectY2, arrayRect2[i].right + this.rectX2,
                        arrayRect2[i].bottom + rectY2, paint);
            }
        }
    
        @Override
        public void run() {
            Canvas canvas = null;
            while (flag) {
                try {
                    canvas = surfaceHolder.lockCanvas();
                    synchronized (canvas) {
                        draw(canvas);
                    }
                } catch (Exception e) {
                    Log.e("collsion", e.getMessage());
                } finally {
                    if (canvas != null)
                        surfaceHolder.unlockCanvasAndPost(canvas);
                }
                try {
                    Thread.sleep(sleeptime);
                } catch (Exception e) {
                    Log.e("collsion", e.getMessage());
                }
            }
        }
    
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            flag = true;
            // 实例线程
            thread = new Thread(this);
            if (!thread.isAlive()) {
                // 启动线程
                thread.start();
            }
        }
    
        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {
    
        }
    
        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            flag = false;
            thread = null;
        }
    
        /**
         * 触屏事件监听
         */
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // 让矩形1随着触屏位置移动
            rectX1 = (int) event.getX() - rectW1 / 2;
            rectY1 = (int) event.getY() - rectH1 / 2;
            if (CheckRectCollsion(arrayRect1, arrayRect2, rectX1, rectY1, rectX2,
                    rectY2)) {
                isCollsion = true;
            } else {
                isCollsion = false;
            }
            return true;
        }
    
        /**
         * 
         * @param rectArray
         *            物体1的数组
         * @param rect2Array
         *            物体2的数组
         * @param rectX1
         * @param rectY1
         * @param rectX2
         * @param rectY2
         * @return
         */
        public boolean CheckRectCollsion(Rect[] rectArray, Rect[] rect2Array,
                int rectX1, int rectY1, int rectX2, int rectY2) {
            Rect rect = null;
            Rect rect2 = null;
            for (int i = 0; i < rectArray.length; i++) {
                // 依次取出第一个矩形数组的每个矩形实例
                rect = rectArray[i];
                // 获取到第一个矩形数组中每个矩形元素的属性值
                int x1 = rect.left + rectX1;
                int y1 = rect.top + rectY1;
                int w1 = rect.right - rect.left;
                int h1 = rect.bottom - rect.top;
                for (int j = 0; j < rect2Array.length; j++) {
                    // 依次取出第二个矩形数组的每个矩形实例
                    rect2 = rect2Array[j];
                    // 获取到第二个矩形数组中每个矩形元素的属性值
                    int x2 = rect2.left + rectX2;
                    int y2 = rect2.top + rectY2;
                    int w2 = rect2.right - rect2.left;
                    int h2 = rect2.bottom - rect2.top;
                    // 进行循环遍历两个矩形碰撞数组所有元素之间的位置关系
                    if (x1 >= x2 && x1 >= x2 + w2) {
                    } else if (x1 <= x2 && x1 + w1 <= x2) {
                    } else if (y1 >= y2 && y1 >= y2 + h2) {
                    } else if (y1 <= y2 && y1 + h1 <= y2) {
                    } else {
                        // 只要有一个碰撞矩形数组与另一碰撞矩形数组发生碰撞则认为碰撞
                        return true;
                    }
                }
            }
            return false;
        }
    }
  • 相关阅读:
    刷题94—树(一)
    刷题93—动态规划(十)
    刷题92—动态规划(九)
    刷题91—动态规划(八)
    android Q build 变化
    ubuntu下解压rar文件
    Android PAI (PlayAutoInstall)预装APK 功能
    MTK Android O1平台预置apk
    预置第三方apk到MTK项目相关问题总结
    Android预置Apk方法
  • 原文地址:https://www.cnblogs.com/cindyOne/p/2996750.html
Copyright © 2011-2022 走看看