diff --git a/examples/attachedEntitiesManager.js b/examples/attachedEntitiesManager.js new file mode 100644 index 0000000000..cbffb41f9a --- /dev/null +++ b/examples/attachedEntitiesManager.js @@ -0,0 +1,303 @@ +// +// attachedEntitiesManager.js +// +// Created by Seth Alves on 2016-1-20 +// Copyright 2016 High Fidelity, Inc. +// +// This script handles messages from the grab script related to wearables, and interacts with a doppelganger. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +Script.include("libraries/utils.js"); + +var NULL_UUID = "{00000000-0000-0000-0000-000000000000}"; +var DEFAULT_WEARABLE_DATA = { + joints: {} +}; + + +var MINIMUM_DROP_DISTANCE_FROM_JOINT = 0.4; +var ATTACHED_ENTITY_SEARCH_DISTANCE = 10.0; +var ATTACHED_ENTITIES_SETTINGS_KEY = "ATTACHED_ENTITIES"; +var DRESSING_ROOM_DISTANCE = 2.0; + +// tool bar + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var BUTTON_SIZE = 32; +var PADDING = 3; +Script.include(["libraries/toolBars.js"]); +var toolBar = new ToolBar(0, 0, ToolBar.VERTICAL, "highfidelity.attachedEntities.toolbar", function(screenSize) { + return { + x: (BUTTON_SIZE + PADDING), + y: (screenSize.y / 2 - BUTTON_SIZE * 2 + PADDING) + }; +}); +var saveButton = toolBar.addOverlay("image", { + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: "http://headache.hungry.com/~seth/hifi/save.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); +var loadButton = toolBar.addOverlay("image", { + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: "http://headache.hungry.com/~seth/hifi/load.png", + color: { + red: 255, + green: 255, + blue: 255 + }, + alpha: 1 +}); + + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + + if (clickedOverlay == saveButton) { + manager.saveAttachedEntities(); + } else if (clickedOverlay == loadButton) { + manager.loadAttachedEntities(); + } +} + +function scriptEnding() { + toolBar.cleanup(); +} + +Controller.mousePressEvent.connect(mousePressEvent); +Script.scriptEnding.connect(scriptEnding); + + + + +// attached entites + + +function AttachedEntitiesManager() { + this.subscribeToMessages = function() { + Messages.subscribe('Hifi-Object-Manipulation'); + Messages.messageReceived.connect(this.handleWearableMessages); + } + + this.handleWearableMessages = function(channel, message, sender) { + if (channel !== 'Hifi-Object-Manipulation') { + return; + } + // if (sender !== MyAvatar.sessionUUID) { + // print('wearablesManager got message from wrong sender'); + // return; + // } + + var parsedMessage = null; + + try { + parsedMessage = JSON.parse(message); + } catch (e) { + print('error parsing wearable message'); + return; + } + + if (parsedMessage.action === 'update' || + parsedMessage.action === 'loaded') { + // ignore + } else if (parsedMessage.action === 'release') { + manager.checkIfWearable(parsedMessage.grabbedEntity, parsedMessage.joint) + // manager.saveAttachedEntities(); + } else if (parsedMessage.action === 'shared-release') { + // manager.saveAttachedEntities(); + } else if (parsedMessage.action === 'equip') { + // manager.saveAttachedEntities(); + } else { + print('attachedEntitiesManager -- unknown actions: ' + parsedMessage.action); + } + } + + this.avatarIsInDressingRoom = function() { + // return true if MyAvatar is near the dressing room + var possibleDressingRoom = Entities.findEntities(MyAvatar.position, DRESSING_ROOM_DISTANCE); + for (i = 0; i < possibleDressingRoom.length; i++) { + var entityID = possibleDressingRoom[i]; + var props = Entities.getEntityProperties(entityID); + if (props.name == 'Hifi-Dressing-Room-Base') { + return true; + } + } + return false; + } + + this.checkIfWearable = function(grabbedEntity, releasedFromJoint) { + var allowedJoints = getEntityCustomData('wearable', grabbedEntity, DEFAULT_WEARABLE_DATA).joints; + + var props = Entities.getEntityProperties(grabbedEntity, ["position", "parentID"]); + if (props.parentID === NULL_UUID || props.parentID === MyAvatar.sessionUUID) { + var bestJointName = ""; + var bestJointIndex = -1; + var bestJointDistance = 0; + var bestJointOffset = null; + for (var jointName in allowedJoints) { + if ((releasedFromJoint == "LeftHand" || releasedFromJoint == "RightHand") && + (jointName == "LeftHand" || jointName == "RightHand")) { + // don't auto-attach to a hand if a hand just dropped something + continue; + } + var jointIndex = MyAvatar.getJointIndex(jointName); + if (jointIndex > 0) { + var jointPosition = MyAvatar.getJointPosition(jointIndex); + var distanceFromJoint = Vec3.distance(jointPosition, props.position); + if (distanceFromJoint <= MINIMUM_DROP_DISTANCE_FROM_JOINT) { + if (bestJointIndex == -1 || distanceFromJoint < bestJointDistance) { + bestJointName = jointName; + bestJointIndex = jointIndex; + bestJointDistance = distanceFromJoint; + bestJointOffset = allowedJoints[jointName]; + } + } + } + } + + if (bestJointIndex != -1) { + var wearProps = { + parentID: MyAvatar.sessionUUID, + parentJointIndex: bestJointIndex + }; + + if (!this.avatarIsInDressingRoom() && + bestJointOffset && bestJointOffset.constructor === Array && bestJointOffset.length > 1) { + // don't snap the entity to the preferred position if the avatar is in the dressing room. + wearProps.localPosition = bestJointOffset[0]; + wearProps.localRotation = bestJointOffset[1]; + } + Entities.editEntity(grabbedEntity, wearProps); + } else if (props.parentID != NULL_UUID) { + // drop the entity with no parent (not on the avatar) + Entities.editEntity(grabbedEntity, { + parentID: NULL_UUID + }); + } + } + } + + this.updateRelativeOffsets = function(entityID, props) { + // save the preferred (current) relative position and rotation into the user-data of the entity + var wearableData = getEntityCustomData('wearable', entityID, DEFAULT_WEARABLE_DATA); + var currentJointName = MyAvatar.getJointNames()[props.parentJointIndex]; + wearableData.joints[currentJointName] = [props.localPosition, props.localRotation]; + setEntityCustomData('wearable', entityID, wearableData); + } + + this.saveAttachedEntities = function() { + print("--- saving attached entities ---"); + saveData = []; + var nearbyEntities = Entities.findEntities(MyAvatar.position, ATTACHED_ENTITY_SEARCH_DISTANCE); + for (i = 0; i < nearbyEntities.length; i++) { + var entityID = nearbyEntities[i]; + var props = Entities.getEntityProperties(entityID); + if (props.parentID == MyAvatar.sessionUUID) { + grabData = getEntityCustomData('grabKey', entityID, {}); + grabbableData = getEntityCustomData('grabbableKey', entityID, {}); + this.updateRelativeOffsets(entityID, props); + props = Entities.getEntityProperties(entityID); // refresh, because updateRelativeOffsets changed them + + // if an entity is currently being held or equipped, its original properties are saved in + // the userData under "grabKey". Save with these original properties rather than the + // ones currently on the entity. + if (grabData.refCount > 0) { + if ("gravity" in grabData) { + props.gravity = grabData.gravity; + } + if ("collidesWith" in grabData) { + props.collidesWith = grabData.collidesWith; + } + if ("dynamic" in grabData) { + props.dynamic = grabData.dynamic; + } + if ("collisionless" in grabData) { + if ("invertSolidWhileHeld" in grabbableData && grabbableData.invertSolidWhileHeld) { + props.collisionless = !grabData.collisionless; + } else { + props.collisionless = grabData.collisionless; + } + } + // if ("parentID" in grabData) { + // props.parentID = grabData.parentID; + // } + // if ("parentJointIndex" in grabData) { + // props.parentJointIndex = grabData.parentJointIndex; + // } + } + + this.scrubProperties(props); + saveData.push(props); + } + } + Settings.setValue(ATTACHED_ENTITIES_SETTINGS_KEY, JSON.stringify(saveData)); + } + + this.scrubProperties = function(props) { + var toScrub = ["queryAACube", "position", "rotation", + "created", "ageAsText", "naturalDimensions", + "naturalPosition", "velocity", "acceleration", + "angularVelocity", "boundingBox"]; + toScrub.forEach(function(propertyName) { + delete props[propertyName]; + }); + // if the userData has a grabKey, strip it out + if ("userData" in props) { + try { + parsedUserData = JSON.parse(props.userData); + if ("grabKey" in parsedUserData) { + delete parsedUserData["grabKey"]; + props["userData"] = JSON.stringify(parsedUserData); + } + } catch (e) { + } + } + } + + this.loadAttachedEntities = function(grabbedEntity) { + print("--- loading attached entities ---"); + jsonAttachmentData = Settings.getValue(ATTACHED_ENTITIES_SETTINGS_KEY); + var loadData = []; + try { + loadData = JSON.parse(jsonAttachmentData); + } catch (e) { + print('error parsing saved attachment data'); + return; + } + + for (i = 0; i < loadData.length; i ++) { + var savedProps = loadData[ i ]; + var currentProps = Entities.getEntityProperties(savedProps.id); + if (currentProps.id == savedProps.id && + // TODO -- also check that parentJointIndex matches? + currentProps.parentID == MyAvatar.sessionUUID) { + // entity is already in-world. TODO -- patch it up? + continue; + } + this.scrubProperties(savedProps); + delete savedProps["id"]; + savedProps.parentID = MyAvatar.sessionUUID; // this will change between sessions + var loadedEntityID = Entities.addEntity(savedProps); + + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'loaded', + grabbedEntity: loadedEntityID + })); + } + } +} + +var manager = new AttachedEntitiesManager(); +manager.subscribeToMessages(); diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index cc35cac807..5f2cdcf89a 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -18,7 +18,7 @@ Script.include("../libraries/utils.js"); // add lines where the hand ray picking is happening // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = false; +var WANT_DEBUG_STATE = true; // // these tune time-averaging and "on" value for analog trigger @@ -109,7 +109,8 @@ var GRABBABLE_PROPERTIES = [ "rotation", "gravity", "collidesWith", - "collisionsWillMove", + "dynamic", + "collisionless", "locked", "name", "shapeType", @@ -228,48 +229,6 @@ function entityIsGrabbedByOther(entityID) { return false; } -function getSpatialOffsetPosition(hand, spatialKey) { - var position = Vec3.ZERO; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativePosition) { - position = spatialKey.leftRelativePosition; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativePosition) { - position = spatialKey.rightRelativePosition; - } - if (spatialKey.relativePosition) { - position = spatialKey.relativePosition; - } - - // add the relative hand center offset - var handSizeRatio = calculateHandSizeRatio(); - position = Vec3.multiply(position, handSizeRatio); - return position; -} - -var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y); - -function getSpatialOffsetRotation(hand, spatialKey) { - var rotation = Quat.IDENTITY; - - if (hand !== RIGHT_HAND && spatialKey.leftRelativeRotation) { - rotation = spatialKey.leftRelativeRotation; - } - if (hand === RIGHT_HAND && spatialKey.rightRelativeRotation) { - rotation = spatialKey.rightRelativeRotation; - } - if (spatialKey.relativeRotation) { - rotation = spatialKey.relativeRotation; - } - - // Flip left hand - if (hand !== RIGHT_HAND) { - rotation = Quat.multiply(yFlip, rotation); - } - - return rotation; -} - function MyController(hand) { this.hand = hand; if (this.hand === RIGHT_HAND) { @@ -280,9 +239,6 @@ function MyController(hand) { this.getHandRotation = MyAvatar.getLeftPalmRotation; } - var SPATIAL_CONTROLLERS_PER_PALM = 2; - var TIP_CONTROLLER_OFFSET = 1; - this.actionID = null; // action this script created... this.grabbedEntity = null; // on this entity. this.state = STATE_OFF; @@ -363,6 +319,15 @@ function MyController(hand) { } }; + this.callEntityMethodOnGrabbed = function(entityMethodName, args) { + print("Entity Method: " + entityMethodName + ", hand: " + this.hand); + if (args.length > 0) { + Entities.callEntityMethod(this.grabbedEntity, entityMethodName, args); + } else { + Entities.callEntityMethod(this.grabbedEntity, entityMethodName); + } + } + this.setState = function(newState) { if (WANT_DEBUG || WANT_DEBUG_STATE) { print("STATE (" + this.hand + "): " + stateToName(this.state) + " --> " + @@ -381,7 +346,7 @@ function MyController(hand) { linePoints: [ZERO_VEC, farPoint], color: color, lifetime: 0.1, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { @@ -403,7 +368,7 @@ function MyController(hand) { linePoints: [ZERO_VEC, farPoint], color: color, lifetime: LIFETIME, - collisionsWillMove: false, + dynamic: false, ignoreForCollisions: true, userData: JSON.stringify({ grabbableKey: { @@ -767,6 +732,7 @@ function MyController(hand) { this.search = function() { this.grabbedEntity = null; + this.isInitialGrab = false; if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { this.setState(STATE_RELEASE); @@ -813,7 +779,7 @@ function MyController(hand) { direction: pickRay.direction }; - Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked)); + // Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked)); var intersection; @@ -861,6 +827,11 @@ function MyController(hand) { // too far away, don't grab continue; } + if (propsForCandidate.parentID != NULL_UUID && this.state == STATE_EQUIP_SEARCHING) { + // don't allow a double-equip + continue; + } + if (distance < minDistance) { this.grabbedEntity = candidateEntities[i]; minDistance = distance; @@ -870,7 +841,7 @@ function MyController(hand) { } if ((this.grabbedEntity !== null) && (this.triggerSmoothedGrab() || this.bumperSqueezed())) { // We are squeezing enough to grab, and we've found an entity that we'll try to do something with. - var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0); + var near = (nearPickedCandidateEntities.indexOf(this.grabbedEntity) >= 0) || minDistance <= NEAR_PICK_MAX_DISTANCE; var isPhysical = this.propsArePhysical(props); // near or far trigger @@ -890,11 +861,14 @@ function MyController(hand) { return; } this.temporaryPositionOffset = null; - if (typeof grabbableData.spatialKey === 'undefined') { + if (!this.hasPresetOffsets()) { // We want to give a temporary position offset to this object so it is pulled close to hand var intersectionPointToCenterDistance = Vec3.length(Vec3.subtract(intersection.intersection, intersection.properties.position)); - this.temporaryPositionOffset = Vec3.normalize(Vec3.subtract(intersection.properties.position, handPosition)); + var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); + var handJointPosition = MyAvatar.getJointPosition(handJointIndex); + this.temporaryPositionOffset = + Vec3.normalize(Vec3.subtract(intersection.properties.position, handJointPosition)); this.temporaryPositionOffset = Vec3.multiply(this.temporaryPositionOffset, intersectionPointToCenterDistance * FAR_TO_NEAR_GRAB_PADDING_FACTOR); @@ -919,13 +893,17 @@ function MyController(hand) { if (this.intersectionDistance > 0) { // If we hit something with our pick ray, move the search sphere toward that distance - this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); + this.searchSphereDistance = this.searchSphereDistance * SEARCH_SPHERE_FOLLOW_RATE + + this.intersectionDistance * (1.0 - SEARCH_SPHERE_FOLLOW_RATE); } - var searchSphereLocation = Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); - this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance, (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + var searchSphereLocation = Vec3.sum(distantPickRay.origin, + Vec3.multiply(distantPickRay.direction, this.searchSphereDistance)); + this.searchSphereOn(searchSphereLocation, SEARCH_SPHERE_SIZE * this.searchSphereDistance, + (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); if ((USE_OVERLAY_LINES_FOR_SEARCHING === true) && PICK_WITH_HAND_RAY) { - this.overlayLineOn(handPosition, searchSphereLocation, (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); + this.overlayLineOn(handPosition, searchSphereLocation, + (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } }; @@ -966,14 +944,8 @@ function MyController(hand) { if (this.actionID !== null) { this.setState(STATE_CONTINUE_DISTANCE_HOLDING); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab"); + this.activateEntity(this.grabbedEntity, grabbedProperties, false); + this.callSetupEntityMethods("startDistanceGrab"); } this.currentAvatarPosition = MyAvatar.position; @@ -985,7 +957,9 @@ function MyController(hand) { this.continueDistanceHolding = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + if (this.isInitialGrab) { + this.callEntityMethodOnGrabbed("releaseGrab", []); + } return; } @@ -997,7 +971,7 @@ function MyController(hand) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() && - typeof grabbableData.spatialKey !== 'undefined') { + this.hasPresetOffsets()) { var saveGrabbedID = this.grabbedEntity; this.release(); this.setState(STATE_EQUIP); @@ -1067,7 +1041,7 @@ function MyController(hand) { this.handPreviousRotation = handRotation; this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation); - Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab"); + this.callEntityMethodOnGrabbed("continueDistantGrab", []); var defaultMoveWithHeadData = { disableMoveWithHead: false @@ -1167,40 +1141,69 @@ function MyController(hand) { }; this.projectVectorAlongAxis = function(position, axisStart, axisEnd) { - var aPrime = Vec3.subtract(position, axisStart); - - var bPrime = Vec3.subtract(axisEnd, axisStart); - - var bPrimeMagnitude = Vec3.length(bPrime); - var dotProduct = Vec3.dot(aPrime, bPrime); - - var scalar = dotProduct / bPrimeMagnitude; - if (scalar < 0) { scalar = 0; } - if (scalar > 1) { scalar = 1; } - var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime))); - return projection }; + this.callSetupEntityMethods = function(entityMethodName) { + if (this.isInitialGrab) { + if (this.hand === RIGHT_HAND) { + this.callEntityMethodOnGrabbed("setRightHand", []); + } else { + this.callEntityMethodOnGrabbed("setLeftHand", []); + } + this.callEntityMethodOnGrabbed("setHand", [this.hand]); + this.callEntityMethodOnGrabbed(entityMethodName, [JSON.stringify(this.hand)]); + } + } + + this.hasPresetOffsets = function() { + var wearableData = getEntityCustomData('wearable', this.grabbedEntity, {joints: {}}); + var allowedJoints = wearableData.joints; + var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; + if (handJointName in allowedJoints) { + return true; + } + } + + this.getPresetPosition = function() { + var wearableData = getEntityCustomData('wearable', this.grabbedEntity, {joints: {}}); + var allowedJoints = wearableData.joints; + var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; + if (handJointName in allowedJoints) { + return allowedJoints[handJointName][0]; + } + } + + this.getPresetRotation = function() { + var wearableData = getEntityCustomData('wearable', this.grabbedEntity, {joints: {}}); + var allowedJoints = wearableData.joints; + var handJointName = this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"; + if (handJointName in allowedJoints) { + return allowedJoints[handJointName][1]; + } + } + this.nearGrabbing = function() { var now = Date.now(); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + if (this.isInitialGrab) { + this.callEntityMethodOnGrabbed("releaseGrab", []); + } return; } @@ -1208,10 +1211,10 @@ function MyController(hand) { this.overlayLineOff(); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - this.activateEntity(this.grabbedEntity, grabbedProperties); - if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) { + this.activateEntity(this.grabbedEntity, grabbedProperties, false); + if (grabbedProperties.dynamic && NEAR_GRABBING_KINEMATIC) { Entities.editEntity(this.grabbedEntity, { - collisionsWillMove: false + dynamic: false }); } @@ -1220,11 +1223,13 @@ function MyController(hand) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) { - // if an object is "equipped" and has a spatialKey, use it. - this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false; - this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey); - this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey); + var hasPresetPosition = false; + if (this.state != STATE_NEAR_GRABBING && this.hasPresetOffsets()) { + // if an object is "equipped" and has a predefined offset, use it. + this.ignoreIK = grabbableData.ignoreIK ? grabbableData.ignoreIK : false; + this.offsetPosition = this.getPresetPosition(); + this.offsetRotation = this.getPresetRotation(); + hasPresetPosition = true; } else { this.ignoreIK = false; @@ -1236,6 +1241,7 @@ function MyController(hand) { this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); if (this.temporaryPositionOffset && this.state != STATE_NEAR_GRABBING) { this.offsetPosition = this.temporaryPositionOffset; + hasPresetPosition = true; } } @@ -1247,42 +1253,44 @@ function MyController(hand) { } } else { // grab entity via parenting + this.actionID = null; var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"); - Entities.editEntity(this.grabbedEntity, { + reparentProps = { parentID: MyAvatar.sessionUUID, - parentJointIndex: handJointIndex, - localPosition: this.offsetPosition, - localRotation: this.offsetRotation - }); + parentJointIndex: handJointIndex + } + if (hasPresetPosition) { + reparentProps["localPosition"] = this.offsetPosition; + reparentProps["localRotation"] = this.offsetRotation; + } + Entities.editEntity(this.grabbedEntity, reparentProps); + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'equip', + grabbedEntity: this.grabbedEntity + })); } + this.callSetupEntityMethods(this.state == STATE_NEAR_GRABBING ? "startNearGrab" : "startEquip"); + if (this.state == STATE_NEAR_GRABBING) { + // near grabbing this.setState(STATE_CONTINUE_NEAR_GRABBING); } else { // equipping - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); this.setState(STATE_CONTINUE_EQUIP_BD); } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startNearGrab"); - this.currentHandControllerTipPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition; - this.currentObjectTime = Date.now(); }; this.continueNearGrabbing = function() { if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); + if (this.isInitialGrab) { + this.callEntityMethodOnGrabbed("releaseGrab", []); + } return; } if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) { @@ -1291,11 +1299,15 @@ function MyController(hand) { } if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) { this.setState(STATE_WAITING_FOR_BUMPER_RELEASE); + this.callEntityMethodOnGrabbed("releaseEquip", [JSON.stringify(this.hand)]); return; } if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) { this.setState(STATE_CONTINUE_EQUIP_BD); - Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]); + if (this.isInitialGrab) { + this.callEntityMethodOnGrabbed("releaseGrab", [JSON.stringify(this.hand)]); + this.callEntityMethodOnGrabbed("startEquip", [JSON.stringify(this.hand)]); + } return; } @@ -1314,16 +1326,23 @@ function MyController(hand) { this.currentHandControllerTipPosition = handControllerPosition; this.currentObjectTime = now; - Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); - if (this.state === STATE_CONTINUE_EQUIP_BD) { - Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {}); + if (this.isInitialGrab) { + if (this.state === STATE_CONTINUE_EQUIP) { + // this.callEntityMethodOnGrabbed("continueEquip", []); + Entities.callEntityMethod(this.grabbedEntity, "continueEquip"); + } + if (this.state == STATE_CONTINUE_NEAR_GRABBING) { + // this.callEntityMethodOnGrabbed("continueNearGrab", []); + Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab"); + } } - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'update', - grabbedEntity: this.grabbedEntity - })) + // Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + // action: 'update', + // grabbedEntity: this.grabbedEntity + // })) if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) { // if less than a 5 seconds left, refresh the actions ttl @@ -1350,60 +1369,48 @@ function MyController(hand) { this.waitingForBumperRelease = function() { if (this.bumperReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); - Entities.callEntityMethod(this.grabbedEntity, "unequip"); + var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {}); + if (this.isInitialGrab) { + // TODO -- only one of these should be sent + this.callEntityMethodOnGrabbed("releaseGrab", []); + this.callEntityMethodOnGrabbed("unequip", []); + } } }; this.nearTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + this.callEntityMethodOnGrabbed("stopNearTrigger", []); return; } - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - - Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger"); + this.callSetupEntityMethods("startNearTrigger"); this.setState(STATE_CONTINUE_NEAR_TRIGGER); }; this.farTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + this.callEntityMethodOnGrabbed("stopFarTrigger", []); return; } - - if (this.hand === RIGHT_HAND) { - Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); - } else { - Entities.callEntityMethod(this.grabbedEntity, "setLeftHand"); - } - Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]); - Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger"); + this.callSetupEntityMethods("startFarTrigger"); this.setState(STATE_CONTINUE_FAR_TRIGGER); }; this.continueNearTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopNearTrigger"); + this.callEntityMethodOnGrabbed("stopNearTrigger", []); return; } - - Entities.callEntityMethod(this.grabbedEntity, "continueNearTrigger"); + this.callEntityMethodOnGrabbed("continueNearTrigger", []); }; this.continueFarTrigger = function() { if (this.triggerSmoothedReleased()) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + this.callEntityMethodOnGrabbed("stopFarTrigger", []); return; } @@ -1419,7 +1426,7 @@ function MyController(hand) { this.lastPickTime = now; if (intersection.entityID != this.grabbedEntity) { this.setState(STATE_RELEASE); - Entities.callEntityMethod(this.grabbedEntity, "stopFarTrigger"); + this.callEntityMethodOnGrabbed("stopFarTrigger", []); return; } } @@ -1427,8 +1434,7 @@ function MyController(hand) { if (USE_ENTITY_LINES_FOR_MOVING === true) { this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); } - - Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger"); + this.callEntityMethodOnGrabbed("continueFarTrigger", []); }; _this.allTouchedIDs = {}; @@ -1488,15 +1494,16 @@ function MyController(hand) { }; this.startTouch = function(entityID) { - Entities.callEntityMethod(entityID, "startTouch"); + this.callEntityMethodOnGrabbed("startTouch", []); }; this.continueTouch = function(entityID) { - Entities.callEntityMethod(entityID, "continueTouch"); + // this.callEntityMethodOnGrabbed("continueTouch", []); + Entities.callEntityMethod(this.grabbedEntity, "continueTouch"); }; this.stopTouch = function(entityID) { - Entities.callEntityMethod(entityID, "stopTouch"); + this.callEntityMethodOnGrabbed("stopTouch", []); }; this.release = function() { @@ -1506,13 +1513,10 @@ function MyController(hand) { if (this.grabbedEntity !== null) { if (this.actionID !== null) { + Entities.deleteAction(this.grabbedEntity, this.actionID); //sometimes we want things to stay right where they are when we let go. - var releaseVelocityData = getEntityCustomData(GRABBABLE_DATA_KEY, - this.grabbedEntity, - DEFAULT_GRABBABLE_DATA); - if (releaseVelocityData.disableReleaseVelocity === true) { - Entities.deleteAction(this.grabbedEntity, this.actionID); - + var releaseVelocityData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + if (releaseVelocityData.disableReleaseVelocity === true || !this.isInitialGrab) { Entities.editEntity(this.grabbedEntity, { velocity: { x: 0, @@ -1524,25 +1528,28 @@ function MyController(hand) { y: 0, z: 0 } - }) - Entities.deleteAction(this.grabbedEntity, this.actionID); - - } else { - //don't make adjustments - Entities.deleteAction(this.grabbedEntity, this.actionID); + }); } } } this.deactivateEntity(this.grabbedEntity); - this.actionID = null; this.setState(STATE_OFF); - Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ - action: 'release', - grabbedEntity: this.grabbedEntity - })); + if (this.isInitialGrab) { + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'release', + grabbedEntity: this.grabbedEntity, + joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" + })); + } else { + Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ + action: 'shared-release', + grabbedEntity: this.grabbedEntity, + joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" + })); + } this.grabbedEntity = null; }; @@ -1554,19 +1561,30 @@ function MyController(hand) { Entities.deleteEntity(this.pointLight); }; - this.activateEntity = function(entityID, grabbedProperties) { + this.activateEntity = function(entityID, grabbedProperties, wasLoaded) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); data["activated"] = true; data["avatarId"] = MyAvatar.sessionUUID; - data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + if (wasLoaded) { + data["refCount"] = 1; + } else { + data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; + } // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done if (data["refCount"] == 1) { + this.isInitialGrab = true; data["gravity"] = grabbedProperties.gravity; data["collidesWith"] = grabbedProperties.collidesWith; - data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; - data["parentID"] = grabbedProperties.parentID; + data["collisionless"] = grabbedProperties.collisionless; + data["dynamic"] = grabbedProperties.dynamic; + data["parentID"] = wasLoaded ? NULL_UUID : grabbedProperties.parentID; data["parentJointIndex"] = grabbedProperties.parentJointIndex; + + if ("invertSolidWhileHeld" in grabbableData && grabbableData.invertSolidWhileHeld) { + data["collisionless"] = !data["collisionless"]; + } + var whileHeldProperties = { gravity: { x: 0, @@ -1580,6 +1598,7 @@ function MyController(hand) { }; Entities.editEntity(entityID, whileHeldProperties); } else if (data["refCount"] > 1) { + this.isInitialGrab = false; // if an object is being grabbed by more than one person (or the same person twice, but nevermind), switch // the collision groups so that it wont collide with "other" avatars. This avoids a situation where two // people are holding something and one of them will be able (if the other releases at the right time) to @@ -1600,8 +1619,8 @@ function MyController(hand) { Entities.editEntity(entityID, { gravity: data["gravity"], collidesWith: data["collidesWith"], - collisionsWillMove: data["collisionsWillMove"], - ignoreForCollisions: data["ignoreForCollisions"], + collisionless: data["collisionless"], + dynamic: data["dynamic"], parentID: data["parentID"], parentJointIndex: data["parentJointIndex"] }); @@ -1617,7 +1636,7 @@ function MyController(hand) { if (this.state == STATE_OFF || this.state == STATE_SEARCHING || this.state == STATE_EQUIP_SEARCHING) { - var loadedProps = Entities.getEntityProperties(loadedEntityID, ["parentID", "parentJointIndex"]); + var loadedProps = Entities.getEntityProperties(loadedEntityID); if (loadedProps.parentID != MyAvatar.sessionUUID) { return; } @@ -1625,9 +1644,13 @@ function MyController(hand) { if (loadedProps.parentJointIndex != handJointIndex) { return; } + print("--- handControllerGrab found loaded entity ---"); // an entity has been loaded and it's where this script would have equipped something, so switch states. this.grabbedEntity = loadedEntityID; - this.setState(STATE_EQUIP); + this.activateEntity(this.grabbedEntity, loadedProps, true); + this.isInitialGrab = true; + this.callSetupEntityMethods("startEquip"); + this.setState(STATE_CONTINUE_EQUIP); } } }; diff --git a/examples/toybox/bow/bow.js b/examples/toybox/bow/bow.js index 0ac571276e..489cc6341e 100644 --- a/examples/toybox/bow/bow.js +++ b/examples/toybox/bow/bow.js @@ -139,7 +139,7 @@ this.hand = 'right'; }, - startNearGrab: function() { + startEquip: function() { print('START BOW GRAB') if (this.isGrabbed === true) { @@ -159,7 +159,7 @@ setEntityCustomData('grabbableKey', this.entityID, data); }, - continueNearGrab: function() { + continueEquip: function() { this.deltaTime = checkInterval(); //debounce during debugging -- maybe we're updating too fast? @@ -552,4 +552,4 @@ }; return new Bow(); -}); \ No newline at end of file +}); diff --git a/examples/toybox/bow/createBow.js b/examples/toybox/bow/createBow.js index ba4994ab1a..eb6d8bb81b 100644 --- a/examples/toybox/bow/createBow.js +++ b/examples/toybox/bow/createBow.js @@ -64,21 +64,22 @@ function makeBow() { script: SCRIPT_URL, userData: JSON.stringify({ grabbableKey: { - invertSolidWhileHeld: true, - spatialKey: { - leftRelativePosition: { - x: -0.02, - y: 0.08, - z: 0.09 - }, - relativePosition: { - x: 0.02, - y: 0.08, - z: 0.09 - }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90) - } - } + invertSolidWhileHeld: true + }, + wearable:{joints:{RightHand:[{x:0.03960523009300232, + y:0.01979270577430725, + z:0.03294898942112923}, + {x:-0.7257906794548035, + y:-0.4611682891845703, + z:0.4436084032058716, + w:-0.25251442193984985}], + LeftHand:[{x:0.0055799782276153564, + y:0.04354757443070412, + z:0.05119767785072327}, + {x:-0.14914104342460632, + y:0.6448180079460144, + z:-0.2888556718826294, + w:-0.6917579770088196}]}} }) }; @@ -147,4 +148,4 @@ function cleanup() { Entities.deleteEntity(preNotchString); } -Script.scriptEnding.connect(cleanup); \ No newline at end of file +Script.scriptEnding.connect(cleanup); diff --git a/examples/toybox/bubblewand/createWand.js b/examples/toybox/bubblewand/createWand.js index d859d7cb9f..d0b1372755 100644 --- a/examples/toybox/bubblewand/createWand.js +++ b/examples/toybox/bubblewand/createWand.js @@ -46,16 +46,22 @@ var wand = Entities.addEntity({ script: WAND_SCRIPT_URL, userData: JSON.stringify({ grabbableKey: { - invertSolidWhileHeld: true, - spatialKey: { - relativePosition: { - x: 0, - y: 0.1, - z: 0 - }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, -90) - } - } + invertSolidWhileHeld: true + }, + "wearable":{"joints":{"RightHand":[{"x":0.11421211808919907, + "y":0.06508062779903412, + "z":0.06317152827978134}, + {"x":-0.7886992692947388, + "y":-0.6108893156051636, + "z":-0.05003821849822998, + "w":0.047579944133758545}], + "LeftHand":[{"x":0.03530977666378021, + "y":0.11278322339057922, + "z":0.049768272787332535}, + {"x":-0.050609711557626724, + "y":-0.11595471203327179, + "z":0.3554558753967285, + "w":0.9260908961296082}]}} }) }); diff --git a/examples/toybox/bubblewand/wand.js b/examples/toybox/bubblewand/wand.js index fe1d917e69..d0ef2871f8 100644 --- a/examples/toybox/bubblewand/wand.js +++ b/examples/toybox/bubblewand/wand.js @@ -174,6 +174,9 @@ this.createBubbleAtTipOfWand(); } }, + startEquip: function(id, params) { + this.startNearGrab(id, params); + }, continueNearGrab: function() { var deltaTime = checkInterval(); //only get the properties that we need @@ -188,11 +191,17 @@ this.growBubbleWithWandVelocity(properties, deltaTime); }, + continueEquip: function() { + this.continueNearGrab(); + }, releaseGrab: function() { //delete the current buble and reset state when the wand is released Entities.deleteEntity(this.currentBubble); this.currentBubble = null; }, + releaseEquip: function() { + this.releaseGrab(); + }, }; diff --git a/examples/toybox/doll/doll.js b/examples/toybox/doll/doll.js index 04712f0e1d..c7661af610 100644 --- a/examples/toybox/doll/doll.js +++ b/examples/toybox/doll/doll.js @@ -49,6 +49,9 @@ this.isGrabbed = true; this.initialHand = this.hand; }, + startEquip: function(id, params) { + this.startNearGrab(id, params); + }, continueNearGrab: function() { var props = Entities.getEntityProperties(this.entityID, ["position"]); @@ -57,6 +60,9 @@ }; this.audioInjector.options = audioOptions; }, + continueEquip: function() { + this.continueNearGrab(); + }, releaseGrab: function() { if (this.isGrabbed === true && this.hand === this.initialHand) { @@ -73,6 +79,9 @@ this.isGrabbed = false; } }, + releaseEquip: function() { + this.releaseGrab(); + }, preload: function(entityID) { this.entityID = entityID; diff --git a/examples/toybox/flashlight/createFlashlight.js b/examples/toybox/flashlight/createFlashlight.js index 897ba516e1..be91516e63 100644 --- a/examples/toybox/flashlight/createFlashlight.js +++ b/examples/toybox/flashlight/createFlashlight.js @@ -39,6 +39,20 @@ var flashlight = Entities.addEntity({ userData: JSON.stringify({ grabbableKey: { invertSolidWhileHeld: true - } + }, + wearable:{joints:{RightHand:[{x:0.0717092975974083, + y:0.1166968047618866, + z:0.07085515558719635}, + {x:-0.7195770740509033, + y:0.175227552652359, + z:0.5953742265701294, + w:0.31150275468826294}], + LeftHand:[{x:0.0806504637002945, + y:0.09710478782653809, + z:0.08610185235738754}, + {x:0.5630447864532471, + y:-0.2545935809612274, + z:0.7855332493782043, + w:0.033170729875564575}]}} }) }); diff --git a/examples/toybox/flashlight/flashlight.js b/examples/toybox/flashlight/flashlight.js index 251ca71b7a..1a85af695d 100644 --- a/examples/toybox/flashlight/flashlight.js +++ b/examples/toybox/flashlight/flashlight.js @@ -86,6 +86,7 @@ }, startNearGrab: function(entityID) { + print("FLASHLIGHT startNearGrab"); if (!this.hasSpotlight) { var modelProperties = Entities.getEntityProperties(this.entityID, ['position', 'rotation']); @@ -144,6 +145,9 @@ } }, + startEquip: function(id, params) { + this.startNearGrab(id, params); + }, setWhichHand: function() { this.whichHand = this.hand; @@ -157,6 +161,9 @@ this.changeLightWithTriggerPressure(this.whichHand); } }, + continueEquip: function() { + this.continueNearGrab(); + }, releaseGrab: function() { //delete the lights and reset state @@ -170,6 +177,9 @@ this.lightOn = false; } }, + releaseEquip: function() { + this.releaseGrab(); + }, changeLightWithTriggerPressure: function(flashLightHand) { @@ -258,4 +268,4 @@ // entity scripts always need to return a newly constructed object of our type return new Flashlight(); -}); \ No newline at end of file +}); diff --git a/examples/toybox/ping_pong_gun/createPingPongGun.js b/examples/toybox/ping_pong_gun/createPingPongGun.js index c8f7093b7e..d9f47eda37 100644 --- a/examples/toybox/ping_pong_gun/createPingPongGun.js +++ b/examples/toybox/ping_pong_gun/createPingPongGun.js @@ -38,16 +38,22 @@ var pingPongGun = Entities.addEntity({ collisionSoundURL: COLLISION_SOUND_URL, userData: JSON.stringify({ grabbableKey: { - spatialKey: { - relativePosition: { - x: -0.05, - y: 0, - z: 0.0 - }, - relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90) - }, invertSolidWhileHeld: true - } + }, + wearable:{joints:{RightHand:[{x:0.1177130937576294, + y:0.12922893464565277, + z:0.08307232707738876}, + {x:0.4934672713279724, + y:0.3605862259864807, + z:0.6394805908203125, + w:-0.4664038419723511}], + LeftHand:[{x:0.09151676297187805, + y:0.13639454543590546, + z:0.09354984760284424}, + {x:-0.19628101587295532, + y:0.6418180465698242, + z:0.2830369472503662, + w:0.6851521730422974}]}} }) }); diff --git a/examples/toybox/ping_pong_gun/pingPongGun.js b/examples/toybox/ping_pong_gun/pingPongGun.js index 5b928719fa..bcb793746b 100644 --- a/examples/toybox/ping_pong_gun/pingPongGun.js +++ b/examples/toybox/ping_pong_gun/pingPongGun.js @@ -66,7 +66,7 @@ this.hand = 0; }, - startNearGrab: function() { + startEquip: function() { this.setWhichHand(); }, @@ -74,7 +74,7 @@ this.whichHand = this.hand; }, - continueNearGrab: function() { + continueEquip: function() { if (this.whichHand === null) { //only set the active hand once -- if we always read the current hand, our 'holding' hand will get overwritten this.setWhichHand(); @@ -86,7 +86,7 @@ } }, - releaseGrab: function() { + releaseEquip: function() { var _this = this; if (this.whichHand === this.hand) { diff --git a/examples/toybox/pistol/createPistol.js b/examples/toybox/pistol/createPistol.js index e5f9391c65..1608c2fa4b 100644 --- a/examples/toybox/pistol/createPistol.js +++ b/examples/toybox/pistol/createPistol.js @@ -30,16 +30,22 @@ var pistol = Entities.addEntity({ collisionSoundURL: "http://hifi-content.s3.amazonaws.com/james/pistol/sounds/drop.wav", userData: JSON.stringify({ grabbableKey: { - spatialKey: { - relativePosition: { - x: 0, - y: 0.05, - z: -0.08 - }, - relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0) - }, invertSolidWhileHeld: true - } + }, + wearable:{joints:{RightHand:[{x:0.07079616189002991, + y:0.20177987217903137, + z:0.06374628841876984}, + {x:-0.5863648653030396, + y:-0.46007341146469116, + z:0.46949487924575806, + w:-0.4733745753765106}], + LeftHand:[{x:0.1802254319190979, + y:0.13442856073379517, + z:0.08504903316497803}, + {x:0.2198076844215393, + y:-0.7377811074256897, + z:0.2780133783817291, + w:0.574519157409668}]}} }) }); diff --git a/examples/toybox/pistol/pistol.js b/examples/toybox/pistol/pistol.js index c2456d4b7d..87e2f57780 100644 --- a/examples/toybox/pistol/pistol.js +++ b/examples/toybox/pistol/pistol.js @@ -52,7 +52,7 @@ this.hand = JSON.parse(params[0]); }, - continueNearGrab: function() { + continueEquip: function() { if (!this.equipped) { return; } @@ -61,8 +61,6 @@ this.updateLaser(); } this.toggleWithTriggerPressure(); - - }, updateProps: function() {