diff --git a/js/ItemManager.js b/js/ItemManager.js index 6edd26b..07caaf6 100644 --- a/js/ItemManager.js +++ b/js/ItemManager.js @@ -283,65 +283,4 @@ export class ItemManager { this._updateGroupCentres(); this._updateInterGroupLinks(); } - - // _createLinkLines() { - - // this.itemData.forEach(item => { - // if (!item.links) return; - - // item.links.forEach(linkedItemId => { - // // Goes through each connection; links = [0, 1, 2..] - // const linkedItem = this.itemData.get(linkedItemId); - // if (!linkedItem) return; - - // if (item.groupId !== linkedItem.groupId) return; - - // // Creates a key for the Set; a Set can only have unique values, so used for no overlap - // const key = [item.id, linkedItemId].sort().join('-'); - - // if (this.drawnLinks.has(key)) return; - - // const material = new THREE.LineDashedMaterial({ - // color: 0xffa500, - // dashSize: 10, - // gapSize: 1 - // }); - - // const sourcePos = item.spawnPosition.clone(); - // const terminalPos = linkedItem.spawnPosition.clone(); - // sourcePos.y = 1; terminalPos.y = 1; - - // const points = [item.spawnPosition.clone(), linkedItem.spawnPosition.clone()]; - // const geometry = new THREE.BufferGeometry().setFromPoints(points); - - // const line = new THREE.Line(geometry, material); - // line.computeLineDistances(); - - // this.scene.add(line); - - // // The Set is used as the key "0-1", then the item and the linkedItem are set as values in the Map? - // this.linkLines.set(key, { line, item1: item, item2: linkedItem }); - // // Make sure it is not drawn again, adding the unique pair here - // this.drawnLinks.add(key); - // }); - // }); - // } - - // _updateLinkLines() { - // this.linkLines.forEach(link => { - // const { line, item1, item2 } = link; - - // // Only update/show the line if both items are loaded - // if ((item1.loadState === 'loaded' && item2.loadState === 'loaded') - // && (item1.isVisible && item2.isVisible)) { - // line.visible = true; - // const positions = line.geometry.attributes.position; - // positions.setXYZ(0, item1.object.position.x, 1, item1.object.position.z); - // positions.setXYZ(1, item2.object.position.x, 1, item2.object.position.z); - // positions.needsUpdate = true; - // } else { - // line.visible = false; - // } - // }); - // } } \ No newline at end of file diff --git a/js/Player.js b/js/Player.js index 5af849c..a0c1d0a 100644 --- a/js/Player.js +++ b/js/Player.js @@ -85,13 +85,13 @@ export class Player { this.attachedItem = null; // Update player's position and rotation to match the camera's current state - this.position.copy(this.camera.position); - this.rotation.setFromQuaternion(this.camera.quaternion, 'YXZ'); + this.position.copy(this.playerRig.position); + this.rotation.setFromQuaternion(this.playerRig.quaternion, 'YXZ'); } else if(e.code == 'KeyF' && this.currentIntItem && !this.attachedItem){ this.attachedItem = this.currentIntItem; this.attachedItem.isActive = true; - //console.log("Attached item to player: ", this.attachedItem.object.name); + console.log("Attached item to player: ", this.attachedItem.object.name); } if (e.code === 'Space' && this.attachedItem) { @@ -463,7 +463,7 @@ export class Player { ray.ray.direction.set(0, 0, -1).applyMatrix4(new THREE.Matrix4().extractRotation(controllerMatrix)); } else { // Use camera for desktop interaction ray - ray.set(this.camera.position, this.camera.getWorldDirection(new THREE.Vector3())); + ray.setFromCamera({ x: 0, y: 0 }, this.camera); } const nearbyItems = this.itemList.filter(item => item.object && this.position.distanceTo(item.object.position) < this.maxInteractionDistance); @@ -473,17 +473,22 @@ export class Player { const intersects = ray.intersectObjects(itemObj, true); if (intersects.length > 0) { - const intersected = intersects[0].object; - // Find the item whose object contains the intersected mesh - const foundItem = nearbyItems.find(item => { - let found = false; - item.object.traverse(child => { - if (child === intersected) found = true; - }); - return found; - }); + let intersectedObject = intersects[0].object; + + // Traverse up to find the root object that is in our itemObj list + let rootObject = intersectedObject; + while (rootObject.parent && itemObj.indexOf(rootObject) === -1) { + rootObject = rootObject.parent; + } + + // Find the item that corresponds to this root object + const foundItem = nearbyItems.find(item => item.object === rootObject); if (foundItem) { + if (this.currentIntItem !== foundItem) { + // Optional: Add some visual feedback for the newly highlighted item + console.log("Hovering over:", foundItem.object.name); + } this.currentIntItem = foundItem; } else { this.currentIntItem = null; @@ -497,16 +502,26 @@ export class Player { const itemCenter = new THREE.Vector3(); new THREE.Box3().setFromObject(this.attachedItem.object).getCenter(itemCenter); - const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(this.camera.quaternion); - const targetPosition = itemCenter.clone().add(forward.multiplyScalar(2)); + // Get the camera's world position to correctly calculate the lookAt matrix + const cameraWorldPosition = new THREE.Vector3(); + this.camera.getWorldPosition(cameraWorldPosition); + + // Calculate the desired distance from the object + const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(this.playerRig.quaternion); + const desiredCameraPosition = itemCenter.clone().add(forward.multiplyScalar(2)); - this.camera.position.lerp(targetPosition, 0.1); + // Calculate the target position for the rig by subtracting the camera's local offset + // from the desired world position of the camera. + const targetPosition = desiredCameraPosition.clone().sub(this.camera.position); + this.playerRig.position.lerp(targetPosition, 0.1); + + // The target rotation should make the camera (not the rig) look at the item center. const targetRotation = new THREE.Quaternion().setFromRotationMatrix( - new THREE.Matrix4().lookAt(this.camera.position, itemCenter, this.camera.up) + new THREE.Matrix4().lookAt(cameraWorldPosition, itemCenter, this.playerRig.up) ); - this.camera.quaternion.slerp(targetRotation, 0.1); + this.playerRig.quaternion.slerp(targetRotation, 0.1); } _updatePlayerMovement(delta) { @@ -516,7 +531,7 @@ export class Player { this.rotation.x = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, this.rotation.x)); // Only update rotation here. Position will be updated in the main loop after the physics step. - this.camera.rotation.copy(this.rotation); + this.playerRig.rotation.copy(this.rotation); let direction = new THREE.Vector3(); if (this.input.forward) direction.z -= 1; @@ -531,6 +546,7 @@ export class Player { move.applyEuler(this.rotation); move.multiplyScalar(this.moveSpeed * delta); + // Updating the position of the RB based on the position calcuted by Rapier const newPosition = this.position.clone().add(move); if( newPosition.y <= 10 ) newPosition.y = 10; @@ -540,7 +556,7 @@ export class Player { } update(delta, spawnedObjects) { - //console.log(`Number of Controllers: ${this.vrControllers.length}`); + if (this.renderer.xr.isPresenting) { this._handleVRJoystick(); this._handleVRTeleport(spawnedObjects); diff --git a/js/main.js b/js/main.js index a0008ce..7e9bd3f 100644 --- a/js/main.js +++ b/js/main.js @@ -83,9 +83,7 @@ async function init() { player = new Player(rapierWorld, renderer, scene, new THREE.Vector3(0, 1, 0), interactableItems); player._setupVR(renderer); - scene.add(player.playerRig); - - //scene.add(player.camera); + scene.add(player.playerRig);; setupSocketIO(); @@ -153,7 +151,6 @@ async function animate() { // (2) Run a step of the physics sim rapierWorld.step(); - // // (3) Update the camera position, after physics step has run. const newPosition = player.rigibody.translation();