`
wo_deqing
  • 浏览: 60502 次
文章分类
社区版块
存档分类
最新评论

android 碰撞检测

 
阅读更多
Region是一个类,这个类比较常用的方法就是用于判断一个点是否在矩形区域内,其方法是使是Regions类中的contains(int x, int y)函数创建实例:RegionCollsion
项目运行效果:

1.jpg


package com.rectCollsion;
  
 
import android.content.Context;
  
import android.graphics.Canvas;
  
import android.graphics.Color;
  
import android.graphics.Paint;
  
import android.graphics.Paint.Style;
  
import android.graphics.Rect;
  
import android.view.KeyEvent;
  
import android.view.MotionEvent;
  
import android.view.SurfaceHolder;
  
import android.view.SurfaceHolder.Callback;
  
import android.view.SurfaceView;
  
 
public class MySurfaceView extends SurfaceView implements Callback,Runnable{
  
        //用于控制SurfaceView
  
        private SurfaceHolder sfh;
  
        //声明一个画笔
  
        private Paint paint;
  
        //声明一个线程
  
        private Thread th;
  
        //线程消亡的标志位
  
        private boolean flag;
  
        //声明一个画布
  
        private Canvas canvas;
  
        //声明屏幕的宽高
  
        private int screenW,screenH;
  
        //定义两个矩形的宽高坐标
  
        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};
  
         
  
        /**
  
         * SurfaceView初始化函数
  
         */
  
        public MySurfaceView(Context context){
  
                super(context);
  
                //实例SurfaceHolder
  
                sfh = this.getHolder();
  
                //为SurfaceView添加状态监听
  
                sfh.addCallback(this);
  
                //实例一个画笔
  
                paint = new Paint();
  
                //设置画笔颜色为白色
  
                paint.setColor(Color.WHITE);
  
                //设置焦点
  
                setFocusable(true);
  
        }
  
        @Override
  
        public void surfaceCreated(SurfaceHolder holder) {
  
                // TODO Auto-generated method stub
  
                screenW = this.getWidth();
  
                screenH = this.getHeight();
  
                flag = true;
  
                //实例线程
  
                th = new Thread(this);
  
                //启动线程
  
                th.start();
  
        }
  
         
  
         
  
        /**
  
         * 游戏绘图
  
         */
  
        public void myDraw(){
  
                try {
  
                        canvas = sfh.lockCanvas();
  
                        if(canvas != null){
  
                                //刷屏
  
                                canvas.drawColor(Color.BLACK);
  
                                //判断是否发生了碰撞
  
                                if(isCollsion){//发生碰撞
  
                                        paint.setColor(Color.RED);
  
                                        paint.setTextSize(20);
  
                                        canvas.drawText("Collision!", 0, 30, paint);
  
                                         
                                } else{//没发生碰撞
  
                                        paint.setColor(Color.WHITE);
  
                                }
  
                                //绘制两个矩形
  
                                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.WHITE);
  
                                //---绘制第一个矩形所有矩形碰撞区域
  
                                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 + this.rectY2, paint);
  
                                }
  
                                 
  
                        }
  
                }catch(Exception e){
  
                         
  
                }finally{
  
                        if(canvas != null)
  
                                sfh.unlockCanvasAndPost(canvas);
  
                }
  
        }
  
        /**
  
         * 触屏事件监听
  
         */
  
        @Override
  
        public boolean onTouchEvent(MotionEvent event) {
  
                // TODO Auto-generated method stub
  
                //让矩形1随着触屏位置移动(触屏点设为此矩形的中心点)
  
                rectX1 = (int) event.getX() - rectW1/2;
  
                rectY1 = (int) event.getY() - rectH1/2;
  
                //当矩形之间发生碰撞
  
                if(isCollsionWithRect(arrayRect1, arrayRect2)){
  
                        isCollsion = true;//设置标志位为真
  
                        //当矩形之间没有发生碰撞
  
                }else{
  
                        isCollsion = false; //设置标志位为假
  
                }
  
                return true;
  
        }
  
        /**
  
         * 矩形碰撞的函数
  
         * @param left 表示矩形左上角坐标的X坐标
  
         * @param top  表示矩形左上角坐标Y坐标
  
         * @param right 表示矩形右下角坐标X坐标
  
         * @param buttom 表示矩形右下角坐标Y坐标
  
         */
  
        public boolean isCollsionWithRect(Rect[] rectArray, Rect[] rect2Array){
  
                Rect rect = null;
  
                Rect rect2 = null;
  
                for(int i = 0; i < rectArray.length; i++){
  
                        //依次取出第一个矩形数组的每个矩形实例
  
                        rect = rectArray[i];
  
                        //获取到第一个矩形数组中每个矩形元素的属性值
  
                        int x1 = rect.left + this.rectX1;
  
                        int y1 = rect.top + this.rectY1;
  
                        int w1 = rect.right - rect.left;
  
                        int h1 = rect.bottom - rect.top;
  
                        for(int j = 0; j < rect2Array.length; j++){
  
                                //依次取出第二个矩形数组的每个矩形实例
  
                                rect2 = rect2Array[i];
  
                                //获取到第二个矩形数组中每个矩形的属性值
  
                                int x2 = rect2.left + this.rectX1;
  
                                int y2 = rect2.top + this.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;
  
        }
  
 
         
  
        /**
  
         * 按键事件监听
  
         */
  
        @Override
  
        public boolean onKeyDown(int keyCode, KeyEvent event) {
  
                // TODO Auto-generated method stub
  
                return super.onKeyDown(keyCode, event);
  
        }
  
        /**
  
         * 游戏逻辑
  
         */
  
        private void logic(){
  
                 
        }
  
        @Override
  
        public void run() {
  
                // TODO Auto-generated method stub
  
                while(flag){
  
                        long start = System.currentTimeMillis();
  
                        myDraw();
  
                        logic();
  
                        long end = System.currentTimeMillis();
  
                        try {
  
                                if (end - start < 50) {
  
                                        Thread.sleep(50 - (end - start));
  
                                }
  
                        } catch(InterruptedException e){
  
                                e.printStackTrace();
  
                        }
  
                }
  
                 
        }
  
        /**
  
         * Surfaceview视图状态发生改变,响应此函数
  
         */
  
        @Override
  
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
  
                        int height) {
  
                // TODO Auto-generated method stub
  
                 
        }
  
        /**
  
         * Surfaceview视图消亡,响应此函数
  
         */
  
        @Override
  
        public void surfaceDestroyed(SurfaceHolder holder) {
  
                // TODO Auto-generated method stub
  
                 
        }
  
}


矩形碰撞就是利用两个矩形之间的位置关系来进行判断,如果一个矩形的像素在另外一个矩形之中,或者之上都可以认为这两个矩形发生了碰撞。其实两个矩形不发生碰撞的情况就只有四种,其他情况就是发生碰撞了
创建实例:RectCollion, 游戏框架为SurfaceView
项目效果图:

1.jpg

2.jpg
MySurfaceView.java


package com.rectCollsion;
  
import android.content.Context;
  
import android.graphics.Canvas;
  
import android.graphics.Color;
  
import android.graphics.Paint;
  
import android.view.KeyEvent;
  
import android.view.MotionEvent;
  
import android.view.SurfaceHolder;
  
import android.view.SurfaceHolder.Callback;
  
import android.view.SurfaceView;
  
public class MySurfaceView extends SurfaceView implements Callback,Runnable{
  
//用于控制SurfaceView
  
private SurfaceHolder sfh;
  
//声明一个画笔
  
private Paint paint;
  
//声明一个线程
  
private Thread th;
  
//线程消亡的标志位
  
private boolean flag;
  
//声明一个画布
  
private Canvas canvas;
  
//声明屏幕的宽高
  
private int screenW,screenH;
  
//定义两个矩形的宽高坐标
  
private int x1 = 10,y1 = 110,w1 = 40,h1 = 40;
  
private int x2 = 10,y2 = 110,w2 = 40,h2 = 40;
  
//便于观察是否发生碰撞设置一个标识位
  
private boolean isCollsion;
  
 
/**
  
  * SurfaceView初始化函数
  
  */
  
public MySurfaceView(Context context){
  
  super(context);
  
  //实例SurfaceHolder
  
  sfh = this.getHolder();
  
  //为SurfaceView添加状态监听
  
  sfh.addCallback(this);
  
  //实例一个画笔
  
  paint = new Paint();
  
  //设置画笔颜色为白色
  
  paint.setColor(Color.WHITE);
  
  //设置焦点
  
  setFocusable(true);
  
}
  
@Override
  
public void surfaceCreated(SurfaceHolder holder) {
  
  // TODO Auto-generated method stub
  
  screenW = this.getWidth();
  
  screenH = this.getHeight();
  
  flag = true;
  
  //实例线程
  
  th = new Thread(this);
  
  //启动线程
  
  th.start();
  
}
  
 
 
/**
  
  * 游戏绘图
  
  */
  
public void myDraw(){
  
  try {
  
   canvas = sfh.lockCanvas();
  
   if(canvas != null){
  
    //刷屏
  
    canvas.drawColor(Color.BLACK);
  
    //判断是否发生了碰撞
  
    if(isCollsion){//发生碰撞
  
     paint.setColor(Color.RED);
  
     paint.setTextSize(20);
  
     canvas.drawText("Collision!", 0, 30, paint);
  
      
  
    } else{//没发生碰撞
  
     paint.setColor(Color.WHITE);
  
    }
  
    //绘制两个矩形
  
    canvas.drawRect(x1, y1, x1 + w1, y1 + h1, paint);
  
    canvas.drawRect(x2, y2, x2 + w2, y2 + h2, paint);
  
     
   }
  
  }catch(Exception e){
  
    
  
  }finally{
  
   if(canvas != null)
  
    sfh.unlockCanvasAndPost(canvas);
  
  }
  
}
  
/**
  
  * 触屏事件监听
  
  */
  
@Override
  
public boolean onTouchEvent(MotionEvent event) {
  
  // TODO Auto-generated method stub
  
  //让矩形1随着触屏位置移动(触屏点设为此矩形的中心点)
  
  x1 = (int) event.getX() - w1/2;
  
  y1 = (int) event.getY() - h1/2;
  
  //当矩形之间发生碰撞
  
  if(isCollsionWithRect(x1,y1,w1,h1,x2,y2,w2,h2)){
  
   isCollsion = true;//设置标志位为真
  
   //当矩形之间没有发生碰撞
  
  }else{
  
   isCollsion = false; //设置标志位为假
  
  }
  
  return true;
  
}
  
/**
  
  * 矩形碰撞的函数
  
  * @param x1 第一个矩形的X坐标
  
  * @param y1 第一个矩形的Y坐标
  
  * @param w1 第一个矩形的宽
  
  * @param h1 第一个矩形的高
  
  * @param x2 第二个矩形的X坐标
  
  * @param y2 第二个矩形的Y坐标
  
  * @param w2 第二个矩形的宽
  
  * @param h2 第二个矩形的高
  
  */
  
public boolean isCollsionWithRect(int x1,int y1,int w1,int h1,int x2,int y2,int w2,int h2){
  
  //当矩形1位于矩形2的左侧
  
  if (x1 >= x2 && x1>= x2 + w2){
  
   return false;
  
  //当矩形1位于矩形2的右侧
  
  } else if (x1<= x2 && x1 + w1 <= x2){
  
   return false;
  
  //当矩形1位于矩形2的上方
  
  } else if (y1 >= y2 && y1>= y2 + h2){
  
   return false;
  
  } else if (y1 <= y2 && y1 + h1 <= y2){
  
   return false;
  
  }
  
  //所有不会发生碰撞都不满足时,肯定就是碰撞了
  
  return true;
  
}
  
 
/**
  
  * 按键事件监听
  
  */
  
@Override
  
public boolean onKeyDown(int keyCode, KeyEvent event) {
  
  // TODO Auto-generated method stub
  
  return super.onKeyDown(keyCode, event);
  
}
  
/**
  
  * 游戏逻辑
  
  */
  
private void logic(){
  
   
  
}
  
@Override
  
public void run() {
  
  // TODO Auto-generated method stub
  
  while(flag){
  
   long start = System.currentTimeMillis();
  
   myDraw();
  
   logic();
  
   long end = System.currentTimeMillis();
  
   try {
  
    if (end - start < 50) {
  
     Thread.sleep(50 - (end - start));
  
    }
  
   } catch(InterruptedException e){
  
    e.printStackTrace();
  
   }
  
  }
  
   
  
}
  
/**
  
  * Surfaceview视图状态发生改变,响应此函数
  
  */
  
@Override
  
public void surfaceChanged(SurfaceHolder holder, int format, int width,
  
   int height) {
  
  // TODO Auto-generated method stub
  
   
  
}
  
/**
  
  * Surfaceview视图消亡,响应此函数
  
  */
  
@Override
  
public void surfaceDestroyed(SurfaceHolder holder) {
  
  // TODO Auto-generated method stub
  
   
  
}
  
}


RectCollsionActivity.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
	
package com.rectCollsion;
  
import android.app.Activity;
  
import android.os.Bundle;
  
import android.view.Window;
  
import android.view.WindowManager;
  
public class RectCollsionActivity extends Activity {
  
    /** Called when the activity is first created. */
  
    @Override
  
    public void onCreate(Bundle savedInstanceState) {
  
        super.onCreate(savedInstanceState);
  
        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
  
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
          WindowManager.LayoutParams.FLAG_FULLSCREEN);
  
        setContentView(new MySurfaceView(this));
  
    }
  
}


圆形碰撞:主要是利用两圆形的圆心距进行判定的;当两圆的圆心距小于两圆半径之和,判定发生了碰撞。
创建实例:CircleCollsoin
项目效果图:

1.jpg2.jpg
MySurfaceView.java


package com.circleCollsion;
  
import android.content.Context;
  
import android.graphics.Canvas;
  
import android.graphics.Color;
  
import android.graphics.Paint;
  
import android.view.KeyEvent;
  
import android.view.MotionEvent;
  
import android.view.SurfaceHolder;
  
import android.view.SurfaceHolder.Callback;
  
import android.view.SurfaceView;
  
public class MySurfaceView extends SurfaceView implements Callback,Runnable{
  
//用于控制SurfaceView
  
private SurfaceHolder sfh;
  
//声明一个画笔
  
private Paint paint;
  
//声明一个线程
  
private Thread th;
  
//线程消亡的标志位
  
private boolean flag;
  
//声明一个画布
  
private Canvas canvas;
  
//声明屏幕的宽高
  
private int screenW,screenH;
  
//定义两个圆的半径和坐标
  
private int r1 = 20, r2 = 20;
  
private int x1 = 50, y1 = 100, x2 = 150, y2 = 100;
  
//便于观察是否发生碰撞设置一个标识位
  
private boolean isCollsion;
  
 
/**
  
  * SurfaceView初始化函数
  
  */
  
public MySurfaceView(Context context){
  
  super(context);
  
  //实例SurfaceHolder
  
  sfh = this.getHolder();
  
  //为SurfaceView添加状态监听
  
  sfh.addCallback(this);
  
  //实例一个画笔
  
  paint = new Paint();
  
  //设置画笔颜色为白色
  
  paint.setColor(Color.WHITE);
  
  //设置焦点
  
  setFocusable(true);
  
}
  
@Override
  
public void surfaceCreated(SurfaceHolder holder) {
  
  // TODO Auto-generated method stub
  
  screenW = this.getWidth();
  
  screenH = this.getHeight();
  
  flag = true;
  
  //实例线程
  
  th = new Thread(this);
  
  //启动线程
  
  th.start();
  
}
  
 
 
/**
  
  * 游戏绘图
  
  */
  
public void myDraw(){
  
  try {
  
   canvas = sfh.lockCanvas();
  
   if(canvas != null){
  
    //刷屏
  
    canvas.drawColor(Color.BLACK);
  
    //判断是否发生了碰撞
  
    if(isCollsion){//发生碰撞
  
     paint.setColor(Color.RED);
  
     paint.setTextSize(20);
  
     canvas.drawText("Collision!", 0, 30, paint);
  
      
  
    } else{//没发生碰撞
  
     paint.setColor(Color.WHITE);
  
    }
  
    //绘制两个圆
  
    canvas.drawCircle(x1, y1, r1, paint);
  
    canvas.drawCircle(x2, y2, r2, paint);
  
   }
  
  }catch(Exception e){
  
    
  
  }finally{
  
   if(canvas != null)
  
    sfh.unlockCanvasAndPost(canvas);
  
  }
  
}
  
/**
  
  * 触屏事件监听
  
  */
  
@Override
  
public boolean onTouchEvent(MotionEvent event) {
  
  // TODO Auto-generated method stub
  
  x1 = (int) event.getX();
  
  y1 = (int) event.getY() ;
  
  //当圆形之间发生碰撞
  
  if(isCollsionWithCircle(x1,y1,x2,y2,r1,r2)){
  
   isCollsion = true;//设置标志位为真
  
   //当矩形之间没有发生碰撞
  
  }else{
  
   isCollsion = false; //设置标志位为假
  
  }
  
  return true;
  
}
  
/**
  
  * 圆形碰撞
  
  * @param x1圆形1的圆心x坐标
  
  * @param y1圆形1的圆心y坐标
  
  * @param x2圆心2的圆形x坐标
  
  * @param y2圆形2的圆形y坐标
  
  * @param r1圆形1的半径
  
  * @param r2圆形2的半径
  
  */
  
private boolean isCollsionWithCircle(int x1,int y1,int x2,int y2,int r1,int r2){
  
  //Math.sqrt:开平方
  
  //Math.pow(double x,double y):X的Y次方
  
  if(Math.sqrt(Math.pow(x1 - x2, 2)+ Math.pow(y1 - y2,2))<= r1 + r2){
  
   //如果两圆的圆心距小于或等于两圆半径则认为发生碰撞
  
   return true;
  
  }
  
  return false;
  
}
  
 
/**
  
  * 按键事件监听
  
  */
  
@Override
  
public boolean onKeyDown(int keyCode, KeyEvent event) {
  
  // TODO Auto-generated method stub
  
  return super.onKeyDown(keyCode, event);
  
}
  
/**
  
  * 游戏逻辑
  
  */
  
private void logic(){
  
   
  
}
  
@Override
  
public void run() {
  
  // TODO Auto-generated method stub
  
  while(flag){
  
   long start = System.currentTimeMillis();
  
   myDraw();
  
   logic();
  
   long end = System.currentTimeMillis();
  
   try {
  
    if (end - start < 50) {
  
     Thread.sleep(50 - (end - start));
  
    }
  
   } catch(InterruptedException e){
  
    e.printStackTrace();
  
   }
  
  }
  
   
  
}
  
/**
  
  * Surfaceview视图状态发生改变,响应此函数
  
  */
  
@Override
  
public void surfaceChanged(SurfaceHolder holder, int format, int width,
  
   int height) {
  
  // TODO Auto-generated method stub
  
   
  
}
  
/**
  
  * Surfaceview视图消亡,响应此函数
  
  */
  
@Override
  
public void surfaceDestroyed(SurfaceHolder holder) {
  
  // TODO Auto-generated method stub
  
   
  
}
  
}

像素碰撞:在游戏开发中是不推荐使用的,虽然它很精确,但是会造成代码的效率降低。因为有可以代替像素碰撞检测的方法:多矩形、多圆形的检测方式。下面进行介绍

多矩形碰撞:顾名思义就是设置多个矩形碰撞区域
下面创建一个实例:MoreRectCollsion项目
效果图:

1.jpg


package com.rectCollsion;
  
 
import android.content.Context;
  
import android.graphics.Canvas;
  
import android.graphics.Color;
  
import android.graphics.Paint;
  
import android.graphics.Paint.Style;
  
import android.graphics.Rect;
  
import android.view.KeyEvent;
  
import android.view.MotionEvent;
  
import android.view.SurfaceHolder;
  
import android.view.SurfaceHolder.Callback;
  
import android.view.SurfaceView;
  
 
public class MySurfaceView extends SurfaceView implements Callback,Runnable{
  
        //用于控制SurfaceView
  
        private SurfaceHolder sfh;
  
        //声明一个画笔
  
        private Paint paint;
  
        //声明一个线程
  
        private Thread th;
  
        //线程消亡的标志位
  
        private boolean flag;
  
        //声明一个画布
  
        private Canvas canvas;
  
        //声明屏幕的宽高
  
        private int screenW,screenH;
  
        //定义两个矩形的宽高坐标
  
        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};
  
         
  
        /**
  
         * SurfaceView初始化函数
  
         */
  
        public MySurfaceView(Context context){
  
                super(context);
  
                //实例SurfaceHolder
  
                sfh = this.getHolder();
  
                //为SurfaceView添加状态监听
  
                sfh.addCallback(this);
  
                //实例一个画笔
  
                paint = new Paint();
  
                //设置画笔颜色为白色
  
                paint.setColor(Color.WHITE);
  
                //设置焦点
  
                setFocusable(true);
  
        }
  
        @Override
  
        public void surfaceCreated(SurfaceHolder holder) {
  
                // TODO Auto-generated method stub
  
                screenW = this.getWidth();
  
                screenH = this.getHeight();
  
                flag = true;
  
                //实例线程
  
                th = new Thread(this);
  
                //启动线程
  
                th.start();
  
        }
  
         
  
         
  
        /**
  
         * 游戏绘图
  
         */
  
        public void myDraw(){
  
                try {
  
                        canvas = sfh.lockCanvas();
  
                        if(canvas != null){
  
                                //刷屏
  
                                canvas.drawColor(Color.BLACK);
  
                                //判断是否发生了碰撞
  
                                if(isCollsion){//发生碰撞
  
                                        paint.setColor(Color.RED);
  
                                        paint.setTextSize(20);
  
                                        canvas.drawText("Collision!", 0, 30, paint);
  
                                         
                                } else{//没发生碰撞
  
                                        paint.setColor(Color.WHITE);
  
                                }
  
                                //绘制两个矩形
  
                                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.WHITE);
  
                                //---绘制第一个矩形所有矩形碰撞区域
  
                                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 + this.rectY2, paint);
  
                                }
  
                                 
  
                        }
  
                }catch(Exception e){
  
                         
  
                }finally{
  
                        if(canvas != null)
  
                                sfh.unlockCanvasAndPost(canvas);
  
                }
  
        }
  
        /**
  
         * 触屏事件监听
  
         */
  
        @Override
  
        public boolean onTouchEvent(MotionEvent event) {
  
                // TODO Auto-generated method stub
  
                //让矩形1随着触屏位置移动(触屏点设为此矩形的中心点)
  
                rectX1 = (int) event.getX() - rectW1/2;
  
                rectY1 = (int) event.getY() - rectH1/2;
  
                //当矩形之间发生碰撞
  
                if(isCollsionWithRect(arrayRect1, arrayRect2)){
  
                        isCollsion = true;//设置标志位为真
  
                        //当矩形之间没有发生碰撞
  
                }else{
  
                        isCollsion = false; //设置标志位为假
  
                }
  
                return true;
  
        }
  
        /**
  
         * 矩形碰撞的函数
  
         * @param left 表示矩形左上角坐标的X坐标
  
         * @param top  表示矩形左上角坐标Y坐标
  
         * @param right 表示矩形右下角坐标X坐标
  
         * @param buttom 表示矩形右下角坐标Y坐标
  
         */
  
        public boolean isCollsionWithRect(Rect[] rectArray, Rect[] rect2Array){
  
                Rect rect = null;
  
                Rect rect2 = null;
  
                for(int i = 0; i < rectArray.length; i++){
  
                        //依次取出第一个矩形数组的每个矩形实例
  
                        rect = rectArray[i];
  
                        //获取到第一个矩形数组中每个矩形元素的属性值
  
                        int x1 = rect.left + this.rectX1;
  
                        int y1 = rect.top + this.rectY1;
  
                        int w1 = rect.right - rect.left;
  
                        int h1 = rect.bottom - rect.top;
  
                        for(int j = 0; j < rect2Array.length; j++){
  
                                //依次取出第二个矩形数组的每个矩形实例
  
                                rect2 = rect2Array[i];
  
                                //获取到第二个矩形数组中每个矩形的属性值
  
                                int x2 = rect2.left + this.rectX1;
  
                                int y2 = rect2.top + this.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;
  
        }
  
 
         
  
        /**
  
         * 按键事件监听
  
         */
  
        @Override
  
        public boolean onKeyDown(int keyCode, KeyEvent event) {
  
                // TODO Auto-generated method stub
  
                return super.onKeyDown(keyCode, event);
  
        }
  
        /**
  
         * 游戏逻辑
  
         */
  
        private void logic(){
  
                 
        }
  
        @Override
  
        public void run() {
  
                // TODO Auto-generated method stub
  
                while(flag){
  
                        long start = System.currentTimeMillis();
  
                        myDraw();
  
                        logic();
  
                        long end = System.currentTimeMillis();
  
                        try {
  
                                if (end - start < 50) {
  
                                        Thread.sleep(50 - (end - start));
  
                                }
  
                        } catch(InterruptedException e){
  
                                e.printStackTrace();
  
                        }
  
                }
  
                 
        }
  
        /**
  
         * Surfaceview视图状态发生改变,响应此函数
  
         */
  
        @Override
  
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
  
                        int height) {
  
                // TODO Auto-generated method stub
  
                 
        }
  
        /**
  
         * Surfaceview视图消亡,响应此函数
  
         */
  
        @Override
  
        public void surfaceDestroyed(SurfaceHolder holder) {
  
                // TODO Auto-generated method stub
  
                 
        }
  
}


第一种:就是圆形与矩形边框的碰撞检测
检测Y轴圆心到矩中心的距离是否小于半径+矩形X轴1/2宽
检测X轴圆心到矩中心的距离是否小于半径+矩形Y轴1/2高
第二种:就是特殊的矩形四个角检测
四个矩形顶角到圆心的距离是否小于半径

相信后面的大家就很容易理解:
这篇文章讲解一下基本的矩形和圆形之间的碰撞检测算法。上次我已经介绍过了矩形和矩形之间的碰撞检测,这次比上次麻烦那么一点。

二者碰撞最主要还是位于矩形的四个角。为了简洁,我还是运用上次的函数框架,虽然不是很方便,下面直接上代码:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
bool OverLap(RECT round, RECT rect)
{
int cr = (round.right - round.left)/2;
int cx = round.left + cr;
int cy = round.top + cr;
int distanceX = abs(cx - rect.left - (rect.right-rect.left)/2);
int distanceY = abs(cy - rect.top - (rect.bottom-rect.top)/2);
if(distanceX > ((rect.right-rect.left)/2 + cr)) return false;
if(distanceY > ((rect.bottom-rect.top)/2 + cr)) return false;
if(distanceX <= (rect.right-rect.left)/2) return true;
if(distanceY <= (rect.bottom-rect.top)/2) return true;
int sq = (distanceX-(rect.right-rect.left)/2)*(distanceX-(rect.right-rect.left)/2) +
(distanceY-(rect.bottom-rect.top)/2)*(distanceY-(rect.bottom-rect.top)/2);
return (sq <= cr*cr);
}

应该很容易看懂,函数输入的是两个矩形,前者是画圆用的外接矩形,后者是碰撞的矩形。
代码简单的分析一下:
1
2
3
int cr = (round.right - round.left)/2;
int cx = round.left + cr;
int cy = round.top + cr;

下面的几行代码是为了求出圆的半径和圆心。
1
int distanceX = abs(cx - rect.left - (rect.right-rect.left)/2); int distanceY = abs(cy - rect.top - (rect.bottom-rect.top)/2);

接下来的两行代码其实就是求圆心和矩形中心的距离。第一行是横坐标的距离,第二行是纵坐标的距离。
1
2
if(distanceX > ((rect.right-rect.left)/2 + cr)) return false;
if(distanceY > ((rect.bottom-rect.top)/2 + cr)) return false;

这两行是排除显而易见的情况,其实就是图上中间大的矩形外部的所有范围。第一句是表示圆形到矩形X坐标的距离大于二者半径的累加,排除图上的灰色线条两边的范围。第二句话排出的是两条蓝色线之外的范围,结合两者,正好剩余中间大的矩形范围。
1
2
if(distanceX <= (rect.right-rect.left)/2+r) return true;
if(distanceY <= (rect.bottom-rect.top)/2+r) return true;
就是非常单纯的检测矩形的四个角落碰撞。方法就是检验矩形和圆形的距离的平方和与圆的半径的平方的大小关系。

如果上边的你不太懂,没有关系,我用这个算法写了一个DEMO,你可以下载测试,然后注释掉算法的每一条语句来检测,看看语句的作用,到时候就懂了。


线段与矩形碰撞检测
*
* @param x1 线段一端点x坐标
* @param y1 线段一端点y坐标
* @param x2 线段二端点x坐标
* @param y2 线段二端点y坐标
* @param x 矩形左上角x坐标
* @param y 矩形左上角y坐标
* @param width 矩形宽度
* @param height 矩形高度
* @return


public static boolean lineWidthRect(int x1, int y1, int x2, int y2, int x, int y, int width, int height) {
  
double a =(double) ((y1 - y2)) / (double) ((x1 - x2));
  
double b =y1 - a * x1;
  
if (x1 < x2) {
  
for (int i =x1; i <= x2; i++) {
  
int tempY =(int) (a * i + b);
  
if (intersectRect(i, tempY, 1, 1, x, y, width, height)) {
  
return true;
  
}
  
}
  
} else if (x1 > x2) {
  
for (int i =x1; i >= x2; i--) {
  
int tempY =(int) (a * i + b);
  
if (intersectRect(i, tempY, 1, 1, x, y, width, height)) {
  
return true;
  
}
  
}
  
} else {
  
if (y1 <= y2) {
  
for (int i =y1; i < y2; i++) {
  
if (intersectRect(x1, i, 1, 1, x, y, width, height)) {
  
return true;
  
}
  
}
  
} else {
  
for (int i =y2; i > y2; i--) {
  
if (intersectRect(x1, i, 1, 1, x, y, width, height)) {
  
return true;
  
}
  
}
  
}
  
}
  
return false;
  
}


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics