Java游戏中的碰撞检测之矩形碰撞

我们在游戏开发中少不了会遇到各种各样的碰撞,例如飞机射击类游戏、坦克大战游戏、推箱子游戏......并且会频繁地去处理这些碰撞,这也是游戏开发中的一种基本算法。常见的碰撞算法有矩形碰撞、像素碰撞、圆形碰撞,其中矩形碰撞使用得最多。

两个矩形发生碰撞的情况有如下几种:

图片

此外还有一种容易被忽视的碰撞情况(重叠):

图片

第1种方法:

        我们可以通过判断一个矩形的4个顶点是否在另外一个矩形的内部来完成。下面简单地创建一个Rectangle类:

public class Rectangle {
    int x, y, w, h;// 分别是x和y坐标,宽度和高度,构成一个矩形

    public Rectangle() {
    }

    public Rectangle(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getRectangleWidth() {
        return w;
    }

    public int getRectangleHeight() {
        return h;
    }
}

检测是否发生碰撞的部分代码如下:

public boolean isColliding(int px, int py) {
        // px和py分别传入的是x坐标和y坐标
        // 等号的情况是考虑重叠的情况
        // 传入的坐标只要满足下面所有条件就表示传入的坐标在当前矩形范围内,返回true也就是碰撞了
        if (px >= getX() && px < getX() + getRectangleWidth() && py >= getY() && py < getY() + getRectangleHeight()) {
            return true;
        }
        return false;
    }

    // 碰撞检测,发生碰撞返回true,否则返回false
    public boolean isColliding(Rectangle two) {
        // 判断矩形只要有任何一个点在另一个one所表示的矩形范围内,就表示发生了碰撞,返回true值
        if (isColliding(two.getX(), two.getY()) ||
                isColliding(two.getX() + two.getRectangleWidth(), two.getY()) ||
                isColliding(two.getX(), two.getY() + two.getRectangleHeight()) ||
                isColliding(two.getX() + two.getRectangleWidth(), two.getY() + two.getRectangleHeight())) {
            return true;
        }
        return false;
    }

完整代码如下:

public class Rectangle {
    int x, y, w, h;// 分别是x和y坐标,宽度和高度,构成一个矩形

    public Rectangle() {
    }

    public Rectangle(int x, int y, int w, int h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getRectangleWidth() {
        return w;
    }

    public int getRectangleHeight() {
        return h;
    }

    public boolean isColliding(int px, int py) {
        // px和py分别传入的是x坐标和y坐标
        // 等号的情况是考虑重叠的情况
        // 传入的坐标只要满足下面所有条件就表示传入的坐标在当前矩形范围内,返回true也就是碰撞了
        if (px >= getX() && px < getX() + getRectangleWidth() && py >= getY() && py < getY() + getRectangleHeight()) {
            return true;
        }
        return false;
    }

    // 碰撞检测,发生碰撞返回true,否则返回false
    public boolean isColliding(Rectangle r) {
        // 判断矩形只要有任何一个点在另一个one所表示的矩形范围内,就表示发生了碰撞,返回true值
        if (isColliding(r.getX(), r.getY()) ||
                isColliding(r.getX() + r.getRectangleWidth(), r.getY()) ||
                isColliding(r.getX(), r.getY() + r.getRectangleHeight()) ||
                isColliding(r.getX() + r.getRectangleWidth(), r.getY() + r.getRectangleHeight())) {
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        Rectangle one = new Rectangle(10, 10, 50, 100);
        Rectangle two = new Rectangle(20, 30, 50, 100);
        Rectangle three = new Rectangle(10, 30, 50, 100);
        Rectangle four = new Rectangle(70, 10, 50, 100);
        boolean colliding1 = one.isColliding(two);
        boolean colliding2 = one.isColliding(three);
        boolean colliding3 = one.isColliding(four);
        System.out.println(colliding1);
        System.out.println(colliding2);
        System.out.println(colliding3);
    }
}
输出结果:
true
true
false

解析图如下:

图片

图片

图片

第2种方法:

        第1种方法没有考虑到运行速度,而通常游戏中需要大量的碰撞检测,因此要求碰撞检测尽量做到高效率。第1种方法是处理什么时候相交,现在我们换个角度思考什么时候不会相交。可以处理4条边,one矩形的右边界在two矩形的左边界以外,同理,one的上边界需要在two的下边界以外,4条边都判断即可知道one与two是否相交。

方法如下:

/**
     * oneX 矩形one的x坐标
     * oneY 矩形one的y坐标
     * oneW 矩形one的宽度
     * oneH 矩形one的高度
     * twoX 矩形two的x坐标
     * twoY 矩形two的y坐标
     * twoW 矩形two的宽度
     * twoH 矩形two的高度
     */
    public boolean isColliding(int oneX, int oneY, int oneW, int oneH, int twoX, int twoY, int twoW, int twoH) {
        if (oneY > twoY + twoH || twoY > oneY + oneH || oneX > twoX + twoW || twoX > oneX + oneW) {
            return false;
        }
        return true;
    }

此方法比第1种方法简单且运行快。

第3种方法:

        是第2种方法的升级版。我们可以保存两个矩形的左上和右下两个坐标的坐标值,然后对比两个坐标即可得出是否相交。这种方法比第2种方法更优越。推荐使用这种方法。

/**
     * one[0]:矩形one左上角x坐标
     * one[1]:矩形one左上角y坐标
     * one[2]:矩形one右下角x坐标
     * one[3]:矩形one右下角y坐标
     * two[0]:矩形two左上角x坐标
     * two[1]:矩形two左上角y坐标
     * two[2]:矩形two右下角x坐标
     * two[3]:矩形two右下角y坐标
     *
     * @param one 第一个矩形的左上角坐标和右下角坐标数组
     * @param two 第二个矩形的左上角坐标和右下角坐标数组
     * @return 如果发生碰撞则返回true,否则返回false
     */
    public static boolean isColliding(int one[], int two[]) {
        if (one[0] > two[2]) return false;
        if (one[2] < two[0]) return false;
        if (one[1] > two[3]) return false;
        if (one[3] < two[1]) return false;
        return true;
    }
    public static void main(String[] args) {
        int one[] = {10, 10, 60, 110};
        int two[] = {20, 30, 70, 130};
        System.out.println(isColliding(one, two));
    }
输出结果:
true

图片

创作不易,点个关注不迷路图片~

  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Java 3D手机游戏开发实例集锦,书的实例源码,对学习java 3D游戏开发帮助较大。   Hello3D 最基础的MIDlet例子,用于测试开发环境   第3章   EventDemo 事件处理演示   MMAPIDemo 声音播放演示   RMSMIDlet 记录存储演示   第4章   M3GCube 立方体模型   pyramidSample 四棱锥模型   Sword 宝剑模型   第5章   AmbientLight 环境光演示   DirectionLight 平行光演示   SpotLight 点光源演示   TeapotM3G 茶壶模型演示   第6章   M3GTransform 坐标变换演示   第7章   BackgroundDemo 背景类使用演示   BillBorad 电子公告牌演示   getProperties 获取设备属性   GroupDemo 组对象应用演示   PickCube 拾取技术演示   Sprite3DDemo 3D精灵演示   TargetCamera 目标摄影机演示   TargetLight 目标灯光演示   第8章   LoaderM3G 加载M3G文件演示   traverseWorld 遍历场景演示   ViewM3Gtree 浏览场景树演示   3DS MAX 3DMAX制作的茶壶源文件和显示代码   Maya Maya制作的立方体源文件和显示代码   Blender Blender制作的立方体源文件   第9章   AnmiPlayDemo 动画播放演示   BendingBlock 弯曲的方块   DrivingBoat 游动的轮船   Hand 活动的手   HandDisplay 活动的手演示   MorphingDemo 顶点变形动画体演示   RotatingCube 旋转的立方体演示   MorphingPenguin 变形企鹅演示   RotatingCube 旋转的立方体   SkinnedDemo 骨骼变形动画体演示   第10章   CollisionTest 碰撞检测   Desert 高度地图演示   ExplosionParticle 爆炸粒子演示   FireworksParticle 喷泉粒子演示   HeightMap 高度地图演示   第11章   Maze3D 关于3D迷宫游戏的演示程序   第12章   FPSDemo 第一人称射击游戏演示   第13章   AffineTrans AffineTrans类的使用   AnmiTexture 动画纹理   RotatingCube 旋转的立方体   SmokeDemo 烟雾例子演示   TextureCube 带纹理的立方体   Transparency 透明属性应用   Util3D 应用类的使用   Vector3D 向量的使用   第14章   RobotDemo 机器人动画演示   DancingBoy 跳舞的男孩   Rotat

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Waylon1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值