游戏开发2D碰撞检测之圆与圆的碰撞
程序员文章站
2022-07-12 22:59:13
...
最近要做一个塔防游戏demo,防御塔需要检测敌人是否进入攻击范围内,我就得判断了。本来可以使用JBox2d的,这边自己实现一下,肯定还有很多问题,暂时做个记录,后面要优化。
关于JBox2d,我写了一篇入门教程JBox2D第一课-搭建swing绘制框架并实现小球*落体
圆与圆碰撞分析
描述:当两个圆半径之和*r1+r2小于两个圆的圆心距c时,即发生碰撞*。
圆心距怎么算?就是求两个点的距离用勾股定理。
这里我们把求两个点的距离封装成一个函数distance
/**
*
* @param pos1 点的位置一
* @param pos2 点的位置二
* @return 点与点的距离
*/
public static double distance(Vector2 pos1, Vector2 pos2){
return Math.sqrt(Math.pow(pos1.x - pos2.x,2) + Math.pow(pos1.y - pos2.y,2));
}
注意:Vector2封装的2d坐标类,自己可以实现一下,可以参考jbox2d(jbox2d我第一篇文章有介绍)的代码
类似下面这样:
下面我们实现我们的碰撞函数
/**
* 圆形碰撞
* @param circlePos1 圆1位置
* @param r1 圆1半径
* @param circlePos2 圆2位置
* @param r2 圆2半径
* @return 碰撞返回true,没碰撞返回false
*/
public static boolean circleAndCircleCollision(Vector2 circlePos1,float r1, Vector2 circlePos2, float r2){
if(distance(circlePos1,circlePos2) < r1+r2)
return true;
return false;
}
看起来很简单吧,下面我们来测试一下
if(Tools.circleAndCircleCollision(this.getPosition(),this.getAttackRangeRadius(),this.hero.getPosition(),this.hero.getR())){
System.out.println("attacked");
System.out.println(this.position);
System.out.println(this.hero.getPosition());
}
问题
你发现并不是你想象的那样,哈,为什么呢?
你发现上面代码的问题了吗?
其实我们的算法并没有问题,那问题就是我们绘制视图的问题了
找到绘制防御塔的地方
g.drawOval(this.tower.getX(), this.tower.getY(), this.tower.getAttackRangeRadius(), this.tower.getAttackRangeRadius());
是的就是这里
这是绘制椭圆的,这里我们让第三个参数和第四个参数都相等就是圆了,那些参数表示什么意思呢?
查看一下jdk api
/**
* Draws the outline of an oval.
* The result is a circle or ellipse that fits within the
* rectangle specified by the <code>x</code>, <code>y</code>,
* <code>width</code>, and <code>height</code> arguments.
* <p>
* The oval covers an area that is
* <code>width + 1</code> pixels wide
* and <code>height + 1</code> pixels tall.
* @param x the <i>x</i> coordinate of the upper left
* corner of the oval to be drawn.
* @param y the <i>y</i> coordinate of the upper left
* corner of the oval to be drawn.
* @param width the width of the oval to be drawn.
* @param height the height of the oval to be drawn.
* @see java.awt.Graphics#fillOval
*/
public abstract void drawOval(int x, int y, int width, int height);
API说:
x表示 左上角的横坐标
y表示 左上角的纵坐标
width 表示画椭圆的外切矩形的宽
height 表示画椭圆的外切矩形的高
也就是说,我们要自己计算圆心
解决方案
我们把绘制防御塔的代码改成
g.drawOval(this.tower.getX(), this.tower.getY(), this.tower.getAttackRangeRadius()*2, this.tower.getAttackRangeRadius()*2);
并把碰撞检测代码改成
if(Tools.circleAndCircleCollision(new Vector2(this.getX()+this.getAttackRangeRadius(),this.getY()+this.attackRangeRadius),this.getAttackRangeRadius(),new Vector2(this.hero.getX()+this.hero.getR(),this.hero.getY()+this.hero.getR()),this.hero.getR())){
System.out.println("attacked");
System.out.println(this.position);
System.out.println(this.hero.getPosition());
}
好了再测试一下
开源地址
这样圆与圆的碰撞就完成了,上面的代码是本人在写塔防游戏demo,已经在github上了地址:https://github.com/CreOpenDream/EGame
推荐阅读