最近研究碰撞检测碰撞,稍微总结一下,以后继续补充:
未几之前在论坛上有人发贴,使用java编写的超级马里奥如何实现碰撞检测,笔者自己以前
也做过Tank大战。里面一样涉及到碰撞检测,翻翻U盘里的东西还在,什么时候也给同享出来。
这篇文章就简单游戏中的碰撞检测做一个简单的总结。首先需声明的是这里只是2D的碰撞检测。
对于形状之间如何来判断是不是是碰撞的这要根据详细的形状来定。在新手练手的小游戏中,
物体形状一般可以设定为矩形区域,这类规矩图形。它的碰撞检测可以通过java API中的
Rectangle类来实现碰撞的检测。
首先我们查看API关于Rectangle类的介绍:它就是指定坐标空间的一个区域,这个区域是通过
指定左上角x、y坐标和去高度和宽度来肯定的。
接下来看起详细的方法public Rectangle intersection(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的区域尽量小。这类碰撞检测的方法被称之为多矩形碰撞。
一旦有一个矩形数组中的矩形与另外一个矩形数组的矩形产生碰撞便可以为产生了
多矩形碰撞。其中多圆形碰撞也是一样的道理,只是包裹的图形区域是圆形罢了。
不过细心思考多矩形碰撞一样会有误差,虽然这类误差非常小。
像素级别的碰撞检测算得上是最精确的碰撞检测方法了。
首先遍历算出一张位图全部的像素点坐标,然后与另外一张位图上的全部点坐标停止对比,
一旦有一个像素点的坐标雷同,就立刻取出这两个坐标雷同的像素点,通过位运算取出这两个
像素点的最高位(透明度)停止对比,如果两个像素点都长短透明像素则判断这两张位图产生
碰撞。
介绍了像素碰撞之后可以得到两个论断:
1、像素碰撞很精确,不论位图之间是不是带有透明像素,都可以精确判断;
2、正是因为像素碰撞的这类高精确判断,从而也会造成代码效率显著降低!
假设两张100×100 巨细的位图利用像素级检测碰撞,仅是遍历两张位图的像素点就要循环
100×100×2=20000 句逻辑代码;况且还要对筛选出来的雷同坐标的像素点停止遍历对比其
透明值!这类效率可想而知!
当然,这里的像素碰撞只是大致供给一种思路,肯定还可以停止代码优化;但是不论再优的
代码,使用像素级停止碰撞检测终会导致整个程序的运行效率大大降低。因此像素级别的碰
撞检测在游戏开发中是尽量避免使用的!
对于子弹和障碍物的碰撞检测,采取上述第一种方法便可以简单的实现了,不过子弹是圆形的
有没有更加精确的碰撞检测方法呢?也就是实现圆形和矩形的碰撞检测嘛。
这里我们需要简单的运行下几何数学的知识,给个简单的图就会明白了。
小圆有个运动轨迹,轨迹的线如果和他对着的正方形的相对某一象限的边有焦点,那么
就能碰撞,边就是那一个象限的边(还要把圆半径算进去),详细代码就不实现了,读者可
自己尝试着去实现。
这里直接转载一篇文章:
http://www.cnblogs.com/Kurodo/archive/2012/08/08/2628688.html
对于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;//表示知道未碰撞 }
文章结束给大家分享下程序员的一些笑话语录: 马云喜欢把自己包装成教主,张朝阳喜欢把自己包装成明星,李彦宏喜欢把自己包装成的很知性,丁磊喜欢把自己包装的有创意,李开复总摆出一副叫兽的样子。看来的。其实我想说,缺啥补啥,人之常情。