资讯专栏INFORMATION COLUMN

简析 js 碰撞检测原理与算法实现

Miyang / 862人阅读

摘要:碰撞检测边界检测在前端游戏,以及涉及拖拽交互的场景应用十分广泛。这就涉及到碰撞检测或者叫边界检测的问题了。若四边均未发生重合,则未发生碰撞,反之则发生碰撞。目前业务有遇到碰撞需求,所以抽时间整理了下。

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

那么啥叫碰撞?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 // 碰撞
    }
     
圆形与圆形的碰撞:

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

图形示例:

简单算法实现

    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 // 未碰撞
    }

还有一种涉及到多 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}
 // 判断是否可安置
 ...

以上是比较主流的几种碰撞情况,以及主要的思路实现。目前业务有遇到碰撞需求,所以抽时间整理了下。圆形和矩形碰撞的情况感觉还可以优化下,如果有好的思路,可以互相学习下。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/117124.html

相关文章

  • 简析 js 碰撞检测原理算法实现

    摘要:碰撞检测边界检测在前端游戏,以及涉及拖拽交互的场景应用十分广泛。这就涉及到碰撞检测或者叫边界检测的问题了。若四边均未发生重合,则未发生碰撞,反之则发生碰撞。目前业务有遇到碰撞需求,所以抽时间整理了下。 碰撞检测(边界检测)在前端游戏,以及涉及拖拽交互的场景应用十分广泛。 那么啥叫碰撞?JavaScript 又是如何检测 DOM 发生碰撞的呢? 碰撞,顾名思义,就是两个物体碰撞在了一起,...

    Markxu 评论0 收藏0
  • js随手笔记-------理解JavaScript碰撞检测算法核心简单实现原理

    摘要:通用算法概念模型圆形与矩形之间的碰撞核心理念通过找出矩形上离圆心最近的点,然后通过判断该点与圆心的距离是否小于圆的半径,若小于则为碰撞。 碰撞检测在前端游戏,设计拖拽的实用业务等领域的应用场景非常广泛,今天我们就在这里对于前端JavaScript如何实现碰撞检测算法进行一个原理上的探讨,让大家能够明白如何实现碰撞以及碰撞的理念是什么:1.矩形与矩形间的碰撞核心理念判断任意两个(无旋转)...

    hikui 评论0 收藏0
  • 某数加密的流程原理简析

    摘要:前言啃了这么长时间,基本上已经把某数的套路摸了个八九不离十,不愧是中国反爬界的集大成者,感觉收获满满,这里就简单记录一下分析成果。注意某数在不同的网站上有不同的版本,其流程也略有不同,这里的流程不一定适用于其它网站。 showImg(https://segmentfault.com/img/remote/1460000018765904); 前言 啃了这么长时间,基本上已经把某数的套路...

    dkzwm 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<