diff --git a/character-controller.js b/character-controller.js index 2f1b7b0048..4c4a70465c 100644 --- a/character-controller.js +++ b/character-controller.js @@ -1136,10 +1136,16 @@ class LocalPlayer extends UninterpolatedPlayer { }); } grab(app, hand = 'left') { - const {position, quaternion} = _getSession() ? - localPlayer[hand === 'left' ? 'leftHand' : 'rightHand'] - : - camera; + let position = null, quaternion = null; + + if(_getSession()) { + const h = this[hand === 'left' ? 'leftHand' : 'rightHand']; + position = h.position; + quaternion = h.quaternion; + } else { + position = this.position; + quaternion = camera.quaternion; + } app.updateMatrixWorld(); app.savedRotation = app.rotation.clone(); diff --git a/game.js b/game.js index aead8b33ac..91463c93a2 100644 --- a/game.js +++ b/game.js @@ -13,7 +13,7 @@ import dioramaManager from './diorama.js'; import {world} from './world.js'; import {buildMaterial, highlightMaterial, selectMaterial, hoverMaterial, hoverEquipmentMaterial} from './shaders.js'; import {getRenderer, sceneLowPriority, camera} from './renderer.js'; -import {downloadFile, snapPosition, getDropUrl, handleDropJsonItem} from './util.js'; +import {downloadFile, snapPosition, getDropUrl, handleDropJsonItem, makeId, makeHighlightPhysicsMesh} from './util.js'; import {maxGrabDistance, throwReleaseTime, storageHost, minFov, maxFov, throwAnimationDuration} from './constants.js'; import metaversefileApi from './metaversefile-api.js'; import * as metaverseModules from './metaverse-modules.js'; @@ -25,7 +25,7 @@ import npcManager from './npc-manager.js'; import raycastManager from './raycast-manager.js'; import zTargeting from './z-targeting.js'; import Avatar from './avatars/avatars.js'; -import {makeId} from './util.js' +import grabManager from './grab-manager.js'; const localVector = new THREE.Vector3(); const localVector2 = new THREE.Vector3(); @@ -54,19 +54,6 @@ let isMouseUp = false; // const cubicBezier = easing(0, 1, 0, 1); // let redMesh = null; -const _getGrabAction = i => { - const targetHand = i === 0 ? 'left' : 'right'; - const localPlayer = playersManager.getLocalPlayer(); - const grabAction = localPlayer.findAction(action => action.type === 'grab' && action.hand === targetHand); - return grabAction; -}; -const _getGrabbedObject = i => { - const grabAction = _getGrabAction(i); - const grabbedObjectInstanceId = grabAction?.instanceId; - const result = grabbedObjectInstanceId ? metaversefileApi.getAppByInstanceId(grabbedObjectInstanceId) : null; - return result; -}; - const _unwearAppIfHasSitComponent = (player) => { const wearActions = player.getActionsByType('wear'); for (const wearAction of wearActions) { @@ -79,42 +66,6 @@ const _unwearAppIfHasSitComponent = (player) => { } } -// returns whether we actually snapped -function updateGrabbedObject(o, grabMatrix, offsetMatrix, {collisionEnabled, handSnapEnabled, physx, gridSnap}) { - grabMatrix.decompose(localVector, localQuaternion, localVector2); - offsetMatrix.decompose(localVector3, localQuaternion2, localVector4); - const offset = localVector3.length(); - localMatrix.multiplyMatrices(grabMatrix, offsetMatrix) - .decompose(localVector5, localQuaternion3, localVector6); - - let collision = collisionEnabled && physicsScene.raycast(localVector, localQuaternion); - if (collision) { - // console.log('got collision', collision); - const {point} = collision; - o.position.fromArray(point) - // .add(localVector2.set(0, 0.01, 0)); - - if (o.position.distanceTo(localVector) > offset) { - collision = null; - } - } - if (!collision) { - o.position.copy(localVector5); - } - - const handSnap = !handSnapEnabled || offset >= maxGrabDistance || !!collision; - if (handSnap) { - snapPosition(o, gridSnap); - o.quaternion.setFromEuler(o.savedRotation); - } else { - o.quaternion.copy(localQuaternion3); - } - - return { - handSnap, - }; -} - const _getCurrentGrabAnimation = () => { let currentAnimation = ''; const localPlayer = playersManager.getLocalPlayer(); @@ -268,47 +219,33 @@ const _makeTargetMesh = (() => { return mesh; }; })(); -const _makeHighlightPhysicsMesh = material => { - const geometry = new THREE.BoxBufferGeometry(1, 1, 1); - material = material.clone(); - const mesh = new THREE.Mesh(geometry, material); - mesh.frustumCulled = false; - mesh.physicsId = 0; - return mesh; -}; /* const highlightMesh = _makeTargetMesh(); highlightMesh.visible = false; sceneLowPriority.add(highlightMesh); let highlightedObject = null; */ -const highlightPhysicsMesh = _makeHighlightPhysicsMesh(buildMaterial); -highlightPhysicsMesh.visible = false; -sceneLowPriority.add(highlightPhysicsMesh); -let highlightedPhysicsObject = null; -let highlightedPhysicsId = 0; - -const mouseHighlightPhysicsMesh = _makeHighlightPhysicsMesh(highlightMaterial); +const mouseHighlightPhysicsMesh = makeHighlightPhysicsMesh(highlightMaterial); mouseHighlightPhysicsMesh.visible = false; sceneLowPriority.add(mouseHighlightPhysicsMesh); let mouseHoverObject = null; let mouseHoverPhysicsId = 0; let mouseHoverPosition = null; -const mouseSelectPhysicsMesh = _makeHighlightPhysicsMesh(selectMaterial); +const mouseSelectPhysicsMesh = makeHighlightPhysicsMesh(selectMaterial); mouseSelectPhysicsMesh.visible = false; sceneLowPriority.add(mouseSelectPhysicsMesh); let mouseSelectedObject = null; let mouseSelectedPhysicsId = 0; let mouseSelectedPosition = null; -const mouseDomHoverPhysicsMesh = _makeHighlightPhysicsMesh(hoverMaterial); +const mouseDomHoverPhysicsMesh = makeHighlightPhysicsMesh(hoverMaterial); mouseDomHoverPhysicsMesh.visible = false; sceneLowPriority.add(mouseDomHoverPhysicsMesh); let mouseDomHoverObject = null; let mouseDomHoverPhysicsId = 0; -const mouseDomEquipmentHoverPhysicsMesh = _makeHighlightPhysicsMesh(hoverEquipmentMaterial); +const mouseDomEquipmentHoverPhysicsMesh = makeHighlightPhysicsMesh(hoverEquipmentMaterial); mouseDomEquipmentHoverPhysicsMesh.visible = false; sceneLowPriority.add(mouseDomEquipmentHoverPhysicsMesh); let mouseDomEquipmentHoverObject = null; @@ -336,7 +273,7 @@ const _use = () => { gameManager.setMenu(0); cameraManager.requestPointerLock(); } else if (highlightedObject /* && !editedObject */) { - _grab(highlightedObject); + grabManager.grab(highlightedObject); highlightedObject = null; gameManager.setMenu(0); @@ -354,37 +291,7 @@ const _use = () => { cameraManager.requestPointerLock(); } }; -const _delete = () => { - const grabbedObject = _getGrabbedObject(0); - if (grabbedObject) { - const localPlayer = playersManager.getLocalPlayer(); - localPlayer.ungrab(); - - world.appManager.removeTrackedApp(grabbedObject.instanceId); - - } else if (highlightedPhysicsObject) { - world.appManager.removeTrackedApp(highlightedPhysicsObject.instanceId); - highlightedPhysicsObject = null; - } else if (mouseSelectedObject) { - world.appManager.removeTrackedApp(mouseSelectedObject.instanceId); - - if (mouseHoverObject === mouseSelectedObject) { - gameManager.setMouseHoverObject(null); - } - gameManager.setMouseSelectedObject(null); - } -}; -const _click = e => { - if (_getGrabbedObject(0)) { - const localPlayer = playersManager.getLocalPlayer(); - localPlayer.ungrab(); - } else { - if (highlightedPhysicsObject) { - _grab(highlightedPhysicsObject); - } - } -}; let lastUseIndex = 0; const _getNextUseIndex = animationCombo => { if (Array.isArray(animationCombo)) { @@ -445,14 +352,6 @@ const _mouseup = () => { isMouseUp = true; }; -const _grab = object => { - const localPlayer = playersManager.getLocalPlayer(); - localPlayer.grab(object); - - gameManager.gridSnap = 0; - gameManager.editMode = false; -}; - const hitRadius = 1; const hitHeight = 0.2; const hitHalfHeight = hitHeight * 0.5; @@ -492,26 +391,13 @@ let lastActivated = false; let lastThrowing = false; const _gameUpdate = (timestamp, timeDiff) => { const now = timestamp; - const renderer = getRenderer(); const localPlayer = playersManager.getLocalPlayer(); - const _handlePush = () => { - if (gameManager.canPush()) { - if (ioManager.keys.forward) { - gameManager.menuPush(-1); - } else if (ioManager.keys.backward) { - gameManager.menuPush(1); - } - } - }; - _handlePush(); - - const _updateGrab = () => { - const renderer = getRenderer(); + const _updateGrabUseMesh = () => { const _isWear = o => localPlayer.findAction(action => action.type === 'wear' && action.instanceId === o.instanceId); grabUseMesh.visible = false; - if (!gameManager.editMode) { + if (!grabManager.editMode) { const avatarHeight = localPlayer.avatar ? localPlayer.avatar.height : 0; localVector.copy(localPlayer.position) .add(localVector2.set(0, avatarHeight * (1 - localPlayer.getCrouchFactor()) * 0.5, -0.3).applyQuaternion(localPlayer.quaternion)); @@ -536,27 +422,8 @@ const _gameUpdate = (timestamp, timeDiff) => { } } } - - for (let i = 0; i < 2; i++) { - const grabAction = _getGrabAction(i); - const grabbedObject = _getGrabbedObject(i); - if (grabbedObject && !_isWear(grabbedObject)) { - const {position, quaternion} = renderer.xr.getSession() ? localPlayer[hand === 'left' ? 'leftHand' : 'rightHand'] : camera; - localMatrix.compose(position, quaternion, localVector.set(1, 1, 1)); - grabbedObject.updateMatrixWorld(); - - updateGrabbedObject(grabbedObject, localMatrix, localMatrix3.fromArray(grabAction.matrix), { - collisionEnabled: true, - handSnapEnabled: true, - physx, - gridSnap: gameManager.getGridSnap(), - }); - - grabUseMesh.setComponent('value', localPlayer.actionInterpolants.activate.getNormalized()); - } - } }; - _updateGrab(); + _updateGrabUseMesh(); zTargeting.update(timestamp, timeDiff); @@ -612,47 +479,6 @@ const _gameUpdate = (timestamp, timeDiff) => { } _handlePickUp(); - const _handlePhysicsHighlight = () => { - highlightedPhysicsObject = null; - - if (gameManager.editMode) { - const {position, quaternion} = renderer.xr.getSession() ? localPlayer.leftHand : camera; - const collision = physicsScene.raycast(position, quaternion); - if (collision) { - const physicsId = collision.objectId; - highlightedPhysicsObject = metaversefileApi.getAppByPhysicsId(physicsId); - highlightedPhysicsId = physicsId; - } - } - }; - _handlePhysicsHighlight(); - - const _updatePhysicsHighlight = () => { - highlightPhysicsMesh.visible = false; - - if (highlightedPhysicsObject) { - const physicsId = highlightedPhysicsId; - - highlightedPhysicsObject.updateMatrixWorld(); - - const physicsObject = metaversefileApi.getPhysicsObjectByPhysicsId(physicsId); - if (physicsObject) { - const {physicsMesh} = physicsObject; - highlightPhysicsMesh.geometry = physicsMesh.geometry; - highlightPhysicsMesh.matrixWorld.copy(physicsMesh.matrixWorld) - .decompose(highlightPhysicsMesh.position, highlightPhysicsMesh.quaternion, highlightPhysicsMesh.scale); - - highlightPhysicsMesh.material.uniforms.uTime.value = (now%1500)/1500; - highlightPhysicsMesh.material.uniforms.uTime.needsUpdate = true; - highlightPhysicsMesh.material.uniforms.uColor.value.setHex(buildMaterial.uniforms.uColor.value.getHex()); - highlightPhysicsMesh.material.uniforms.uColor.needsUpdate = true; - highlightPhysicsMesh.visible = true; - highlightPhysicsMesh.updateMatrixWorld(); - } - } - }; - _updatePhysicsHighlight(); - const _updateMouseHighlight = () => { mouseHighlightPhysicsMesh.visible = false; @@ -994,7 +820,7 @@ const _gameUpdate = (timestamp, timeDiff) => { if (crosshairEl) { const visible = !!cameraManager.pointerLockElement && (['camera', 'firstperson', 'thirdperson'].includes(cameraManager.getMode()) || localPlayer.hasAction('aim')) && - !_getGrabbedObject(0); + !grabManager.getGrabbedObject(0); crosshairEl.style.visibility = visible ? null : 'hidden'; } @@ -1027,8 +853,6 @@ const _pushPlayerUpdates = () => { localPlayer.pushPlayerUpdates(); }; -const rotationSnap = Math.PI/6; - /* const metaverseUi = { makeArrowLoader() { const app = metaversefileApi.createApp(); @@ -1048,7 +872,7 @@ const _bindPointerLock = () => { gameManager.setMouseHoverObject(null); if (!pointerLockElement) { - gameManager.editMode = false; + grabManager.editMode = false; } }); }; @@ -1081,8 +905,6 @@ class GameManager extends EventTarget { super(); this.menuOpen = 0; - this.gridSnap = 0; - this.editMode = false; // this.dragging = false; // this.draggingRight = false; this.contextMenu = false; @@ -1123,12 +945,6 @@ class GameManager extends EventTarget { menuUse() { _use(); } - menuDelete() { - _delete(); - } - menuClick(e) { - _click(e); - } menuMouseDown() { _mousedown(); } @@ -1230,17 +1046,6 @@ class GameManager extends EventTarget { inputFocused() { return !!document.activeElement && ['INPUT', 'TEXTAREA'].includes(document.activeElement.nodeName); } - canGrab() { - return !!highlightedObject /*&& !editedObject*/; - } - canRotate() { - return !!_getGrabbedObject(0); - // return !!world.appManager.grabbedObjects[0]; - } - menuRotate(direction) { - const object = _getGrabbedObject(0); - object.savedRotation.y -= direction * rotationSnap; - } dropSelectedApp() { const app = loadoutManager.getSelectedApp(); if (app) { @@ -1264,47 +1069,10 @@ class GameManager extends EventTarget { } } } - canPush() { - return !!_getGrabbedObject(0); - // return !!world.appManager.grabbedObjects[0] /*|| (editedObject && editedObject.isBuild)*/; - } - menuPush(direction) { - const localPlayer = playersManager.getLocalPlayer(); - const grabAction = localPlayer.findAction(action => action.type === 'grab' && action.hand === 'left'); - if (grabAction) { - const matrix = localMatrix.fromArray(grabAction.matrix); - matrix - .decompose(localVector, localQuaternion, localVector2); - localVector.z += direction * 0.1; - matrix - .compose(localVector, localQuaternion, localVector2) - .toArray(grabAction.matrix); - } else { - console.warn('trying to push with no grab object'); - } - } - menuGridSnap() { - if (this.gridSnap === 0) { - this.gridSnap = 32; - } else if (this.gridSnap > 1) { - this.gridSnap /= 2; - } else { - this.gridSnap = 0; - } - // gridSnapEl.innerText = this.gridSnap > 0 ? (this.gridSnap + '') : 'off'; - } - getGridSnap() { - if (this.gridSnap === 0) { - return 0; - } else { - return 4/this.gridSnap; - } - } - menuVDown() { const localPlayer = playersManager.getLocalPlayer(); - if (_getGrabbedObject(0)) { - this.menuGridSnap(); + if (grabManager.getGrabbedObject(0)) { + grabManager.menuGridSnap(); } else { localPlayer.removeAction('dance'); @@ -1473,21 +1241,6 @@ class GameManager extends EventTarget { toggleAxis() { console.log('toggle axis'); } - async toggleEditMode() { - this.editMode = !this.editMode; - if (this.editMode) { - if (!cameraManager.pointerLockElement) { - await cameraManager.requestPointerLock(); - } - if (this.mouseSelectedObject) { - this.setMouseSelectedObject(null); - } - if (_getGrabbedObject(0)) { - const localPlayer = playersManager.getLocalPlayer(); - localPlayer.ungrab(); - } - } - } isJumping() { const localPlayer = playersManager.getLocalPlayer(); return localPlayer.hasAction('jump'); diff --git a/grab-manager.js b/grab-manager.js new file mode 100644 index 0000000000..d5fd0bfeb6 --- /dev/null +++ b/grab-manager.js @@ -0,0 +1,343 @@ +import * as THREE from 'three'; +import ioManager from './io-manager.js'; +import { playersManager } from './players-manager.js'; +import physicsManager from './physics-manager.js'; +import metaversefileApi from './metaversefile-api.js'; +import * as metaverseModules from './metaverse-modules.js'; +import { maxGrabDistance } from './constants.js'; +import { getRenderer, sceneLowPriority, camera } from './renderer.js'; +import cameraManager from './camera-manager.js'; +import gameManager from './game.js'; +import { world } from './world.js'; +import { makeHighlightPhysicsMesh, snapPosition } from './util.js'; +import { buildMaterial } from './shaders.js'; + +const physicsScene = physicsManager.getScene(); + +const localVector = new THREE.Vector3(); +const localVector2 = new THREE.Vector3(); +const localVector3 = new THREE.Vector3(); +const localVector4 = new THREE.Vector3(); +const localVector5 = new THREE.Vector3(); +const localVector6 = new THREE.Vector3(); +const localVector7 = new THREE.Vector3(); +const localVector8 = new THREE.Vector3(); +const localVector9 = new THREE.Vector3(); +const localQuaternion = new THREE.Quaternion(); +const localQuaternion2 = new THREE.Quaternion(); +const localQuaternion3 = new THREE.Quaternion(); +const localQuaternion4 = new THREE.Quaternion(); +const localMatrix = new THREE.Matrix4(); +const localMatrix3 = new THREE.Matrix4(); + +const rotationSnap = Math.PI / 6; +const highlightPhysicsMesh = makeHighlightPhysicsMesh(buildMaterial); +let highlightedPhysicsObject = null; +let highlightedPhysicsId = 0; + +highlightPhysicsMesh.visible = false; +sceneLowPriority.add(highlightPhysicsMesh); + +const _updateGrabbedObject = ( + o, + grabMatrix, + offsetMatrix, + { collisionEnabled, handSnapEnabled, gridSnap } +) => { + // grabMatrix represents localPlayer (= pivot point) + grabMatrix.decompose(localVector, localQuaternion, localVector2); + + // offsetMatrix represents grabbed object + offsetMatrix.decompose(localVector3, localQuaternion2, localVector4); + + // offset = distance localPlayer -> grabbed object + const offset = localVector3.length(); + + // Move grabbed object around pivot point + localMatrix + .multiplyMatrices(grabMatrix, offsetMatrix) + .decompose(localVector5, localQuaternion3, localVector6); + + // raycast from localPlayer in direction of camera angle + const collision = collisionEnabled && physicsScene.raycast(localVector, localQuaternion); + + // raycast from grabbed object down perpendicularly + localQuaternion2.setFromAxisAngle(localVector8.set(1, 0, 0), -Math.PI * 0.5); + const downCollision = collisionEnabled && physicsScene.raycast(localVector5, localQuaternion2); + + if (!!collision) { + const { point } = collision; + localVector6.fromArray(point); + } + + if (!!downCollision) { + const { point } = downCollision; + localVector4.fromArray(point); + if (ioManager.keys.shift) { + o.position.copy(localVector5.setY(localVector4.y)); + } else { + // if collision point is closer to the player than the grab offset and collisionDown point + // is below collision point then place the object at collision point + if ( + localVector.distanceTo(localVector6) < offset && + localVector4.y < localVector6.y + ) + localVector5.copy(localVector6); + + // if grabbed object would go below another object then place object at downCollision point + if (localVector5.y < localVector4.y) localVector5.setY(localVector4.y); + o.position.copy(localVector5); + } + } + + const handSnap = + !handSnapEnabled || + offset >= maxGrabDistance || + !!collision || + !!downCollision; + if (handSnap) { + snapPosition(o, gridSnap); + o.quaternion.setFromEuler(o.savedRotation); + } else { + o.quaternion.copy(localQuaternion3); + } + + o.updateMatrixWorld(); + + return { + handSnap, + }; +}; + +const _delete = () => { + const grabbedObject = grabManager.getGrabbedObject(0); + const mouseSelectedObject = gameManager.getMouseSelectedObject(); + if (grabbedObject) { + const localPlayer = playersManager.getLocalPlayer(); + localPlayer.ungrab(); + world.appManager.removeTrackedApp(grabbedObject.instanceId); + } else if (highlightedPhysicsObject) { + world.appManager.removeTrackedApp(highlightedPhysicsObject.instanceId); + highlightedPhysicsObject = null; + } else if (mouseSelectedObject) { + world.appManager.removeTrackedApp(mouseSelectedObject.instanceId); + if (mouseHoverObject === mouseSelectedObject) { + gameManager.setMouseHoverObject(null); + } + gameManager.setMouseSelectedObject(null); + } +}; + +const _click = (e) => { + if (grabManager.getGrabbedObject(0)) { + const localPlayer = playersManager.getLocalPlayer(); + localPlayer.ungrab(); + } else { + if (highlightedPhysicsObject) { + grabManager.grab(highlightedPhysicsObject); + } + } +}; + +class Grabmanager extends EventTarget { + constructor() { + super(); + this.gridSnap = 0; + this.editMode = false; + } + grab(object) { + const localPlayer = playersManager.getLocalPlayer(); + localPlayer.grab(object); + this.gridSnap = 0; + this.editMode = false; + } + getGrabAction(i) { + const targetHand = i === 0 ? 'left' : 'right'; + const localPlayer = playersManager.getLocalPlayer(); + const grabAction = localPlayer.findAction( + (action) => action.type === 'grab' && action.hand === targetHand + ); + return grabAction; + } + getGrabbedObject(i) { + const grabAction = this.getGrabAction(i); + const grabbedObjectInstanceId = grabAction?.instanceId; + const result = grabbedObjectInstanceId + ? metaversefileApi.getAppByInstanceId(grabbedObjectInstanceId) + : null; + return result; + } + async toggleEditMode() { + this.editMode = !this.editMode; + if (this.editMode) { + if (!cameraManager.pointerLockElement) { + await cameraManager.requestPointerLock(); + } + if (gameManager.getMouseSelectedObject()) { + gameManager.setMouseSelectedObject(null); + } + if (this.getGrabbedObject(0)) { + const localPlayer = playersManager.getLocalPlayer(); + localPlayer.ungrab(); + } + } + this.dispatchEvent( + new MessageEvent('toggleeditmode', { + data: { isEditMode: this.editMode }, + }) + ); + } + menuClick(e) { + _click(e); + } + menuDelete() { + _delete(); + } + menuGridSnap() { + if (this.gridSnap === 0) { + this.gridSnap = 32; + } else if (this.gridSnap > 1) { + this.gridSnap /= 2; + } else { + this.gridSnap = 0; + } + } + getGridSnap() { + if (this.gridSnap === 0) { + return 0; + } else { + return 4 / this.gridSnap; + } + } + canRotate() { + return !!this.getGrabbedObject(0); + } + menuRotate(direction) { + const object = this.getGrabbedObject(0); + object.savedRotation.y -= direction * rotationSnap; + } + canPush() { + return !!this.getGrabbedObject(0); + } + menuPush(direction) { + const localPlayer = playersManager.getLocalPlayer(); + const grabAction = localPlayer.findAction( + (action) => action.type === 'grab' && action.hand === 'left' + ); + if (grabAction) { + const matrix = localMatrix.fromArray(grabAction.matrix); + matrix.decompose(localVector, localQuaternion, localVector2); + localVector.z += direction * 0.1; + matrix + .compose(localVector, localQuaternion, localVector2) + .toArray(grabAction.matrix); + } else { + console.warn('trying to push with no grab object'); + } + } + + update(timestamp, timeDiff) { + const renderer = getRenderer(); + const localPlayer = playersManager.getLocalPlayer(); + + const _updateGrab = () => { + const _isWear = (o) => + localPlayer.findAction( + (action) => action.type === 'wear' && action.instanceId === o.instanceId); + + for (let i = 0; i < 2; i++) { + const grabAction = this.getGrabAction(i); + const grabbedObject = this.getGrabbedObject(i); + if (grabbedObject && !_isWear(grabbedObject)) { + let position = null, quaternion = null; + if (renderer.xr.getSession()) { + const h = localPlayer[hand === 'left' ? 'leftHand' : 'rightHand']; + position = h.position; + quaternion = h.quaternion; + } else { + position = localVector2.copy(localPlayer.position); + quaternion = camera.quaternion; + } + + localMatrix.compose(position, quaternion, localVector.set(1, 1, 1)); + + _updateGrabbedObject( + grabbedObject, + localMatrix, + localMatrix3.fromArray(grabAction.matrix), + { + collisionEnabled: true, + handSnapEnabled: true, + gridSnap: this.getGridSnap(), + } + ); + } + } + }; + _updateGrab(); + + const _handlePush = () => { + if (this.canPush()) { + if (ioManager.keys.forward) { + this.menuPush(-1); + } else if (ioManager.keys.backward) { + this.menuPush(1); + } + } + }; + _handlePush(); + + const _handlePhysicsHighlight = () => { + highlightedPhysicsObject = null; + + if (this.editMode) { + const { position, quaternion } = renderer.xr.getSession() + ? localPlayer.leftHand + : localPlayer; + const collision = physicsScene.raycast(position, quaternion); + if (collision) { + const physicsId = collision.objectId; + highlightedPhysicsObject = metaversefileApi.getAppByPhysicsId(physicsId); + highlightedPhysicsId = physicsId; + } + } + }; + _handlePhysicsHighlight(); + + const _updatePhysicsHighlight = () => { + highlightPhysicsMesh.visible = false; + + if (highlightedPhysicsObject) { + const physicsId = highlightedPhysicsId; + + highlightedPhysicsObject.updateMatrixWorld(); + + const physicsObject = metaversefileApi.getPhysicsObjectByPhysicsId(physicsId); + if (physicsObject) { + const { physicsMesh } = physicsObject; + highlightPhysicsMesh.geometry = physicsMesh.geometry; + highlightPhysicsMesh.matrixWorld + .copy(physicsMesh.matrixWorld) + .decompose( + highlightPhysicsMesh.position, + highlightPhysicsMesh.quaternion, + highlightPhysicsMesh.scale + ); + + highlightPhysicsMesh.material.uniforms.uTime.value = (timestamp % 1500) / 1500; + highlightPhysicsMesh.material.uniforms.uTime.needsUpdate = true; + highlightPhysicsMesh.material.uniforms.uColor.value.setHex( + buildMaterial.uniforms.uColor.value.getHex() + ); + highlightPhysicsMesh.material.uniforms.uColor.needsUpdate = true; + highlightPhysicsMesh.visible = true; + highlightPhysicsMesh.updateMatrixWorld(); + } + } + }; + _updatePhysicsHighlight(); + } +} + +const grabManager = new Grabmanager(); +export default grabManager; diff --git a/io-manager.js b/io-manager.js index a43ffe14e3..b2263043e8 100644 --- a/io-manager.js +++ b/io-manager.js @@ -24,6 +24,7 @@ import transformControls from './transform-controls.js'; import storyManager from './story.js'; // import domRenderer from './dom-renderer.jsx'; import raycastManager from './raycast-manager.js'; +import grabManager from './grab-manager.js'; // const localVector = new THREE.Vector3(); // const localVector2 = new THREE.Vector3(); @@ -419,7 +420,7 @@ ioManager.keydown = e => { case 70: { // F e.preventDefault(); e.stopPropagation(); - if (game.canPush()) { + if (grabManager.canPush()) { ioManager.keys.forward = true; } else { /* if (game.canJumpOff()) { @@ -446,7 +447,7 @@ ioManager.keydown = e => { } else if (game.canBuild()) { game.setBuildMode('floor'); } else { */ - game.menuDelete(); + grabManager.menuDelete(); // } } break; @@ -457,7 +458,7 @@ ioManager.keydown = e => { game.startBuild('stair'); } else if (game.canBuild()) { game.setBuildMode('stair'); - } else */if (game.canPush()) { + } else */if (grabManager.canPush()) { ioManager.keys.backward = true; } else { ioManager.keys.ctrl = true; @@ -507,8 +508,8 @@ ioManager.keydown = e => { } else { game.menuMiddleUp(); - if (game.canRotate()) { - game.menuRotate(-1); + if (grabManager.canRotate()) { + grabManager.menuRotate(-1); } else { game.menuActivateDown(); } @@ -537,8 +538,8 @@ ioManager.keydown = e => { } case 82: { // R if (cameraManager.pointerLockElement) { - if (game.canRotate()) { - game.menuRotate(1); + if (grabManager.canRotate()) { + grabManager.menuRotate(1); } else { game.dropSelectedApp(); } @@ -608,7 +609,7 @@ ioManager.keydown = e => { break; } case 192: { // tilde - game.toggleEditMode(); + grabManager.toggleEditMode(); break; } } @@ -755,7 +756,7 @@ ioManager.mouseleave = e => { }; ioManager.click = e => { if (cameraManager.pointerLockElement) { - game.menuClick(e); + grabManager.menuClick(e); } else { // game.setContextMenu(false); diff --git a/util.js b/util.js index 75eed293ad..49bd07a54e 100644 --- a/util.js +++ b/util.js @@ -1228,3 +1228,11 @@ export const splitLinesToWidth = (() => { return lines; }; })(); +export const makeHighlightPhysicsMesh = material => { + const geometry = new THREE.BoxBufferGeometry(1, 1, 1); + material = material.clone(); + const mesh = new THREE.Mesh(geometry, material); + mesh.frustumCulled = false; + mesh.physicsId = 0; + return mesh; +}; \ No newline at end of file diff --git a/webaverse.js b/webaverse.js index 28a513570a..ba24057491 100644 --- a/webaverse.js +++ b/webaverse.js @@ -47,6 +47,7 @@ import story from './story.js'; import zTargeting from './z-targeting.js'; import raycastManager from './raycast-manager.js'; import universe from './universe.js'; +import grabManager from './grab-manager.js'; const localVector = new THREE.Vector3(); const localVector2 = new THREE.Vector3(); @@ -318,6 +319,7 @@ export default class Webaverse extends EventTarget { transformControls.update(); raycastManager.update(timestamp, timeDiffCapped); game.update(timestamp, timeDiffCapped); + grabManager.update(timestamp, timeDiffCapped); localPlayer.updateAvatar(timestamp, timeDiffCapped); playersManager.updateRemotePlayers(timestamp, timeDiffCapped);