js中实现碰撞检测
原理:
在html的坐标系中,横轴向右为正,纵轴向下为正,将红色方块命名为a,蓝色方块命名为b。四个蓝色方块代表了四个不同方向。t1(2)、b1(2)、l1(2)、r1(2)分别表示红色(蓝色)方块的上偏移量、高度、左偏移量和宽度,当r2 < l1 、 r1 < l2 、 b2 < t1、 b1 < t2时,两方块不会碰撞。
原文链接:https://blog.youkuaiyun.com/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;
}
}
threejs中实现碰撞检测
官方的方法 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.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、如果有旋转,注意 Box3 获取的也是没有旋转的 Object 的包围盒
包围盒 + 位置判断碰撞的方法,存在使用有局限性,仅思路仅供参考
文章介绍了如何在JavaScript中进行基本的碰撞检测,以及在Three.js中利用ammo.js和射线进行更复杂的3D碰撞检测。同时提到了使用Box3计算物体包围盒以辅助检测,并指出了这些方法的局限性和注意事项。
3154

被折叠的 条评论
为什么被折叠?



