Проблема с откликом raycaster three.js
Проблема в чем: -Есть 3 куба и по клику на них они передвигаются, при повторном возвращаются в начальное положение
НО! если я нажимаю не на куб, а на любое другое место на экране то мне выдает ошибку что такой объект не найден.
Uncaught TypeError: Cannot read properties of undefined (reading 'object')
как мне реализовать реагирование только на клик по кубу.(отлавливать и проглатывать ошибку я не хочу)
Я думаю проблема не в самом raycaster, а в window.addEventListener который и не находит куб на window
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import TWEEN from 'three/examples/jsm/libs/tween.module';
import './style.css';
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 ); // рендерим
renderer.setClearColor(0x9BCFFF);
const canvas = document.body.appendChild( renderer.domElement );
const controls = new OrbitControls(camera,canvas);
controls.enableDamping = true;
const geometry = new THREE.BoxGeometry( 1, 1, 1 ); //геомертрия куба
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); //материал - цвет
const material1 = new THREE.MeshBasicMaterial( { color: 0x039BCF } );
const material2 = new THREE.MeshBasicMaterial( { color: 0x50D445 } );
const cube = new THREE.Mesh( geometry, material );
const tpiyg = new THREE.TetrahedronGeometry(1,0);
const trh = new THREE.Mesh(tpiyg,material2);
trh.position.y = 2;
scene.add(trh);
const cube1 = new THREE.Mesh( geometry, material1 );
const cube2 = new THREE.Mesh( geometry, material2 ); // собираем куб
const grupa = new THREE.Group();
cube.position.x = -3;
cube2.position.x = 3;
grupa.add(cube,cube1,cube2);
console.log('позиция куба:',cube.position);
console.log('позиция куба1:',cube1.position);
console.log('позиция куба2:',cube2.position);
let mouseX = 0,mouseY = 0;
//клик
let stat = 0;
let stat1 = 0;
let stat2 = 0;
const cast = new THREE.Raycaster();
console.log(cast);
const handclick = (event)=>{
const pointer = new THREE.Vector2();
pointer.x = (event.clientX / window.innerWidth)*2-1;
pointer.y = -(event.clientY / window.innerHeight) *2+1;
cast.setFromCamera(pointer,camera);
const inter = cast.intersectObject(grupa,true);
console.log('ssss',inter[0].object.id);
// console.log(inter[0].normal.x)
if(stat == 0 && stat1 == 0 && stat2 == 0){
inter[0].object.material.color.set('black');
if (inter[0].object.id == 11){
stat++;
}else if(inter[0].object.id == 13){
stat1++
}else if(inter[0].object.id == 14){
stat2++
};
new TWEEN.Tween(inter[0].object.position).to({
x:0,
y:0,
z:3,
},Math.random()*1000+1000).easing(TWEEN.Easing.Exponential.InOut).start();
}else{
// inter[0].object.material.color.set(0x00ff00 );
console.log(inter)
if(inter[0].object.id == 11){
inter[0].object.material.color.set(0x00ff00 );
new TWEEN.Tween(inter[0].object.position).to({
x:-3,
y:0,
z:0,
},Math.random()*1000+1000).easing(TWEEN.Easing.Exponential.InOut).start();
stat = 0 ;
}else if(inter[0].object.id == 13){
inter[0].object.material.color.set(0x039BCF );
new TWEEN.Tween(inter[0].object.position).to({
x:0,
y:0,
z:0,
},Math.random()*1000+1000).easing(TWEEN.Easing.Exponential.InOut).start();
stat1 = 0;
}else if(inter[0].object.id == 14){
inter[0].object.material.color.set(0x50D445 );
new TWEEN.Tween(inter[0].object.position).to({
x:3,
y:0,
z:0,
},Math.random()*1000+1000).easing(TWEEN.Easing.Exponential.InOut).start();
stat2 = 0;
};
};
console.log('статус0', stat);
console.log('статус1', stat1);
console.log('статус2', stat2);
};
function updateConePosition() {
let targetX = mouseX / window.innerWidth * 2 - 1;
let targetY = -mouseY / window.innerHeight * 2 + 1;
let vector = new THREE.Vector3(targetX, targetY, camera.position.z - 1);
vector.unproject(camera);
let dir = vector.sub(camera.position).normalize();
let distance = -camera.position.z / dir.z;
let pos = camera.position.clone().add(dir.multiplyScalar(distance));
cone.position.copy(pos);
}
window.addEventListener('click',handclick)
scene.add(grupa);
camera.position.z = 5;// позиция камеры по
let cursor = {
x: 0,
y: 0,
z: 0,
};
const clock = new THREE.Clock();
function animate() { requestAnimationFrame( animate );
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
cube2.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
let size = {
x: window.innerWidth,
y: window.innerHeight,
};
window.addEventListener('mousemove',(event)=>{
cursor.x = -(event.clientX / size.x - 0.5);
cursor.y = (event.clientY / size.y - 0.5);
camera.lookAt(grupa.position);
});
const tick = ()=>{
controls.update();
TWEEN.update();
renderer.render(scene,camera);
window.requestAnimationFrame(tick);
}
tick()
window.addEventListener('resize', ()=>
{
size.x = window.innerWidth;
size.y = window.innerHeight;
camera.aspect = size.x / size.y;
camera.updateProjectionMatrix();
renderer.setSize(size.x,size.y);
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));
renderer.render(scene,camera);
});
window.addEventListener('dblclick',()=>
{
if(document.fullscreenElement){
document.exitFullscreen();
}else{
canvas.requestFullscreen();
}
})
Ответы (1 шт):
В общем решение я нашел, но вопрос оставлю и надеюсь помогу таким как я. Как я понимаю я искал объект используя:
const inter = cast.intersectObject(grupa,true);
*при этом объекты в группе
из-за этого он возможно и выдавал ошибку
Ну и решение
Кубы я пушнул в список:
let boxs = [];
boxs.push(cube,cube1,cube2);
Заменил:
const inter = cast.intersectObject(grupa);
На:
const inter = cast.intersectObjects(boxs);
И далее через цикл уже делал свои дела:
for(let obj of inter){
obj.object.material.color.set('white'); // тут типо мой прошлый код, но inter[0] теперь obj
Старался по понятнее для чайников как я