欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

游戏开发2D碰撞检测之圆与圆的碰撞

程序员文章站 2022-07-12 22:59:13
...

最近要做一个塔防游戏demo,防御塔需要检测敌人是否进入攻击范围内,我就得判断了。本来可以使用JBox2d的,这边自己实现一下,肯定还有很多问题,暂时做个记录,后面要优化。

关于JBox2d,我写了一篇入门教程JBox2D第一课-搭建swing绘制框架并实现小球*落体

圆与圆碰撞分析

游戏开发2D碰撞检测之圆与圆的碰撞
描述:当两个圆半径之和*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我第一篇文章有介绍)的代码
类似下面这样:
游戏开发2D碰撞检测之圆与圆的碰撞

下面我们实现我们的碰撞函数

    /**
     * 圆形碰撞
     * @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());
        }

游戏开发2D碰撞检测之圆与圆的碰撞

问题

你发现并不是你想象的那样,哈,为什么呢?
你发现上面代码的问题了吗?
其实我们的算法并没有问题,那问题就是我们绘制视图的问题了
找到绘制防御塔的地方
游戏开发2D碰撞检测之圆与圆的碰撞

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&nbsp;+&nbsp;1</code> pixels wide
     * and <code>height&nbsp;+&nbsp;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 表示画椭圆的外切矩形的高

也就是说,我们要自己计算圆心
游戏开发2D碰撞检测之圆与圆的碰撞

解决方案

我们把绘制防御塔的代码改成

  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());
        }

好了再测试一下
游戏开发2D碰撞检测之圆与圆的碰撞

开源地址

这样圆与圆的碰撞就完成了,上面的代码是本人在写塔防游戏demo,已经在github上了地址:https://github.com/CreOpenDream/EGame