Java简单游戏开发之碰撞检测

前言

    不久以前在论坛上有人发贴,使用java编写的超级马里奥如何实现碰撞检测,笔者本身之前html

  也作过Tank大战。里面一样涉及到碰撞检测,翻翻U盘里的东西还在,何时也给共享出来。java

  这篇文章就简单游戏中的碰撞检测作一个简单的总结。首先需声明的是这里只是2D的碰撞检测。算法

    文章出处地址:http://blog.csdn.net/kiritor/article/details/8948097数组

碰撞检测

    对于形状之间如何来判断是不是碰撞的这要根据具体的形状来定。在新手练手的小游戏中,ide

 物体形状通常能够设定为矩形区域,这类规则图形。它的碰撞检测能够经过java API中的优化

  Rectangle类来实现碰撞的检测。spa

 规则图形碰撞检测(Rectangle)

    首先咱们查看API关于Rectangle类的介绍:它就是指定坐标空间的一个区域,这个区域是经过.net

  指定左上角x、y坐标和去高度和宽度来肯定的。htm

  接下来看起具体的方法public Rectangleintersection(Rectangle r),这个方法就是碰撞检测对象

  的关键了,若是两个Rectangle对象有交集,那么他们就有碰撞了。而每一个形状咱们均可以获得他

  们的Rectangle对象,这样图形的碰撞检测也就得以实现了。

/* 判断×××是否击中障碍物 */
public boolean isHit(com.Alex.map.Map map) {
    boolean flag = true;// 表明没有撞到
    // 分类别的获得全部的障碍物
    List<Stuff> stuffList = new Vector<Stuff>();
    stuffList.addAll(map.getBricks());
    stuffList.addAll(map.getIrons());
    stuffList.addAll(map.getWaters());
    for (int i = 0; i < stuffList.size(); i++) {
        Stuff a = stuffList.get(i);
        Rectangle tankRectangle = new Rectangle(bullet2.getRec());
        Rectangle stuffRectangle = new Rectangle(a.getX(), a.getY(), 20, 20);
        if (stuffRectangle.intersects(tankRectangle)) {
            flag = false;// 撞到了
            break;
        }
    }
    return flag;
}

          上述这个例子就是判断Tank发出的×××是否对地图中的障碍物有碰撞,若是有的话

     就作相关的操做(×××爆炸、障碍物消失)。上述代码中×××对象有一个getRec()方法就是

     获得×××图形的Rectangle对象,具体实现就是根据其坐标和width、height来生成的。

          采用此种方法进行碰撞检测须要注意,对于图片的实现处理应该尽可能的去掉图标边角

     的空白,否则实际效果能够产生肉眼可辨的偏差。也就是说Rectangle尽可能的包住图形

     且Rectangle的区域尽可能小。这种碰撞检测的方法被称之为多矩形碰撞


          一旦有一个矩形数组中的矩形与另一个矩形数组的矩形发生碰撞就可认为发生了

      多矩形碰撞。其中多圆形碰撞也是一样的道理,只是包裹的图形区域是圆形罢了。

      不过仔细思考多矩形碰撞一样会有偏差,虽然这种偏差十分小。


  像素级别的碰撞检测

       像素级别的碰撞检测算得上是最精确的碰撞检测方法了。

       首先遍历算出一张位图全部的像素点坐标,而后与另一张位图上的全部点坐标进行对比,

   一旦有一个像素点的坐标相同,就马上取出这两个坐标相同的像素点,经过位运算取出这两个

   像素点的最高位(透明度)进行对比,若是两个像素点都是非透明像素则断定这两张位图发生

   碰撞。

       介绍了像素碰撞以后能够获得两个结论:

          一、像素碰撞很精确,不论位图之间是否带有透明像素,均可以精确判断;

          二、正是由于像素碰撞的这种高精确断定,从而也会形成代码效率明显下降!

               假设两张100×100 大小的位图利用像素级检测碰撞,仅是遍历两张位图的像素  

               就要循环100×100×2=20000 句逻辑代码;何况还要对筛选出来的相同坐标的

               像素点进行遍历对比其透明值!这种效率可想而知!

      固然,这里的像素碰撞只是大体提供一种思路,确定还能够进行代码优化;可是不论再优的

      代码,使用像素级进行碰撞检测终会致使整个程序的运行效率大大下降。所以像素级别的碰

      撞检测在游戏开发中是尽可能避免使用的!

   规则图形碰撞检测2

         对于×××和障碍物的碰撞检测,采用上述第一种方法就能够简单的实现了,不过×××

     是圆形的有没有更加精确的碰撞检测方法呢?也就是实现圆形和矩形的碰撞检测嘛。

        这里咱们须要简单的运行下几何数学的知识,给个简单的图就会明白了。


         小圆有个运动轨迹,轨迹的线若是和他对着的正方形的相对某一象限的边有焦点,那么

      就能碰撞,边就是那一个象限的边(还要把圆半径算进去),具体代码就不实现了,读者可

      本身尝试着去实现。    

  不规则图形碰撞检测

     对于矩形碰撞,不少人都知道。但面对多边形图形,大多数采用多矩形覆盖的方式。

       SAT 一种能够快速检测不规则的凸多边形是否碰撞的算法给出两个凸多边形体,

    若是咱们能找到一个轴线,使两物体在此轴线上的投影不重叠,则这两个物体之间没有

    发生碰撞,这个轴线叫作Separating Axis(红色轴线)。

       对于2D来讲,红色线就是垂直与多边形边的轴。

      所以,若是咱们要检查两多边形是否碰撞,就去检查两多边形在每一个全部可能的轴上的投影

   是否重叠。

/// 检测2个矩形是否发生碰撞
/// </summary>
/// <returns></returns>
public static bool IsIntersect (Vector2[] A, Vector2[] B)
 {
    Vector2 AX, AY, BX, BY;
    AX = new Vector2();
    AY = new Vector2();
    BX = new Vector2();
    BY = new Vector2();
                                          
    AX.X = A[0].X - A[1].X;
    AX.Y = A[0].Y - A[1].Y;           
    AY.X = A[0].X - A[3].X;          
    AY.Y = A[0].Y - A[3].Y;           
    BX.X = B[0].X - B[1].X;          
    BX.Y = B[0].Y - B[1].Y;           
    BY.X = B[0].X - B[3].X;          
    BY.Y = B[0].Y - B[3].Y;           
    //对于AX上:          
    if (Tmp(AX, A, B)) return false;          
    if (Tmp(AY, A, B)) return false;         
    if (Tmp(BX, A, B)) return false;          
    if (Tmp(BY, A, B)) return false;          
    return true;     
}
                                                
private static bool Tmp(Vector2 IS,Vector2[] A,Vector2[] B)
 {
    float[] v = new float[4];
    for (int i = 0; i < 4; i++)
    {              
        float tmp = (IS.X * A[i].X + IS.Y * A[i].Y) / (IS.X * IS.X + IS.Y * IS.Y);
                 v[i] = tmp * IS.X * IS.X + tmp * IS.Y * IS.Y;         
    }
    float[] vv = new float[4];
    for (int i = 0; i < 4; i++)
    {
        float tmp = (IS.X * B[i].X + IS.Y * B[i].Y) / (IS.X * IS.X + IS.Y * IS.Y);
                  vv[i] = tmp * IS.X * IS.X + tmp * IS.Y * IS.Y;
    }
    if (Math.Max(Math.Max(v[0], v[1]),Math.Max(v[2],v[3])) >Math.Min(Math.Min(vv[0],vv[1]),Math.Min(vv[2],vv[3])) && Math.Min(Math.Min(v[0],v[1]),Math.Min(v[2],v[3])) < Math.Max(Math.Max(vv[0],vv[1]),Math.Max(vv[2],vv[3]))) {
     return false;
    }//表示暂时不知道是否碰撞          
    else return true;//表示知道未碰撞
}
相关文章
相关标签/搜索