web前端入门到实战:简析 js 碰撞检测原理与算法实现

碰撞检测(边界检测)在前端游戏,以及涉及拖拽交互的场景应用十分广泛。

那么啥叫碰撞?JavaScript 又是如何检测 DOM 发生碰撞的呢?

碰撞,顾名思义,就是两个物体碰撞在了一起,眼睛是可以直观的观察到碰撞的发生。但对于前端实现,如何让 JavaScript 代码理解两个独立的“物体”(DOM)碰撞在一起呢。这就涉及到碰撞检测(或者叫边界检测)的问题了。

碰撞检测的常见需求场景:

前端常见的的碰撞,我们可以粗略的分为几下几类:

两个矩形块的碰撞:

判断任意两个(水平)矩形的任意一边是否有间距,从而得之两个矩形块有没有发生碰撞。具体实现方式,可以选定一个矩形为参照物,计算另一矩形的与自己相近的边是否发生重合现象。若四边均未发生重合,则未发生碰撞,反之则发生碰撞。

图形示例:

简单算法实现(非碰撞情况,else 分支就是碰撞情况):

    if( domA.left > domB.right 
        || domA.top > domB.bottom
        || domA.right < domB.left
        || domA.bottom < domB.top )
    {
        return false // 未碰撞
    } else {
        return true // 碰撞
    }
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)

圆形与圆形的碰撞:

判断任意两个圆形碰撞比较简单,只需要判断两个圆的圆心距离是否小于两圆半径之和,如果小于半径和,就可以判定两个圆发生碰撞。

图形示例:

简单算法实现

    let distance = Math.sqrt(Math.pow(x1 - x2) + Math.pow(y1 - y2) )
    if (distance < r1 + r2) { // r1、r2 分别为两圆的半径
        return true // 发生碰撞
    } else {
        return false //未发生碰撞
    }

圆形与矩形块的碰撞:

圆形与矩形发生碰撞的要点则是要找出矩形上距离圆心最近的点,然后通过判断该点与圆心的决定是否小于圆的半径,若小于则为碰撞。

点的位置,可以通过获取矩形某一个特定的定点坐标结合矩形宽高与圆的圆心进行比较确定。基本原理与两个矩形碰撞相似,但是略有差异,因为圆形有直接与矩形顶点碰撞的情况。

如下图所示,与矩形碰撞的区别在于,多出了处理矩形宽高延长线交叉区域的情况。当圆心位于两条平行边线之间时:矩形上与圆心最近的点为圆心垂直与矩形最近边线的交叉点;当圆心位于两条交叉边线之间时(如下图斜线区域),与圆心最近的点则是矩形交叉边线的顶点:

简单算法实现(B 圆只是做辅助说明)

    // 假设 矩形为 Box, 圆的半径为 R
    let distance
    if (x1 < Box.left && y1 > Box.top && y1 < Box.bottom) {
        // 位于上图中 圆 A 的 位置
        distance = Box.left - x1
    } else if ( x1 > Box.Right && y1 < Box.top ) {
        // 位于 上图中 圆 B 的位置
        distance = Math.sqrt(Math.pow(x1 - Box.right) + Math.pow(y1 - Box.top))
    }
    // 其他几种情况类似...按着顺/逆时针的顺序,总共八个区域就能全覆盖

    if (distance < R) {
        return true // 碰撞
    } else {
        return false // 未碰撞
    }
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)

还有一种涉及到多 DOM 碰撞的情况,一般业务需求是动态生成 DOM,占位,移动,然后再生成新 DOM,使他们不可重叠。通过查资料发现 地图碰撞 算法比较适合这样的场景。

地图碰撞算法

地图碰撞算法 主要是应用了矩阵的思想。即将拖拽区域进行数据化分割,划分成一个假想的数据地图,每一个小块算是一个独立的位置格子,通过标记状态来确定小格子是否被占用。然后应用最简单的 矩形碰撞 来判定拖动的 DOM 是否与格子发生碰撞,发生则将格子状态改为 1,未被占用则标记为 0。只有未被占用的格子可以被占用,占用的格子,释放后标记为 0。这种状态管理的方式,很适合结合 React、Vue 等前端框架做一些拖拽、碰撞的复杂业务交互。

图形示例:

简单思路实现

 // 区域是否可用 标记 矩阵
 let map = [
        [0, 1, 0, 0],
        [0, 0, 0, 0]
    ]
 // 设置初始位置
 let NewDom = { left: 0, top: 0}
 // 判断是否可安置
 ...
web前端开发学习Q-q-u-n: 731771211,分享学习的方法和需要注意的小细节,不停更新最新的教程和学习方法(详细的前端项目实战教学视频,PDF)

以上是比较主流的几种碰撞情况,以及主要的思路实现。目前业务有遇到碰撞需求,所以抽时间整理了下。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,012评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,628评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,653评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,485评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,574评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,590评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,596评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,340评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,794评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,102评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,276评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,940评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,583评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,201评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,441评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,173评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,136评论 2 352

推荐阅读更多精彩内容

  • 碰撞检测算法:点和矩形碰撞、点和圆形碰撞、矩形碰撞、圆形碰撞 点和矩形碰撞 /** * * @para...
    Lennie_S阅读 1,387评论 0 0
  • 参考官方文档 2D物理系统概述 一、基础概念 1.刚体rigidbody :刚体是指在运动中和受力作用后,形状和大...
    合肥黑阅读 6,484评论 3 1
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,094评论 1 32
  •   HTML5 添加的最受欢迎的功能就是 元素。这个元素负责在页面中设定一个区域,然后就可以通过 JavaScri...
    霜天晓阅读 3,006评论 0 2
  • 故事的开始 hello,XTU ——虽然也是上一个故事的结束 路过一些地方 也便假装拥有一些故事 ——你走过的都是...
    莫稀有阅读 381评论 0 0