JS函数实现碰撞检测

js中实现碰撞检测

原理:

在html的坐标系中,横轴向右为正,纵轴向下为正,将红色方块命名为a,蓝色方块命名为b。四个蓝色方块代表了四个不同方向。t1(2)、b1(2)、l1(2)、r1(2)分别表示红色(蓝色)方块的上偏移量、高度、左偏移量和宽度,当r2 < l1 、 r1 < l2 、 b2 < t1、 b1 < t2时,两方块不会碰撞。

原文链接:https://blog.csdn.net/m0_50947589/article/details/124981691

JS函数实现碰撞检测_第1张图片
function isCrash(a,b){
        var l1 = a.offsetLeft;
        var t1 = a.offsetTop;
        var r1 = l1 + a.offsetWidth;
        var b1 = t1 + a.offsetHeight;
        // offsetLeft值为与设置position属性的父盒子的距离
        var l2 = b.offsetLeft;
        var t2 = b.offsetTop;
        // offsetWidth: 为元素的width+元素的padding+边框的宽度
        var r2 = l2 + b.offsetWidth;
        var b2 = t2 + b.offsetHeight;
        if(r2 < l1 || r1 < l2 || b2 < t1 || b1 < t2){
            return false;
        }else{
            return true;
        }
    }

threejs中实现碰撞检测

  1. 官方的方法 ammo.js

  1. 案例

  1. 中文文档

  1. 使用射线

  1. 原理

  1. 用Raycaster来检测碰撞的原理很简单,我们需要以物体的中心为起点,向各个顶点(vertices)发出射线,然后检查射线是否与其它的物体相交。如果出现了相交的情况,检查最近的一个交点与射线起点间的距离,如果这个距离比射线起点至物体顶点间的距离要小,则说明发生了碰撞。

  1. 检测光线是否与物体相交使用的是 intersectObject( object, recursive ) 或 intersectObjects 方法: 相交的结果会以一个数组的形式返回,其中的元素依照距离排序,越近的排在越前

/**
 * 功能:检测 movingCube 是否与数组 collideMeshList 中的元素发生了碰撞
 * 
 */
var originPoint = movingCube.position.clone();
 
for (var vertexIndex = 0; vertexIndex < movingCube.geometry.vertices.length; vertexIndex++) {
 // 顶点原始坐标
 var localVertex = movingCube.geometry.vertices[vertexIndex].clone();
 // 顶点经过变换后的坐标
 var globalVertex = localVertex.applyMatrix4(movingCube.matrix);
 // 获得由中心指向顶点的向量
 var directionVector = globalVertex.sub(movingCube.position);
 
 // 将方向向量初始化
 var ray = new THREE.Raycaster(originPoint, directionVector.clone().normalize());
 // 检测射线与多个物体的相交情况
 var collisionResults = ray.intersectObjects(collideMeshList);
 // 如果返回结果不为空,且交点与射线起点的距离小于物体中心至顶点的距离,则发生了碰撞
 if (collisionResults.length > 0 && collisionResults[0].distance < directionVector.length()) {
  crash = true; // crash 是一个标记变量
 }
}
  1. 缺陷

  1. 当物体的中心在另一个物体内部时,是不能够检测到碰撞的。而且当两个物体能够互相穿过,且有较大部分重合时,检测效果也不理想。

  1. 注意点

  1. 在Three.js中创建物体时,它的顶点(veritces)数目是与它的分段数目相关的,分段越多,顶点数目越多。为了检测过程中的准确度考虑,需要适当增加物体的分段。

  1. 自己实现

  1. 使用 Three.Box3 计算物体的包围盒的长宽高

class DashLinesBoxTool{   
    /**
     * 根据 Object 计算几何长宽高, 并 Vector3 形式返回
     * @param {Object} object
     */
    static getObjectBoxSize(object){
        const box3 = new Three.Box3()// 
        //box3:示例{max: Vector3 {x: 3.5, y: 0.5, z: 0.5},min: Vector3 {x: 2.5, y: -0.5, z: -0.5}}
        // min代表最低边界的xyz,max代表最高边界
        box3.expandByObject(object) // 获得object模型的包围盒
        const v3 = new Three.Vector3()
        box3.getSize(v3) //将会把box的长宽高拷贝给v3,并返回box3的长宽高
 
        console.log("v3 ", v3) // 获得一个三位坐标对象{x,y,z}
        return v3
    }
}
  1. 然后根据移动物体与其他物体的位置差,同移动物体与其他物体包围盒对应的长宽高之和的一半,如果位置差的xyz 都小于移动物体与某个物体包围盒长宽高之和的一半,则可判断碰撞

 /**
               * 判断是否碰撞
               */
              function isJudgeCollision(){
                  // 声明一个变量用来表示是否碰撞
                  var moveV3 = DashLinesBoxTool.getObjectBoxSize(curMoveObject)
                  var filterObjArr = filterObjects(objectsMesh, curMoveObject)
                  for (var i = 0; i < filterObjArr.length; i++) {
                      var v3 = DashLinesBoxTool.getObjectBoxSize(filterObjArr[i])
                    
                    // 移动物体与场景配置位置之差
                    var xValue = Math.abs(filterObjArr[i].position.x - curMoveObject.position.x)
                    var yValue = Math.abs(filterObjArr[i].position.y - curMoveObject.position.y)
                    var zValue = Math.abs(filterObjArr[i].position.z - curMoveObject.position.z)
                    
                    console.log(" filterObjArr[i].position,  curMoveObject.position ", filterObjArr[i].position , curMoveObject.position )
                    
                    // 移动物体与场景物体包围盒长宽高一半
                    var xCollision = Math.abs(moveV3.x+v3.x) / 2.0
                    var yCollision = Math.abs(moveV3.y+v3.y) / 2.0
                    var zCollision = Math.abs(moveV3.z+v3.z) / 2.0
                    
                    console.log(" xValue , yValue , xCollision , yCollision ", xValue , yValue , xCollision , yCollision )
                    // 位置之差小于长/宽/高和的一半,则发生碰撞
                    if(xValue < xCollision && yValue < yCollision && zValue < zCollision){
                        return true
                    }
                  }
                 
                  return false
              }
  1. 注意事项

  1. 1、如果有旋转,注意 Box3 获取的也是没有旋转的 Object 的包围盒

  1. 包围盒 + 位置判断碰撞的方法,存在使用有局限性,仅思路仅供参考

你可能感兴趣的:(javascript,前端,vue.js)