I’m not sure how to proceed with the code below. How would I add collision to this?
I would like to know where should the distance go and why? Thank you so much in advance.
original code:
https://threejs.org/examples/misc_controls_pointerlock.html
let raycaster;
class App extends Component {
componentDidMount() {
this.sceneSetup();
this.addCustomSceneObjects();
this.startAnimationLoop();
//
window.addEventListener("resize", this.handleWindowResize);
}
//
//
componentWillUnmount() {
window.removeEventListener("resize", this.handleWindowResize);
window.cancelAnimationFrame(this.requestID);
}
// 1
sceneSetup = () => {
this.objects = [];
//----------------
this.moveForward = false;
this.moveBackward = false;
this.moveLeft = false;
this.moveRight = false;
this.canJump = false;
this.prevTime = performance.now();
this.velocity = new THREE.Vector3();
this.direction = new THREE.Vector3();
this.vertex = new THREE.Vector3();
this.color = new THREE.Color();
// background color scene
// this.lemonChiffon = "rgb(240, 224, 190)";
//
//
// WIDTH/HEIGHT
// --------------------------------------------
//
const width = this.eleModelBlOne.clientWidth;
const height = this.eleModelBlOne.clientHeight;
//
// --------------------------------------------
//
this.camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// this.camera.position.y = 10;
//
this.camera.position.x = 0;
this.camera.position.y = 0;
this.camera.position.z = 58; // origin: 50
//
this.scene = new THREE.Scene();
// this.scene.background = new THREE.Color(0xffffff);
//
this.renderer = new THREE.WebGL1Renderer({
antialias: true,
});
//
this.renderer.setSize(width, height);
// BG color from the scene
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// showMap is connected to the shadows in any object/model
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.autoUpdate = true;
this.renderer.gammaFactor = 1;
//
// here you append it to the jsx
this.eleModelBlOne.appendChild(this.renderer.domElement); // mount using React ref
// document.appendChild(this.renderer.domElement); //before
//
this.blocker.appendChild(this.renderer.domElement);
//
//---------------------------
// PointerLockControl
//---------------------------
this.controls = new PointerLockControls(this.camera, this.eleModelBlOne);
//
this.scene.add(this.controls.getObject());
this.eleModelBlOne.addEventListener("click", () => {
this.controls.lock();
console.log("I clicked");
});
//
this.controls.addEventListener("lock", () => {
this.eleModelBlOne.style.display = "none";
});
//
this.controls.addEventListener("unlock", () => {
this.eleModelBlOne.style.display = "block";
this.eleModelBlOne.style.target = "_blank";
});
//-------------------------------
// KEYS
//-------------------------------
const onKeyDown = (event) => {
switch (event.code) {
case "ArrowUp":
case "KeyW":
this.moveForward = true;
break;
case "ArrowLeft":
case "KeyA":
this.moveLeft = true;
break;
case "ArrowDown":
case "KeyS":
this.moveBackward = true;
break;
case "ArrowRight":
case "KeyD":
this.moveRight = true;
break;
case "Space":
if (this.canJump === true) this.velocity.y += 350;
this.canJump = false;
break;
default:
}
};
const onKeyUp = (event) => {
switch (event.code) {
case "ArrowUp":
case "KeyW":
this.moveForward = false;
break;
case "ArrowLeft":
case "KeyA":
this.moveLeft = false;
break;
case "ArrowDown":
case "KeyS":
this.moveBackward = false;
break;
case "ArrowRight":
case "KeyD":
this.moveRight = false;
break;
default:
}
};
document.addEventListener("keydown", onKeyDown);
document.addEventListener("keyup", onKeyUp);
//
//
// this below is the original settings, NOW lets change for this:
raycaster = new THREE.Raycaster(
new THREE.Vector3(),
new THREE.Vector3(0, -1, 0),
0,
10
);
//
//
//
};
// 2
addCustomSceneObjects = () => {
//
this.loaderImg = new THREE.TextureLoader();
this.manager = new THREE.LoadingManager();
this.manager.onLoad = this.init;
//
//
//------------------ this will give you the name of the parent of the meshes
// but here we have no parent because we exported it form blender indiviadually
// in case we exported it like in the cars example, it will be different:
// cars example
const dumpObj = (obj, lines = [], isLast = true, prefix = "") => {
const localPrefix = isLast ? "└─" : "├─";
lines.push(
`${prefix}${prefix ? localPrefix : ""}${obj.name || "*no-name*"} [${
obj.type
}]`
);
const newPrefix = prefix + (isLast ? " " : "│ ");
const lastNdx = obj.children.length - 1;
obj.children.forEach((child, ndx) => {
const isLast = ndx === lastNdx;
dumpObj(child, lines, isLast, newPrefix);
});
return lines;
};
// DONT ADD INDIVIDUAL FOLDER FOR EACH MODEL, otherwise you will have an error
this.models = {
birdGiant: {
url: "./models/bbird-cube_detail.glb",
name: "Cube001",
},
hairyBubble: {
url: "./models/flower_hair-stair.glb",
name: "florecita-ball-center",
},
distiledFace: {
url: "./models/face-color.glb",
name: "facesculptureFontana",
},
faceDistiler: {
url: "./models/ojo_scene.glb",
name: "BezierCurve003",
},
};
//https://medium.com/swlh/load-countless-3d-objects-in-three-js-5e8d7c44cf3e
//https://stackoverflow.com/questions/15748656/javascript-reduce-on-object
// const total = Object.values(this.models).reduce(
// (acc, currValue) => acc + currValue
// );
// console.log(total);
//
//
//
//
const gltfLoader = new GLTFLoader(this.manager);
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath("myDecoder/");
gltfLoader.setDRACOLoader(dracoLoader);
for (const model of Object.values(this.models)) {
gltfLoader.load(model.url, (gltf) => {
//
//
this.textureAcidVelvet = this.loaderImg.load(
"./img/velvet_fuchsia-reduzed.jpg"
);
this.materialAcidVelvetMat = new THREE.MeshPhongMaterial({
shininess: -150,
side: THREE.DoubleSide,
emissive: new THREE.Color(-0.1, -0.1, 0.2),
});
//
//
//
gltf.scene.traverse((objectModel) => {
//
objectModel.castShadow = true;
objectModel.receiveShadow = true;
//----------------------------**
// Bird giant
//
if (objectModel.name === "Cube001") {
// console.log(objectModel.name);
//
objectModel.scale.set(15, 15, 15);
objectModel.position.x = -1;
objectModel.position.y = 260;
objectModel.position.z = -120;
this.meshToPlayWithAnimation = gltf.scene;
//
this.objects.push(objectModel);
}
//----------------------------**
//
// Hairy bubble
//
if (objectModel.name === "florecita-ball-center") {
// console.log(objectModel.name);
objectModel.castShadow = true;
// material / textures
objectModel.material = this.materialAcidVelvetMat;
this.materialAcidVelvetMat.map = this.textureAcidVelvet;
objectModel.side = THREE.DoubleSide;
//
objectModel.scale.set(13, 13, 13);
objectModel.position.x = -145;
objectModel.position.y = 68.5;
objectModel.position.z = -30;
//
//
//
this.objects.push(objectModel);
}
//
//----------------------------**
//
// DistiledFaceFontana
//
if (objectModel.name === "facesculptureFontana") {
// console.log(objectModel);
//
objectModel.scale.set(40, 40, 40);
objectModel.position.x = 0;
objectModel.position.y = 130;
objectModel.position.z = -255;
//
// material / textures
this.objects.push(objectModel);
}
//
//
//
//----------------------------**
//
// DistiledFace
//
if (objectModel.name === "BezierCurve003") {
objectModel.castShadow = true;
objectModel.receiveShadow = true;
// console.log(objectModel);
//
objectModel.scale.set(22, 22, 22);
objectModel.position.x = 0;
objectModel.position.y = 105;
objectModel.position.z = 240;
//
// material / textures
this.objects.push(objectModel);
}
//
//
//
});
this.scene.add(gltf.scene);
console.log(dumpObj(gltf.scene).join("\n"));
});
}
//
//
//
//----------------------------
// CLONED MODEL
//----------------------------
//
//
//
this.BirdMeshes = []; //related to the cloned birds
//
gltfLoader.load("./models/bbird-cube_detail.glb", (gltf) => {
//
// 1))____ add the following line
// with the this.meshToPlayWithAnimation , you can animate this model
gltf.scene.traverse((objectModel) => {
//----------------------------**
//
objectModel.receiveShadow = true;
objectModel.castShadow = true;
objectModel.scale.set(1, 1, 1);
// now the bird is on top
objectModel.position.z = -1;
objectModel.position.y = 10;
//
//
// console.log(objectModel); // CONSOLE
for (let i = 0; i < 50; i++) {
this.BirdMeshClone = objectModel.clone();
this.BirdMeshClone.position.x =
Math.floor(Math.random() * 20 - 10) * 50;
this.BirdMeshClone.position.y =
Math.floor(Math.random() * 20) * 40 + 50;
this.BirdMeshClone.position.z =
Math.floor(Math.random() * 20 - 10) * 50;
//
// this.BirdMeshClone = this.BirdMeshes;
this.scene.add(this.BirdMeshClone);
this.BirdMeshes.push(this.BirdMeshClone);
}
});
this.scene.add(gltf.scene);
});
//
//
//
//
//--------------------------
//
//--------------------------
// Clock
//
this.clock = new THREE.Clock();
this.delta = 0;
// 30 fps
this.interval = 1 / 30;
this.time2 = 0;
//
//
};
//
//
// 3
startAnimationLoop = () => {
//
this.requestID = window.requestAnimationFrame(this.startAnimationLoop);
//
// Save the current time
this.time = performance.now();
if (this.controls.isLocked === true) {
//
raycaster.ray.origin.copy(this.controls.getObject().position);
// A ray that emits from an origin in a certain direction.
raycaster.ray.origin.y -= 10;
raycaster.ray.origin.x -= 10;
//
this.intersections = raycaster.intersectObjects(this.objects, false);
this.onObject = this.intersections.length > 0;
// Create a delta value based on current time
this.delta = (this.time - this.prevTime) / 1000;
//
// Set the velocity.x and velocity.z using the calculated time delta
this.velocity.x -= this.velocity.x * 10.0 * this.delta;
this.velocity.z -= this.velocity.z * 10.0 * this.delta;
// As velocity.y is our "gravity," calculate delta
this.velocity.y -= 9.8 * 80.0 * this.delta; // 100.0 = mass
//
//
this.direction.z = Number(this.moveForward) - Number(this.moveBackward);
this.direction.x = Number(this.moveRight) - Number(this.moveLeft);
this.direction.normalize(); // this ensures consistent movements in all directions
if (this.moveForward || this.moveBackward)
this.velocity.z -= this.direction.z * 1000.0 * this.delta;
if (this.moveLeft || this.moveRight)
this.velocity.x -= this.direction.x * 400.0 * this.delta;
// ------------------- //
//
if (this.onObject === true) {
this.velocity.y = Math.max(0, this.velocity.y);
this.canJump = true;
}
this.controls.moveRight(-this.velocity.x * this.delta);
this.controls.moveForward(-this.velocity.z * this.delta);
this.controls.getObject().position.y += this.velocity.y * this.delta; // new behavior
//
//
// Prevent the camera/player from falling out of the 'world'
if (this.controls.getObject().position.y < 10) {
this.velocity.y = 0;
this.controls.getObject().position.y = 10;
this.canJump = true;
}
//
//
}
//
//
this.prevTime = this.time;
//
//
//
this.renderer.render(this.scene, this.camera);
};
/*
*/
handleWindowResize = () => {
const width = this.eleModelBlOne.clientWidth;
const height = this.eleModelBlOne.clientHeight;
// updated renderer
this.renderer.setSize(width, height);
// updated **camera** aspect ratio
this.camera.aspect = width / height;
// That is the Three.js optimization: you can group multiple camera changes into a block with only one
this.camera.updateProjectionMatrix();
};