#javascript #three.js #collision-detection #intersection #bounding-box
#javascript #three.js #обнаружение столкновений #пересечение #ограничивающий прямоугольник
Вопрос:
Привет, я работаю над базовой игрой breakout / arkanoid в ThreeJS. Прямо сейчас все, что у меня есть, это весло и мяч, который отскакивает по экрану. Я пытаюсь заставить столкновение работать так, чтобы, когда мяч попадает в весло, он отскакивал. Я пытался использовать ограничивающие рамки для достижения этой цели, однако я столкнулся с проблемой, когда .intersect /.intersectsBox неправильно регистрирует пересечение, и я не знаю почему. Ниже приведен код, который у меня есть до сих пор —
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry(5, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
var cubeBoxHelper = new THREE.BoxHelper(cube, 0xff0000);
var boundingBoxPaddle = new THREE.Box3().setFromObject(cubeBoxHelper);
cubeBoxHelper.update();
const geometrySphere = new THREE.SphereGeometry(1, 32, 32);
const materialSphere = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const sphere = new THREE.Mesh(geometrySphere, materialSphere);
var sphereBoxHelper = new THREE.BoxHelper(sphere, 0xff0000);
var boundingBoxBall = new THREE.Box3().setFromObject(sphereBoxHelper);
sphereBoxHelper.update();
scene.add(cube, cubeBoxHelper, sphere, sphereBoxHelper);
sphere.position.y = 5;
camera.position.z = 15;
camera.position.y = 10;
var xSpeed = 0.0005;
var dx = 0.1;
var dy = 0.1;
function bounce()
{
if (sphere.position.x < -19 || sphere.position.x > 18.5)
{
dx = -dx;
}
if (sphere.position.y < -5 || sphere.position.y > 19)
{
dy = -dy;
}
sphere.position.x = dx;
sphere.position.y = dy;
sphereBoxHelper.update();
}
function intersect()
{
if (boundingBoxBall.intersect(boundingBoxPaddle) == true)
{
console.log("intersection");
}
}
const animate = function ()
{
requestAnimationFrame(animate);
document.addEventListener("keydown", onDocumentKeyDown, false);
function onDocumentKeyDown(event)
{
var keyCode = event.which;
if (keyCode == 65 amp;amp; cube.position.x >= -18.5)
{
cube.position.x -= xSpeed;
}
else if (keyCode == 68 amp;amp; cube.position.x <= 18)
{
cube.position.x = xSpeed;
}
cubeBoxHelper.update();
};
bounce();
intersect();
sphereBoxHelper.update();
renderer.render(scene, camera);
};
animate();
Прямо сейчас я установил его так, чтобы функция intersect просто регистрировалась на консоли, чтобы я мог сказать, что происходит. Любая помощь была бы отличной, поскольку я не уверен, что я делаю неправильно.
Ответ №1:
.intersect ( box : Box3 ) : это поле — поле для пересечения.
Вычисляет пересечение this и box, устанавливая верхнюю границу этого поля на меньшую из верхних границ двух блоков, а нижнюю границу этого поля на большую из нижних границ двух блоков. Если перекрытия нет, делает это поле пустым.
То, что на самом деле делает эта функция, — это обновление boundingBoxBall
с помощью информации boundingBoxPaddle
и, возможно, даже установка boundingBoxBall
пустого поля!
Я думаю, что функция, которую вы действительно ищете, это:
.intersectsBox ( box : Box3 ) : логическое поле — поле для проверки на пересечение.
Определяет, пересекается ли это поле с полем.
intersectsBox
Функция возвращает простое true
/ false
, чтобы вы могли определить, столкнулись ли два поля.
Также обратите внимание, что ваша ограничивающая рамка относится к связанной геометрии. Если вы преобразуете Mesh
, то вам также нужно будет преобразовать ограничивающую рамку. Пример кода на самом Box3 docs
деле подчеркивает это:
const box = new THREE.Box3();
// ...
// in the animation loop, compute the current bounding box with the world matrix
box.copy( mesh.geometry.boundingBox ).applyMatrix4( mesh.matrixWorld );
Полный пример:
let W = window.innerWidth;
let H = window.innerHeight;
const renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(28, 1, 1, 1000);
camera.position.set(0, 0, 50);
camera.lookAt(scene.position);
scene.add(camera);
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 0, -1);
camera.add(light);
let geo = new THREE.BoxBufferGeometry(5, 5, 5);
geo.computeBoundingBox();
let mat = new THREE.MeshPhongMaterial({
color: "red"
});
const left = new THREE.Mesh(geo, mat);
left.position.set(-15, 0, 0)
scene.add(left);
const right = new THREE.Mesh(geo, mat);
right.position.set(15, 0, 0)
scene.add(right);
geo = new THREE.SphereBufferGeometry(1, 16, 16);
geo.computeBoundingBox();
mat = new THREE.MeshPhongMaterial({
color: "yellow"
});
const ball = new THREE.Mesh(geo, mat);
scene.add(ball);
function render() {
renderer.render(scene, camera);
}
function resize() {
W = window.innerWidth;
H = window.innerHeight;
renderer.setSize(W, H);
camera.aspect = W / H;
camera.updateProjectionMatrix();
render();
}
let rate = 0.1;
let goingRight = true;
let ballBox = new THREE.Box3();
let wallBox = new THREE.Box3();
function animate() {
render();
ball.position.x = ((goingRight) ? 1 : -1) * rate;
ball.updateMatrix();
ball.updateMatrixWorld(true);
ballBox.copy(ball.geometry.boundingBox);
ballBox.applyMatrix4(ball.matrixWorld);
if (goingRight) {
wallBox.copy(right.geometry.boundingBox);
wallBox.applyMatrix4(right.matrixWorld);
if (ballBox.intersectsBox(wallBox)) {
goingRight = false;
}
} else {
wallBox.copy(left.geometry.boundingBox);
wallBox.applyMatrix4(left.matrixWorld);
if (ballBox.intersectsBox(wallBox)) {
goingRight = true;
}
}
requestAnimationFrame(animate);
}
window.addEventListener("resize", resize);
resize();
requestAnimationFrame(animate);
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
background: skyblue;
}
<script src="https://threejs.org/build/three.min.js"></script>
Комментарии:
1. Проблема, с которой я все еще сталкиваюсь, заключается в том, что даже если я использую .intersectsBox вместо этого, он продолжает постоянно регистрировать пересечение на консоли, даже если ограничительные рамки to вообще не пересекаются.
2. @OliverCollier Я добавил еще немного информации, которая может быть полезной. Ваши ограничивающие рамки являются локальными для их фигур, поэтому вам необходимо обновить их, чтобы они соответствовали текущей пространственной ориентации фигуры.
3. Попробовал ваше предложение и не повезло. Даже когда ограничивающие рамки полностью разделены, он все равно постоянно регистрирует intersect. Я понятия не имею, что я здесь сделал не так
4. @OliverCollier Я добавил полный, доступный для запуска пример мяча, прыгающего между двумя полями, наблюдая за пересечениями ограничивающих рамок. Если у вас по-прежнему возникают проблемы после просмотра приведенной здесь логики, пожалуйста, обновите свой вопрос обновленным кодом, чтобы мы могли увидеть, что может пойти не так.
5. Спасибо, я попробую