I started to follow several YouTube tutorials for playing with three.js for beginners. I saw one of the examples create three spheres floating in space and to make them clickable.
So I followed the tutorial on how to setup a three.js scene and created 6 3d objects that are cylinders. What I wanted is that...
if you click on an object, the camera points and looks at the object and the camera also transitions physically in front of that object, so i can display text or something there. Once there I'll restrict controls until the user clicks on the object where a tween will take them back to the original position and orientation.
I tried to have the logic be that if you click on object 1 && you haven't clicked on it before then go towards and look at it, else if you click on object 1 && if it HAD been clicked, then the camera will tween in reverse and orient back towards the origin... if else you click on object 2 && you haven't clicked on it before then go towards and look at it, else if you click on object 2 && if it HAD been clicked....... and so on and so on until both scenarios for each object is accounted for. I saw the tutorial do this on one object by creating a boolean variable to set the status to either have been or have not been clicked. I tried to incorporate that into my code but I think the problem is that the Javascript system is not marking or retaining the information that changes the variable to one or the other....it could be a syntax error, it could be that the approach i am taking isn't even possible (unknown unknowns), or a simple typo.
Once I made them 5 separate If statements then I was able to see each of the tweens go toward the object as I wanted but none of the tweens respond to the part that checks if they have already been clicked and to tween the camera back to the center.
here is my code with one of the 5 objects for reference....
//ONE OF THE OBJECTS FOR REFERENCE
const minigeometry1 = new THREE.CylinderGeometry(5, 5, 0.5, 50);
const minimaterial1 = new THREE.MeshStandardMaterial({ color: 0xffff00 });
const minicylinder1 = new THREE.Mesh(minigeometry1, minimaterial1);
minicylinder1.name = 'minicylinder1';
minicylinder1.position.z = 7.5;
minicylinder1.position.x = -28
minicylinder1.rotation.z = Math.PI / 2;
scene.add(minicylinder1);
//CLICK EVENT ANIMATIONS
//CAMERA MOVEMENT TWEEN FUNCTION//
function tweenCamera(finalPosition, tweenSpeed) {
let initialPosition = new THREE.Vector3(camera.position.x, camera.position.y, camera.position.z);
new TWEEN.Tween(initialPosition)
.to(finalPosition, tweenSpeed)
.onUpdate(() => {
camera.position.set(initialPosition.x, initialPosition.y, initialPosition.z);
})
.easing(TWEEN.Easing.Cubic.Out)
.start();
}
//WHERE THE CAMERA IS CURRENTLY LOOKING, I THINK
let currentTarget = new THREE.Vector3();
currentTarget.set(controls.target.x, controls.target.y, controls.target.z);
let originTarget = new THREE.Vector3();
originTarget.set(0,0,0);
//TELLS CAMERA TO ORIENT TOWARD SPECIFIED OBJECT (target controls = camera orientation?)
let minicylinder1Target = new THREE.Vector3();
minicylinder1Target.set(minicylinder1.position.x, minicylinder1.position.y, minicylinder1.position.z);
let minicylinder2Target = new THREE.Vector3();
minicylinder2Target.set(minicylinder2.position.x, minicylinder2.position.y, minicylinder2.position.z);
let minicylinder3Target = new THREE.Vector3();
minicylinder3Target.set(minicylinder3.position.x, minicylinder3.position.y, minicylinder3.position.z);
let minicylinder4Target = new THREE.Vector3();
minicylinder4Target.set(minicylinder4.position.x, minicylinder4.position.y, minicylinder4.position.z);
let minicylinder5Target = new THREE.Vector3();
minicylinder5Target.set(minicylinder4.position.x, minicylinder5.position.y, minicylinder5.position.z);
//RAYCASTER SETUP AND CLICK EVENT FUNCTION
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onClick(event) {
//Normalized mouse coordinates (-1, +1)
mouse.x = (event.offsetX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
//THIS DETERMINES WHETHER WE HAVE CLICKED ON AN OBJECT OR NOT
let coin1Clicked = false;
let coin2Clicked = false;
let coin3Clicked = false;
let coin4Clicked = false;
let coin5Clicked = false;
//IF WE CLICK ON COIN1 FROM THE MAIN POSITION, WE WILL ZOOM INTO IT
if ((getIndexInIntersectsArray(minicylinder1, intersects) > -1) && !coin1Clicked) {
//TWEEN TO ORIENT CAMERA TOWARDS COIN1
new TWEEN.Tween(currentTarget)
.to(minicylinder1Target, 2500)
.onUpdate(function() {
controls.target = currentTarget;
})
.easing(TWEEN.Easing.Quartic.InOut)
.start()
coin1Clicked = true;
//RESTRICT CAMERA ROTATION AND ZOOM OUT
tweenCamera(new THREE.Vector3(minicylinder1.position.x, minicylinder1.position.y, 25), 2500)
return coin1Clicked;
} else if ((getIndexInIntersectsArray(minicylinder1, intersects) > -1) && coin1Clicked) {
//TWEEN TO ORIENT CAMERA TOWARDS COIN1
new TWEEN.Tween(currentTarget)
.to(originTarget, 2500)
.onUpdate(function() {
controls.target = currentTarget;
})
.easing(TWEEN.Easing.Quartic.InOut)
.start()
coin1Clicked = false;
tweenCamera(new THREE.Vector3(origPos.position.x, origPos.position.y, origPos.position.z), 2500);
return coin1Clicked;
}
if ((getIndexInIntersectsArray(minicylinder2, intersects) > -1) && !coin2Clicked) {
//TWEEN TO ORIENT CAMERA TOWARDS COIN1
new TWEEN.Tween(currentTarget)
.to(minicylinder2Target, 2500)
.onUpdate(function() {
controls.target = currentTarget;
})
.easing(TWEEN.Easing.Quartic.InOut)
.start()
coin2Clicked = true;
//RESTRICT CAMERA ROTATION AND ZOOM OUT
tweenCamera(new THREE.Vector3(minicylinder2.position.x, minicylinder2.position.y, 25), 2500)
return coin2Clicked;
}
if ((getIndexInIntersectsArray(minicylinder3, intersects) > -1) && !coin3Clicked) {
//TWEEN TO ORIENT CAMERA TOWARDS COIN1
new TWEEN.Tween(currentTarget)
.to(minicylinder3Target, 2500)
.onUpdate(function() {
controls.target = currentTarget;
})
.easing(TWEEN.Easing.Quartic.InOut)
.start()
coin3Clicked = true;
//RESTRICT CAMERA ROTATION AND ZOOM OUT
tweenCamera(new THREE.Vector3(minicylinder3.position.x, minicylinder3.position.y, 25), 2500)
return coin3Clicked;
}
if ((getIndexInIntersectsArray(minicylinder4, intersects) > -1) && !coin4Clicked) {
//TWEEN TO ORIENT CAMERA TOWARDS COIN1
new TWEEN.Tween(currentTarget)
.to(minicylinder4Target, 2500)
.onUpdate(function() {
controls.target = currentTarget;
})
.easing(TWEEN.Easing.Quartic.InOut)
.start()
coin4Clicked = true;
//RESTRICT CAMERA ROTATION AND ZOOM OUT
tweenCamera(new THREE.Vector3(minicylinder4.position.x, minicylinder4.position.y, 25), 2500)
return coin4Clicked;
}
if ((getIndexInIntersectsArray(minicylinder5, intersects) > -1) && !coin5Clicked) {
//TWEEN TO ORIENT CAMERA TOWARDS COIN1
new TWEEN.Tween(currentTarget)
.to(minicylinder5Target, 2500)
.onUpdate(function() {
controls.target = currentTarget;
})
.easing(TWEEN.Easing.Quartic.InOut)
.start()
coin5Clicked = true;
//RESTRICT CAMERA ROTATION AND ZOOM OUT
tweenCamera(new THREE.Vector3(minicylinder5.position.x, minicylinder5.position.y, 25), 2500)
return coin5Clicked;
}
}
function getIndexInIntersectsArray(elem, array) {
var ind = -1;
for (var i = 0; i < array.length; i++) {
if (array[i].object.name == elem.name) {
ind = i;
}
}
return ind;
}
window.addEventListener("click", (event) => {
onClick(event);
})
var animate = function() {
requestAnimationFrame(animate);
cylinder.rotation.y += 0.025;
minicylinder1.rotation.y += 0.025;
minicylinder2.rotation.y += 0.025;
minicylinder3.rotation.y += 0.025;
minicylinder4.rotation.y += 0.025;
minicylinder5.rotation.y += 0.025;
controls.update();
render();
TWEEN.update();
};
function render() {
renderer.render(scene, camera);
}
animate();
Could anyone share any insight please? Pretty please? Thanks in advance!
P.S. if you feel my code is inefficient...I'm sure it is, I think i can use switch statements but i don't know how to do that yet as this is the FIRST project I've ever done so I have nothing to compare it with.
Note to self: after testing where the break in the flow of....processing/displaying? (I can't think of an appropriate word), by printing messages to the console to see what was/wasn't happening like I wanted, I realized that I had to put the
let coin1Clicked = false; . . . let coin5Clicked = false;
code OUTSIDE my onClick function. I don't know why though since I thought I was making them local variables (vs global variables) which shouldn't have been an issue, at least I thought. Once I made them global variables, the if...else statements are working! On to GSAP!