原理:
在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
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;}}
官方的方法 ammo.js
案例
中文文档
使用射线
原理
用Raycaster来检测碰撞的原理很简单,我们需要以物体的中心为起点,向各个顶点(vertices)发出射线,然后检查射线是否与其它的物体相交。如果出现了相交的情况,检查最近的一个交点与射线起点间的距离,如果这个距离比射线起点至物体顶点间的距离要小,则说明发生了碰撞。
检测光线是否与物体相交使用的是 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 是一个标记变量}
}
缺陷
当物体的中心在另一个物体内部时,是不能够检测到碰撞的。而且当两个物体能够互相穿过,且有较大部分重合时,检测效果也不理想。
注意点
在Three.js中创建物体时,它的顶点(veritces)数目是与它的分段数目相关的,分段越多,顶点数目越多。为了检测过程中的准确度考虑,需要适当增加物体的分段。
自己实现
使用 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}
}
然后根据移动物体与其他物体的位置差,同移动物体与其他物体包围盒对应的长宽高之和的一半,如果位置差的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.0var yCollision = Math.abs(moveV3.y+v3.y) / 2.0var zCollision = Math.abs(moveV3.z+v3.z) / 2.0console.log(" xValue , yValue , xCollision , yCollision ", xValue , yValue , xCollision , yCollision )// 位置之差小于长/宽/高和的一半,则发生碰撞if(xValue < xCollision && yValue < yCollision && zValue < zCollision){return true}}return false}
注意事项
1、如果有旋转,注意 Box3 获取的也是没有旋转的 Object 的包围盒
包围盒 + 位置判断碰撞的方法,存在使用有局限性,仅思路仅供参考
下一篇:数据库HA产品比较