Javascript 仅检测第一次碰撞(使用光线投射进行碰撞检测)
我正在构建一个无休止的跑步者风格的游戏,其中(0,0)处的角色只能在X轴上左右移动(使用箭头键或鼠标)。有两种类型的对象从Javascript 仅检测第一次碰撞(使用光线投射进行碰撞检测),javascript,three.js,Javascript,Three.js,我正在构建一个无休止的跑步者风格的游戏,其中(0,0)处的角色只能在X轴上左右移动(使用箭头键或鼠标)。有两种类型的对象从z=-10000向角色移动,一旦它们到达z=10000(即在角色后面和屏幕外),它们将重置为z=-10000我正在使用以下光线投射代码检测角色和两种类型对象之间的碰撞 本质上,光线是在渲染循环的每一帧中从每个角色顶点发射的。如果光线与一个对象顶点相交,且距离接近角色(不确定其使用的确切距离),则会检测到碰撞 let cooldown = false; let objectMe
z=-10000
向角色移动,一旦它们到达z=10000
(即在角色后面和屏幕外),它们将重置为z=-10000
我正在使用以下光线投射代码检测角色和两种类型对象之间的碰撞
本质上,光线是在渲染循环的每一帧中从每个角色顶点发射的。如果光线与一个对象顶点相交,且距离接近角色(不确定其使用的确切距离),则会检测到碰撞
let cooldown = false;
let objectMesh;
let collisionResults;
let timeout;
function detectCollisionRaycaster(originObject, collidedObjects) {
if (this.isCollision(originObject, collidedObject)) {
cooldown = true;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function () {
cooldown = false;
}, 500);
}
}
function isCollision(originObject, collidedObjects) {
let originPoint = originObject.position.clone();
for (var vertexIndex = 0; vertexIndex < objectMesh.geometry.vertices.length; vertexIndex++) {
var localVertex = objectMesh.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4( objectMesh.matrix );
var directionVector = globalVertex.sub( objectMesh.position );
var raycaster = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
collisionResults = raycaster.intersectObjects( collidedObjects, true );
if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() && !cooldown) {
console.info("Object Collided");
return true;
}
}
return false;
}
这是我的代码:
这将在渲染循环中运行:
detectCollisionRaycaster(character, objectsArray);
这是碰撞检测功能:
let cooldown = false;
let objectMesh;
let collisionResults;
function detectCollisionRaycaster(originObject, collidedObjects) {
let originPoint = originObject.position.clone();
for (var vertexIndex = 0; vertexIndex < objectMesh.geometry.vertices.length; vertexIndex++) {
var localVertex = objectMesh.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4( objectMesh.matrix );
var directionVector = globalVertex.sub( objectMesh.position );
var raycaster = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
collisionResults = raycaster.intersectObjects( collidedObjects, true );
if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() && !cooldown) {
cooldown = true;
console.info("Object Collided");
setTimeout(function(){
collisionResults.length = 0;
cooldown = false;
}, 500);
}
}
}
让冷却时间=假;
让物体啮合;
让冲突产生结果;
功能检测碰撞光线投射器(原始对象、碰撞对象){
让originPoint=originObject.position.clone();
对于(变量vertexIndex=0;vertexIndex0&&collisionResults[0]。距离
问题
碰撞代码已触发多次。我非常确定这是因为对象正朝角色移动,因此对象的顶点与光线碰撞超过一帧,因此只要对象在敌人的“内部”,碰撞代码就会运行
我想要什么:
我希望碰撞检测代码显式触发一次,暂停碰撞检测一段时间,直到对象不再与角色碰撞,然后继续检测碰撞
我尝试过的
我尝试在碰撞检测代码中设置一个超时函数,我认为该函数将停止在渲染循环中运行碰撞检测,直到该时间结束,但它似乎只需要运行一次代码,暂停超时,然后在对象运行的所有时间继续运行碰撞检测代码字符的“内部”。由于在发现冲突时没有终止循环,因此即使满足
条件,它也会继续执行剩余的迭代
类似这样的方法可以帮助您更好地组织逻辑,因为它可以分离出您对以前的冲突检测方法所承担的一些责任。通过两种方法,我们将您的逻辑分离为一种,它只告诉我们是否发生了冲突(isCollision
),以及另一种方法,该方法使用isCollision
在检测到碰撞时适当设置冷却时间
let cooldown = false;
let objectMesh;
let collisionResults;
let timeout;
function detectCollisionRaycaster(originObject, collidedObjects) {
if (this.isCollision(originObject, collidedObject)) {
cooldown = true;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function () {
cooldown = false;
}, 500);
}
}
function isCollision(originObject, collidedObjects) {
let originPoint = originObject.position.clone();
for (var vertexIndex = 0; vertexIndex < objectMesh.geometry.vertices.length; vertexIndex++) {
var localVertex = objectMesh.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4( objectMesh.matrix );
var directionVector = globalVertex.sub( objectMesh.position );
var raycaster = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
collisionResults = raycaster.intersectObjects( collidedObjects, true );
if ( collisionResults.length > 0 && collisionResults[0].distance < directionVector.length() && !cooldown) {
console.info("Object Collided");
return true;
}
}
return false;
}
让冷却时间=假;
让物体啮合;
让冲突产生结果;
让超时;
功能检测碰撞光线投射器(原始对象、碰撞对象){
if(此.isCollision(原始对象、碰撞对象)){
冷却时间=真;
如果(超时){
clearTimeout(超时);
}
超时=设置超时(函数(){
冷却时间=假;
}, 500);
}
}
函数isCollision(原始对象、碰撞对象){
让originPoint=originObject.position.clone();
对于(变量vertexIndex=0;vertexIndex0&&collisionResults[0]。距离
编辑:这将保持冷却,直到没有对象与玩家发生碰撞。如果你想设置它,以便暂停直到触发碰撞的特定对象是被检查的对象,那么你需要保留对该对象的引用并检查它,而不是针对全套玩家tices+对象。一种方法是从isCollision
方法返回对碰撞对象的引用,而不是布尔值,然后使用另一种方法从该对象显式地光线投射到播放器顶点,以确定碰撞何时结束。非常感谢,这解决了我的问题,并且完全正确我在问题中问了什么!:)如果我试图删除碰撞检测代码中的碰撞对象(在return true
之前的一行),它会中断并返回多次运行碰撞检测代码…知道为什么吗?我正在使用此代码删除对象:scene.remove(scene.getObjectByName(collisionResults[0].object.parent.name));
我觉得这是因为