js碰撞检测

碰撞检测

碰撞检测(边界检测)在前端游戏,以及涉及拖拽交互的场景应用十分广泛。
碰撞,顾名思义,就是两个物体碰撞在了一起,眼睛是可以直观的观察到碰撞的发生。但对于前端实现,如何让 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 // 碰撞
    }
     

圆形与圆形的碰撞:

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

图形示例:
在这里插入图片描述
简单算法实现

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

案例:碰撞换位

在这里插入图片描述

碰撞检测方案

        1. 何时不会发生碰撞
          1. box1.right < box2.left
          2. box1.bottom < box2.top
          3. box1.left > box.right
          4. box1.top > box2.bottom
          这四种情况只要满足一种 盒子就不可能发生碰撞(相交)
          反过来说 只要不满足这四种情况 盒子就是发生碰撞(相交)
        2. target 当前元素和多个元素进行循环碰撞检测
          如果target是也其他待检测元素的兄弟 那检测时要先排除掉 target自身
          和某一个元素发生碰撞时 isCollision(this.targetEle, aChild[i])
        3. 初始化让每个child都变成绝对定位 并且自动设置好对应的 top left
          DOM异步问题 js 操作DOM API 通过DOM API 提供的属性和方法来对页面上的实际标签进行增删改查处理 修改样式 修改元素的style属性的值 
          异步过程
          js => DOM
          js 循环中发出指令 让DOM根据我们js代码的操作指示 去页面上修改对应的标签渲染
          循环是非常快的 js不停的快速的发出指令 但是 DOM修改页面是需要时间的 什么时候修改完成 需要看你的内存执行速度
          异步 任务交给别人来做 自己不管
          DOM工厂处理事务的时候 修改left 修改top 修改position是并行处理
          复杂度越低的越容易优先处理完成
          修改left 和 top都需要先通过获取offet系列属性 
          修改position直接有现成的字符串 
          修改position先完成 然后完成了修改left和top
          导致效果和js代码对不上
          解决方案 
            1. 把可能会冲突的DOM操作 分不同循环来处理
            2. 让任务滞后处理的方式 setTimeout 任务队列异步插入的能力 
            定时器任务是讲子任务插入到主线程队列最后 等主线程任务都完成之后会执行子线程任务
              不让修改style的代码在循环的时候直接去做 而是缓一缓
              不要再赋值的时候去获取
          4. 密集型元素矩阵中 碰撞可能发生在多个元素上 和多个元素同时发生碰撞的时候 如何处理
             需求 只要一个发生碰撞的 距离target最近的这个
             如何辨别多个碰撞元素中距离最近的那一个
             判断其他被碰撞元素中 谁的左上角距离target的左上角直线距离最短
             直线距离怎么求 勾股定理 勾三股四玄五
             a=40 b=30 求c长  a,b < 90°
             c = Math.sqrt(a*a + b*b)
          5. 元素位置的交换
            1. 目标元素和碰撞元素互换位置
                把两个元素 本身排列顺序中所对应下标的 left 和 top 进行置换
            2.  变量互换
                temp = A
                A = B
                B = temp
            3. 取得两个元素的下标 target coll 
            4. 根据下标去tempArr 获取对应的 top left
              修改两个元素的 top 和left css
            5. 让tempArr中对应两个位置的值进行对换 为下一次互换重置
          6. 目标元素插入新位置 所有元素自动重新排列
            1. 序列置换  0 <=> 2  
            [0,1,2,3,4,5,6,7,8] = >  [1,2,0,3,4,5,6,7,8]
            2. 修改dom元素的顺序排列 
              1. 如何修改DOM元素的顺序 
                 不需要修改实际DOM树(运算压力太大) 
                 我们只需要提供一个虚拟DOM数组(替身)
            3. 根据修改后的虚拟DOM 数组顺序 去对应 tempArr中存储的位置 做样式修改
            4. 高频触发碰撞监测 => vDom数组 频繁操作 => translate频繁修改元素的位置 
                限制一下 => 加一把锁 交换完成之后 打开锁 交换过程中 关闭锁
                发生碰撞监测需要进行交换之前我们需要判断一下锁的状态 如果锁是打开的就可以进行后续...
          7. 如果targetEle 在某一个中间位置停留 被碰撞的coll不管移动到哪里都会发生碰撞
            解决:
            1.只有重叠面积大于1/2 或者 2/3才发生交互
              缺点: 布局间距小的话 重叠面积比例不好把握 而且 计算复杂
            2.加锁 刚碰撞过一次的元素 加锁 如果连续碰撞 锁生效 不触发置换 循环锁 
              缺点: 用户体验不好 相当于给用户行为加锁]
            3.解决不了问题 我们就解决提出问题的人
              换一种碰撞检测方式 
              介入检测 
              鼠标在元素之内 
              dom.left < pointer.x && dom.right > pointer.x && dom.top < pointer.y && dom.bottom > pointer.y

代码实现

<!--
 * @Author: your name
 * @Date: 2020-08-13 20:33:37
 * @LastEditTime: 2023-03-14 16:54:46
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Description: In User Settings Edit
 * @FilePath: \案例\case00.html
-->
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>碰撞监测</title>
  <style>
    * {
     
      user-select: none;
      margin: 0;
      padding: 0;
    }

    img {
     
      display: block;
      pointer-events: none;
    }

    html,
    body {
     
      height: 100%;

    }

    body {
     
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .wrap {
     
      display: flex;
      flex-wrap: wrap;
      justify-content: space-between;
      align-content: space-around;
      position: relative;
      width: 940px;
      height: 468px;
      padding: 10px;
      box-shadow: 0 0 8px #222;
      border-radius: 6px;
    }

    .wrap .child {
     
      overflow: hidden;
      box-shadow: 0 0 2px #ccc;
      border-radius: 3px;
      transition: .4s linear;
    }

    .wrap .child.active {
     
      z-index: 999;
      box-shadow: 0 0 8px #222;
      transition: none;
    <
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值