专栏首页白玉无冰四叉树与碰撞检测 !Cocos Creator !

四叉树与碰撞检测 !Cocos Creator !

四叉树与引擎内置碰撞检测的结合运用。完整项目见文末。

效果预览

绿色为参加检测的对象(当前四叉树节点),红色为碰撞对象。

如何使用

引入脚本 QuadtreeCollision.ts , 新建一个 QuadtreeCollision ,并初始化为世界坐标系下的对齐轴向的包围盒(AABB)。

// 这边是挂载在canvas下的脚本,用canvas的rect初始化创建。
this._quadCollision = new QuadtreeCollision(this.node.getBoundingBoxToWorld())

传入待检测的碰撞数组 cc.Collider[] 和测试对象的 cc.Collider

返回准备测试的 cc.Collider[] 和发生碰撞的 cc.Collider[]

// check(colliders: cc.Collider[], testCollider: cc.Collider)
const { retrieve, contacts } = this._quadCollision.check(this._all_collider, this.collider_role);
// retrieve 准备测试的对象(预览图中的绿色)   cc.Collider[]
// contacts 碰撞对象(预览图中的红色)   cc.Collider[]

实现原理

四叉树是什么?

白玉无冰是这样理解的,四叉树本身是树结构的一种,如果物体过多的话,先根据物体所处位置划分成四块,如果每个块中的物体数量还是很多的话,继续划分成四块。如下图红线所示。

检测的时候,就是根据待测试对象的位置,去找属于哪个块,再把这个块中的物体告诉你。如下图中的绿色物体。

那么怎么实现四叉树呢?用好 github 就行了(误),搜了一下,找到一个库,直接拿来改改就行了。

https://github.com/timohausmann/quadtree-js

//export default class QuadtreeCollision {
private _tree;
constructor(rect: { x: number, y: number, width: number, height: number }) {
    this._tree = new Quadtree(rect);
}

那么怎么检测碰撞呢?

先看看引擎(v2.3.3)的 CollisionManager 是怎么处理的。

cc.Collider 这个组件 onEnable 时,会把这个组件加入 CollisionManager 中。

CollisionManager 添加 Collider 时,会遍历所有的 Collider ,根据分组创建一个碰撞连接。

所以,我们碰撞检测的思路,就在源码中搬过来改改。

将上面的代码整理出我们要用的检测代码如下。

function testContact(collider1, collider2) {
    // 分组不通过
    if (!cc.director.getCollisionManager()['shouldCollide'](collider1, collider2)) {
        return false;
    }

    let world1 = collider1.world;
    let world2 = collider2.world;
    if (!world1.aabb.intersects(world2.aabb)) {
        return false;
    }

    let isCollider1Polygon = (collider1 instanceof cc.BoxCollider) || (collider1 instanceof cc.PolygonCollider);
    let isCollider2Polygon = (collider2 instanceof cc.BoxCollider) || (collider2 instanceof cc.PolygonCollider);
    let isCollider1Circle = collider1 instanceof cc.CircleCollider;
    let isCollider2Circle = collider2 instanceof cc.CircleCollider;

    if (isCollider1Polygon && isCollider2Polygon) {
        return cc.Intersection.polygonPolygon(world1.points, world2.points);
    } else if (isCollider1Circle && isCollider2Circle) {
        return cc.Intersection.circleCircle(world1, world2);
    } else if (isCollider1Polygon && isCollider2Circle) {
        return cc.Intersection.polygonCircle(world1.points, world2);
    } else if (isCollider1Circle && isCollider2Polygon) {
        return cc.Intersection.polygonCircle(world2.points, world1);
    } else {
        // cc.errorID(6601, cc.js.getClassName(collider1), cc.js.getClassName(collider2));
    }
    return false;
}

最后再结合四叉树碰撞,检测代码如下。

check(colliders: cc.Collider[], testCollider: cc.Collider) {
    const ret: { retrieve: cc.Collider[], contacts: cc.Collider[] } = { retrieve: [], contacts: [] };

    // 四叉树清理
    this._tree.clear();
    const collisionManager = cc.director.getCollisionManager();
    collisionManager['updateCollider'](testCollider);
    for (let i = 0, l = colliders.length; i < l; i++) {
        const collider = colliders[i];
        // 更新碰撞体世界aabb
        collisionManager['updateCollider'](collider);
        const aabb = collider['world'].aabb;
        const rect = { x: aabb.x, y: aabb.y, height: aabb.height, width: aabb.width, collider: collider };
        // 四叉树插入
        this._tree.insert(rect)
    }
    // 四叉树抓出待检查的对象(属于那个块的所有节点)
    const retrieveObjects = this._tree.retrieve(testCollider['world'].aabb);
    retrieveObjects.forEach(element => {
        ret.retrieve.push(element.collider);
        // 抓出来后检查碰撞
        if (testContact(element.collider, testCollider)) {
            ret.contacts.push(element.collider);
        }
    });

    return ret;
}

本文分享自微信公众号 - 白玉无冰(lamyoung-com),作者:lamyoung

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-07-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • cocos creator | 用摄像机实现残影幻影拖尾效果

    利用摄像机拍摄角色,然后投影到多个显示画布,给画布节点设置不同的透明度,最后让画布节点跟随角色移动。

    白玉无冰
  • 图片/文字 的渐变色实现!

    在 cc.Spirte 或 cc.Label 添加脚本 ColorAssembler2D 。

    白玉无冰
  • 物理挖洞!涂抹地形! 小鳄鱼爱洗澡!百战天虫 !Cocos Creator !

    整体思路是先使用 PolyBool 计算多边形,接着使用 cc.PhysicsChainCollider 将多边形围起来,最后使用 cc.Graphics 将整...

    白玉无冰
  • 冰冰教你用“四叉树”手写“碰撞检测”,太感动了!

    引入脚本 QuadtreeCollision.ts , 新建一个 QuadtreeCollision ,并初始化为世界坐标系下的对齐轴向的包围盒(AABB)。

    张晓衡
  • OpenSSL与yaSSL性能对比

    摘要 MySQL可以使用OpenSSL或yaSSL/wolfSSL进行编译,这两者都支持基于OpenSSL API的加密连接。在5.7版本,我们知道默认情况下...

    腾讯数据库技术
  • 关于cocos2dx之lua使用TableView

    在手机游戏的开发中,滚动是一项非常重要的操作,而cocos2dx中使用的最广泛的就属于TableView了,不过由于cocos2dx的接口比较晦涩,所以需要一...

    帘卷西风
  • cocos2d-js 3.0 RC0 监听返回键、菜单键、进入后台(home键)、恢复显示等事件

    用户1258909
  • H5小游戏的坑点小结

    1) iOS 9.1 的safari中,在onTouchBegan方法中调用cc.audioEngine.playEffect播放音效是没有效果的,如果在onT...

    meteoric
  • 利用越权漏洞窃取Airbnb房东的收款资金

    今天分享的Writeup是作者在2017年发现,在最近披露的Airbnb平台漏洞,漏洞类型为越权(IDOR),攻击者可以利用漏洞向Airbnb平台中的房东收款信...

    FB客服
  • 深挖五年数据,给AI顶会重新排名:CVPR居首,NIPS、ICML紧跟

    随着计算机技术的日新月异,尤其是以人工智能和机器学习为代表的新兴技术快速发展,使得以AI为主题的会议层出不穷。那么了解AI领域的最新科研成果与发展趋势,就一定要...

    大数据文摘

扫码关注云+社区

领取腾讯云代金券