碰撞就是游戏中的元素是否碰到一起,比如打飞机游戏,没躲避炮弹就算碰撞,要检测出来,要game over的。主要讲讲2D游戏里的碰撞检测,传统的2D游戏可以把不同元素当作基本图形粗糙地来检测碰撞与否?
1、矩形判断
比如把游戏中敌我双方人物都当作矩形来检测两个矩形是否相交。那么如何判读两个矩形是否相交呢?
相交 == !(不相交),不相交较好判断,优先判读不相交再取反就可以了。
如上图旁边矩形都不和中间矩形相交,它们都有共同特点:
1、旁边矩形(B)的xy坐标没有同时介于中间矩形(A)x~x',y~y'间,即没有一个点出现在A矩形内部,用伪代码判断不相交就是
B.max(x) < A.min(x) || B.min(x) > A.max(x) || B.max(y) < A.min(y) || B.min(y) > A.max(y)
那么判读相交的伪代码就是
!(B.max(x) < A.min(x) || B.min(x) > A.max(x) || B.max(y) < A.min(y) || B.min(y) > A.max(y))
2、当然由于矩形的特殊性,当知道矩形左上角的坐标和宽高时就可以知道其他三点的坐标,而且左上角坐标一般也是我们绘制矩形要传递的参数。
设两个矩形(A,B)坐标宽高为x1,y1,w1,h1和x2,y2,w2,h2,判断不相交代码就是:
1 /** 2 * 判断两矩形是否相交 3 */ 4 public boolean isCollsionWithRect(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { 5 // 矩形A位于矩形B的右侧 6 if (x1 >= x2 && x1 >= x2 + w2) { 7 return false; 8 // 矩形A位于矩形B的左侧 9 } else if (x1 <= x2 && x1 + w1 <= x2) { 10 return false; 11 // 矩形A位于矩形B的下侧 12 } else if (y1 >= y2 && y1 >= y2 + h2) { 13 return false; 14 // 矩形A位于矩形B的上侧 15 } else if (y1 <= y2 && y1 + h1 <= y2) { 16 return false; 17 } 18 // 不相交都不满足,那就是相交了 19 return true; 20 }
2、圆形判断
圆形判读比较简单,即判断两个圆心距离是否大于两个圆的半径之和
1 /** 2 * 圆形碰撞 3 * @param x1 圆形1的圆心X坐标 4 * @param y1 圆形2的圆心X坐标 5 * @param x2 圆形1的圆心Y坐标 6 * @param y2 圆形2的圆心Y坐标 7 * @param r1 圆形1的半径 8 * @param r2 圆形2的半径 9 * @return 10 */ 11 private boolean isCollisionWithCircle(int x1, int y1, int x2, int y2, int r1, int r2) { 12 //Math.sqrt:开平方 13 //Math.pow(double x, double y): X的Y次方 14 if (Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) <= r1 + r2) { 15 //如果两圆的圆心距小于或等于两圆半径则认为发生碰撞 16 return true; 17 } 18 return false; 19 }
3、多矩形判断
这时我们就要封装多个矩形来一一判断是否有碰撞。
1 //Rect 类中的四个属性 top bottom left right 2 //分别表示这个矩形的 上 下 左 右 3 public boolean isCollsionWithRect(Rect[] rectArray, Rect[] rect2Array) { 4 Rect rect = null; 5 Rect rect2 = null; 6 for (int i = 0; i < rectArray.length; i++) { 7 //依次取出第一个矩形数组的每个矩形实例 8 rect = rectArray[i]; 9 //获取到第一个矩形数组中每个矩形元素的属性值 10 int x1 = rect.left + this.rectX1; 11 int y1 = rect.top + this.rectY1; 12 int w1 = rect.right - rect.left; 13 int h1 = rect.bottom - rect.top; 14 for (int j = 0; j < rect2Array.length; j++) { 15 //依次取出第二个矩形数组的每个矩形实例 16 rect2 = rect2Array[j]; 17 //获取到第二个矩形数组中每个矩形元素的属性值 18 int x2 = rect2.left + this.rectX2; 19 int y2 = rect2.top + this.rectY2; 20 int w2 = rect2.right - rect2.left; 21 int h2 = rect2.bottom - rect2.top; 22 //进行循环遍历两个矩形碰撞数组所有元素之间的位置关系 23 if (x1 >= x2 && x1 >= x2 + w2) { 24 } else if (x1 <= x2 && x1 + w1 <= x2) { 25 } else if (y1 >= y2 && y1 >= y2 + h2) { 26 } else if (y1 <= y2 && y1 + h1 <= y2) { 27 } else { 28 //只要有一个碰撞矩形数组与另一碰撞矩形数组发生碰撞则认为碰撞 29 return true; 30 } 31 } 32 } 33 return false; 34 }