3
0
Fork 0
mirror of https://thingvellir.net/git/overte synced 2025-03-27 23:52:03 +01:00

Merge pull request from sethalves/equip-via-thumb

Equip via thumb
This commit is contained in:
Philip Rosedale 2016-04-01 17:58:10 -07:00
commit 6f9b912f46
2 changed files with 256 additions and 90 deletions

View file

@ -34,6 +34,8 @@ var TRIGGER_OFF_VALUE = 0.15;
var BUMPER_ON_VALUE = 0.5;
var THUMB_ON_VALUE = 0.5;
var HAND_HEAD_MIX_RATIO = 0.0; // 0 = only use hands for search/move. 1 = only use head for search/move.
var PICK_WITH_HAND_RAY = true;
@ -121,7 +123,8 @@ var GRABBABLE_PROPERTIES = [
"parentID",
"parentJointIndex",
"density",
"dimensions"
"dimensions",
"userData"
];
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
@ -152,20 +155,22 @@ var USE_POINTLIGHT = false;
// states for the state machine
var STATE_OFF = 0;
var STATE_SEARCHING = 1;
var STATE_DISTANCE_HOLDING = 2;
var STATE_CONTINUE_DISTANCE_HOLDING = 3;
var STATE_NEAR_GRABBING = 4;
var STATE_CONTINUE_NEAR_GRABBING = 5;
var STATE_NEAR_TRIGGER = 6;
var STATE_CONTINUE_NEAR_TRIGGER = 7;
var STATE_FAR_TRIGGER = 8;
var STATE_CONTINUE_FAR_TRIGGER = 9;
var STATE_RELEASE = 10;
var STATE_EQUIP_SEARCHING = 11;
var STATE_EQUIP = 12
var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down
var STATE_CONTINUE_EQUIP = 14;
var STATE_WAITING_FOR_BUMPER_RELEASE = 15;
var STATE_HOLD_SEARCHING = 2;
var STATE_DISTANCE_HOLDING = 3;
var STATE_CONTINUE_DISTANCE_HOLDING = 4;
var STATE_NEAR_GRABBING = 5;
var STATE_CONTINUE_NEAR_GRABBING = 6;
var STATE_NEAR_TRIGGER = 7;
var STATE_CONTINUE_NEAR_TRIGGER = 8;
var STATE_FAR_TRIGGER = 9;
var STATE_CONTINUE_FAR_TRIGGER = 10;
var STATE_RELEASE = 11;
var STATE_EQUIP = 12;
var STATE_HOLD = 13;
var STATE_CONTINUE_HOLD = 14;
var STATE_CONTINUE_EQUIP = 15;
var STATE_WAITING_FOR_RELEASE_THUMB_RELEASE = 16;
var STATE_WAITING_FOR_EQUIP_THUMB_RELEASE = 17;
// "collidesWith" is specified by comma-separated list of group names
// the possible group names are: static, dynamic, kinematic, myAvatar, otherAvatar
@ -181,6 +186,8 @@ function stateToName(state) {
return "off";
case STATE_SEARCHING:
return "searching";
case STATE_HOLD_SEARCHING:
return "hold_searching";
case STATE_DISTANCE_HOLDING:
return "distance_holding";
case STATE_CONTINUE_DISTANCE_HOLDING:
@ -199,16 +206,18 @@ function stateToName(state) {
return "continue_far_trigger";
case STATE_RELEASE:
return "release";
case STATE_EQUIP_SEARCHING:
return "equip_searching";
case STATE_EQUIP:
return "equip";
case STATE_CONTINUE_EQUIP_BD:
return "continue_equip_bd";
case STATE_HOLD:
return "hold";
case STATE_CONTINUE_HOLD:
return "continue_hold";
case STATE_CONTINUE_EQUIP:
return "continue_equip";
case STATE_WAITING_FOR_BUMPER_RELEASE:
return "waiting_for_bumper_release";
case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
return "waiting_for_equip_thumb_release";
case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
return "waiting_for_release_thumb_release";
}
return "unknown";
@ -259,9 +268,13 @@ function MyController(hand) {
this.grabbedEntity = null; // on this entity.
this.state = STATE_OFF;
this.pointer = null; // entity-id of line object
this.entityActivated = false;
this.triggerValue = 0; // rolling average of trigger value
this.rawTriggerValue = 0;
this.rawBumperValue = 0;
this.rawThumbValue = 0;
//for visualizations
this.overlayLine = null;
this.particleBeamObject = null;
@ -295,9 +308,7 @@ function MyController(hand) {
this.touchTest();
break;
case STATE_SEARCHING:
this.search();
break;
case STATE_EQUIP_SEARCHING:
case STATE_HOLD_SEARCHING:
this.search();
break;
case STATE_DISTANCE_HOLDING:
@ -308,13 +319,17 @@ function MyController(hand) {
break;
case STATE_NEAR_GRABBING:
case STATE_EQUIP:
case STATE_HOLD:
this.nearGrabbing();
break;
case STATE_WAITING_FOR_BUMPER_RELEASE:
this.waitingForBumperRelease();
case STATE_WAITING_FOR_EQUIP_THUMB_RELEASE:
this.waitingForEquipThumbRelease();
break;
case STATE_WAITING_FOR_RELEASE_THUMB_RELEASE:
this.waitingForReleaseThumbRelease();
break;
case STATE_CONTINUE_NEAR_GRABBING:
case STATE_CONTINUE_EQUIP_BD:
case STATE_CONTINUE_HOLD:
case STATE_CONTINUE_EQUIP:
this.continueNearGrabbing();
break;
@ -784,6 +799,26 @@ function MyController(hand) {
return _this.rawBumperValue < BUMPER_ON_VALUE;
};
// this.triggerOrBumperSqueezed = function() {
// return triggerSmoothedSqueezed() || bumperSqueezed();
// }
// this.triggerAndBumperReleased = function() {
// return triggerSmoothedReleased() && bumperReleased();
// }
this.thumbPress = function(value) {
_this.rawThumbValue = value;
}
this.thumbPressed = function() {
return _this.rawThumbValue > THUMB_ON_VALUE;
};
this.thumbReleased = function() {
return _this.rawThumbValue < THUMB_ON_VALUE;
};
this.off = function() {
if (this.triggerSmoothedSqueezed() || this.bumperSqueezed()) {
this.lastPickTime = 0;
@ -791,8 +826,8 @@ function MyController(hand) {
this.startingHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
if (this.triggerSmoothedSqueezed()) {
this.setState(STATE_SEARCHING);
} else {
this.setState(STATE_EQUIP_SEARCHING);
} else if (this.bumperSqueezed()) {
this.setState(STATE_HOLD_SEARCHING);
}
}
};
@ -804,7 +839,11 @@ function MyController(hand) {
this.checkForStrayChildren();
if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) {
if (this.state == STATE_SEARCHING && this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
return;
}
if (this.state == STATE_HOLD_SEARCHING && this.bumperReleased()) {
this.setState(STATE_RELEASE);
return;
}
@ -818,18 +857,23 @@ function MyController(hand) {
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
var currentHandRotation = Controller.getPoseValue(controllerHandInput).rotation;
var currentControllerPosition = Controller.getPoseValue(controllerHandInput).position;
var handDeltaRotation = Quat.multiply(currentHandRotation, Quat.inverse(this.startingHandRotation));
var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ?
Controller.Standard.RightHand : Controller.Standard.LeftHand);
var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation);
var distantPickRay = {
origin: PICK_WITH_HAND_RAY ? handPosition : Camera.position,
direction: PICK_WITH_HAND_RAY ? Quat.getUp(this.getHandRotation()) : Vec3.mix(Quat.getUp(this.getHandRotation()),
direction: PICK_WITH_HAND_RAY ? Quat.getUp(controllerRotation) : Vec3.mix(Quat.getUp(controllerRotation),
Quat.getFront(Camera.orientation),
HAND_HEAD_MIX_RATIO),
length: PICK_MAX_DISTANCE
};
var searchVisualizationPickRay = {
origin: handPosition,
origin: currentControllerPosition,
direction: Quat.getUp(this.getHandRotation()),
length: PICK_MAX_DISTANCE
};
@ -936,7 +980,7 @@ function MyController(hand) {
}
continue;
}
if (propsForCandidate.parentID != NULL_UUID && this.state == STATE_EQUIP_SEARCHING) {
if (propsForCandidate.parentID != NULL_UUID && this.state == STATE_HOLD_SEARCHING) {
// don't allow a double-equip
if (WANT_DEBUG_SEARCH_NAME && propsForCandidate.name == WANT_DEBUG_SEARCH_NAME) {
print("grab is skipping '" + WANT_DEBUG_SEARCH_NAME + "': it's a child");
@ -970,15 +1014,19 @@ function MyController(hand) {
this.setState(near ? STATE_NEAR_TRIGGER : STATE_FAR_TRIGGER);
return;
}
// near grab or equip with action
// near grab with action or equip
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {});
var refCount = ("refCount" in grabData) ? grabData.refCount : 0;
if (near && (refCount < 1 || entityHasActions(this.grabbedEntity))) {
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP);
if (this.state == STATE_SEARCHING) {
this.setState(STATE_NEAR_GRABBING);
} else { // (this.state == STATE_HOLD_SEARCHING)
this.setState(STATE_HOLD);
}
return;
}
// far grab or equip with action
if ((isPhysical || this.state == STATE_EQUIP_SEARCHING) && !near) {
// far grab
if (isPhysical && !near) {
if (entityIsGrabbedByOther(this.grabbedEntity)) {
// don't distance grab something that is already grabbed.
if (WANT_DEBUG_SEARCH_NAME && props.name == WANT_DEBUG_SEARCH_NAME) {
@ -999,7 +1047,8 @@ function MyController(hand) {
intersectionPointToCenterDistance *
FAR_TO_NEAR_GRAB_PADDING_FACTOR);
}
this.setState(this.state == STATE_SEARCHING ? STATE_DISTANCE_HOLDING : STATE_EQUIP);
this.setState(STATE_DISTANCE_HOLDING);
this.searchSphereOff();
return;
}
@ -1007,7 +1056,11 @@ function MyController(hand) {
// else this thing isn't physical. grab it by reparenting it (but not if we've already
// grabbed it).
if (refCount < 1) {
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP);
if (this.state == STATE_SEARCHING) {
this.setState(STATE_NEAR_GRABBING);
} else { // this.state == STATE_HOLD_SEARCHING)
this.setState(STATE_HOLD);
}
return;
} else {
// it's not physical and it's already held via parenting. go ahead and grab it, but
@ -1016,7 +1069,11 @@ function MyController(hand) {
this.doubleParentGrab = true;
this.previousParentID = props.parentID;
this.previousParentJointIndex = props.parentJointIndex;
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP);
if (this.state == STATE_SEARCHING) {
this.setState(STATE_NEAR_GRABBING);
} else { // (this.state == STATE_HOLD_SEARCHING)
this.setState(STATE_HOLD);
}
return;
}
if (WANT_DEBUG_SEARCH_NAME && props.name == WANT_DEBUG_SEARCH_NAME) {
@ -1051,10 +1108,12 @@ function MyController(hand) {
this.distanceHolding = function() {
// controller pose is in avatar frame
var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand);
var avatarControllerPose =
Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand);
// transform it into world frame
var controllerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation));
var controllerPosition = Vec3.sum(MyAvatar.position,
Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation));
var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
@ -1066,8 +1125,11 @@ function MyController(hand) {
this.currentObjectTime = now;
this.currentCameraOrientation = Camera.orientation;
this.grabRadius = Vec3.distance(this.currentObjectPosition, controllerPosition);
this.grabRadialVelocity = 0.0;
// compute a constant based on the initial conditions which we use below to exagerate hand motion onto the held object
this.radiusScalar = Math.log(Vec3.distance(this.currentObjectPosition, controllerPosition) + 1.0);
this.radiusScalar = Math.log(this.grabRadius + 1.0);
if (this.radiusScalar < 1.0) {
this.radiusScalar = 1.0;
}
@ -1104,7 +1166,7 @@ function MyController(hand) {
};
this.continueDistanceHolding = function() {
if (this.triggerSmoothedReleased()) {
if (this.triggerSmoothedReleased() && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("releaseGrab");
return;
@ -1113,27 +1175,21 @@ function MyController(hand) {
this.heartBeat(this.grabbedEntity);
// controller pose is in avatar frame
var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand);
var avatarControllerPose = Controller.getPoseValue((this.hand === RIGHT_HAND) ?
Controller.Standard.RightHand : Controller.Standard.LeftHand);
// transform it into world frame
var controllerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation));
var controllerPosition = Vec3.sum(MyAvatar.position,
Vec3.multiplyQbyV(MyAvatar.orientation, avatarControllerPose.translation));
var controllerRotation = Quat.multiply(MyAvatar.orientation, avatarControllerPose.rotation);
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
if (this.state == STATE_CONTINUE_DISTANCE_HOLDING && this.bumperSqueezed() &&
this.hasPresetOffsets()) {
var saveGrabbedID = this.grabbedEntity;
this.release();
this.setState(STATE_EQUIP);
this.grabbedEntity = saveGrabbedID;
return;
}
var now = Date.now();
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
this.currentObjectTime = now;
// the action was set up on a previous call. update the targets.
// the action was set up when this.distanceHolding was called. update the targets.
var radius = Vec3.distance(this.currentObjectPosition, controllerPosition) *
this.radiusScalar * DISTANCE_HOLDING_RADIUS_FACTOR;
if (radius < 1.0) {
@ -1151,7 +1207,7 @@ function MyController(hand) {
// update the currentObject position and rotation.
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved);
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
// this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
this.callEntityMethodOnGrabbed("continueDistantGrab");
@ -1161,6 +1217,25 @@ function MyController(hand) {
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData);
// Update radialVelocity
var lastVelocity = Vec3.subtract(controllerPosition, this.previousControllerPosition);
lastVelocity = Vec3.multiply(lastVelocity, 1.0 / deltaTime);
var newRadialVelocity = Vec3.dot(lastVelocity,
Vec3.normalize(Vec3.subtract(grabbedProperties.position, controllerPosition)));
var VELOCITY_AVERAGING_TIME = 0.016;
this.grabRadialVelocity = (deltaTime / VELOCITY_AVERAGING_TIME) * newRadialVelocity +
(1.0 - (deltaTime / VELOCITY_AVERAGING_TIME)) * this.grabRadialVelocity;
var RADIAL_GRAB_AMPLIFIER = 10.0;
if (Math.abs(this.grabRadialVelocity) > 0.0) {
this.grabRadius = this.grabRadius + (this.grabRadialVelocity * deltaTime * this.grabRadius * RADIAL_GRAB_AMPLIFIER);
}
var newTargetPosition = Vec3.multiply(this.grabRadius, Quat.getUp(controllerRotation));
newTargetPosition = Vec3.sum(newTargetPosition, controllerPosition);
var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position);
if (handControllerData.disableMoveWithHead !== true) {
// mix in head motion
@ -1222,7 +1297,7 @@ function MyController(hand) {
var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition));
var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: targetPosition,
targetPosition: newTargetPosition,
linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
targetRotation: this.currentObjectRotation,
angularTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject),
@ -1312,24 +1387,30 @@ function MyController(hand) {
this.callEntityMethodOnGrabbed("releaseGrab");
return;
}
if (this.state == STATE_HOLD && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("releaseGrab");
return;
}
this.lineOff();
this.overlayLineOff();
if (this.entityActivated) {
var saveGrabbedID = this.grabbedEntity;
this.release();
this.grabbedEntity = saveGrabbedID;
}
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
this.activateEntity(this.grabbedEntity, grabbedProperties, false);
if (grabbedProperties.dynamic && NEAR_GRABBING_KINEMATIC) {
Entities.editEntity(this.grabbedEntity, {
dynamic: false
});
}
// var handRotation = this.getHandRotation();
var handRotation = (this.hand === RIGHT_HAND) ? MyAvatar.getRightPalmRotation() : MyAvatar.getLeftPalmRotation();
var handPosition = this.getHandPosition();
var hasPresetPosition = false;
if (this.state != STATE_NEAR_GRABBING && this.hasPresetOffsets()) {
if ((this.state == STATE_EQUIP || this.state == STATE_HOLD) && this.hasPresetOffsets()) {
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
// if an object is "equipped" and has a predefined offset, use it.
this.ignoreIK = grabbableData.ignoreIK ? grabbableData.ignoreIK : false;
@ -1345,9 +1426,9 @@ function MyController(hand) {
var currentObjectPosition = grabbedProperties.position;
var offset = Vec3.subtract(currentObjectPosition, handPosition);
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
if (this.temporaryPositionOffset && this.state != STATE_NEAR_GRABBING) {
if (this.temporaryPositionOffset && (this.state == STATE_EQUIP)) {
this.offsetPosition = this.temporaryPositionOffset;
hasPresetPosition = true;
// hasPresetPosition = true;
}
}
@ -1370,25 +1451,44 @@ function MyController(hand) {
reparentProps["localRotation"] = this.offsetRotation;
}
Entities.editEntity(this.grabbedEntity, reparentProps);
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
action: 'equip',
grabbedEntity: this.grabbedEntity
}));
}
this.callEntityMethodOnGrabbed(this.state == STATE_NEAR_GRABBING ? "startNearGrab" : "startEquip");
Entities.editEntity(this.grabbedEntity, {
velocity: {x: 0, y: 0, z: 0},
angularVelocity: {x: 0, y: 0, z: 0},
dynamic: false
});
if (this.state == STATE_NEAR_GRABBING) {
this.callEntityMethodOnGrabbed("startNearGrab");
} else { // this.state == STATE_EQUIP || this.state == STATE_HOLD
this.callEntityMethodOnGrabbed("startEquip");
}
if (this.state == STATE_NEAR_GRABBING) {
// near grabbing
this.setState(STATE_CONTINUE_NEAR_GRABBING);
} else {
} else if (this.state == STATE_HOLD) {
// holding
this.setState(STATE_CONTINUE_HOLD);
} else { // (this.state == STATE_EQUIP)
// equipping
this.setState(STATE_CONTINUE_EQUIP_BD);
this.setState(STATE_CONTINUE_EQUIP);
}
this.currentHandControllerTipPosition =
(this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;
this.currentObjectTime = Date.now();
this.currentObjectPosition = grabbedProperties.position;
this.currentObjectRotation = grabbedProperties.rotation;
this.currentVelocity = ZERO_VEC;
this.currentAngularVelocity = ZERO_VEC;
};
this.continueNearGrabbing = function() {
@ -1397,25 +1497,30 @@ function MyController(hand) {
this.callEntityMethodOnGrabbed("releaseGrab");
return;
}
if (this.state == STATE_CONTINUE_EQUIP_BD && this.bumperReleased()) {
this.setState(STATE_CONTINUE_EQUIP);
return;
}
if (this.state == STATE_CONTINUE_EQUIP && this.bumperSqueezed()) {
this.setState(STATE_WAITING_FOR_BUMPER_RELEASE);
if (this.state == STATE_CONTINUE_HOLD && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("releaseEquip");
return;
}
if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) {
this.setState(STATE_CONTINUE_EQUIP_BD);
if (this.state == STATE_CONTINUE_EQUIP && this.thumbPressed()) {
this.setState(STATE_WAITING_FOR_RELEASE_THUMB_RELEASE);
this.callEntityMethodOnGrabbed("releaseEquip");
return;
}
if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.thumbPressed()) {
this.setState(STATE_WAITING_FOR_EQUIP_THUMB_RELEASE);
this.callEntityMethodOnGrabbed("releaseGrab");
this.callEntityMethodOnGrabbed("startEquip");
return;
}
if (this.state == STATE_CONTINUE_HOLD && this.thumbPressed()) {
this.setState(STATE_WAITING_FOR_EQUIP_THUMB_RELEASE);
return;
}
this.heartBeat(this.grabbedEntity);
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]);
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position", "rotation"]);
if (!props.position) {
// server may have reset, taking our equipped entity with it. move back to "off" stte
this.setState(STATE_RELEASE);
@ -1429,7 +1534,11 @@ function MyController(hand) {
print("handControllerGrab -- autoreleasing held or equipped item because it is far from hand." +
props.parentID + " " + vec3toStr(props.position));
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed(this.state == STATE_NEAR_GRABBING ? "releaseGrab" : "releaseEquip");
if (this.state == STATE_CONTINUE_NEAR_GRABBING) {
this.callEntityMethodOnGrabbed("releaseGrab");
} else { // (this.state == STATE_CONTINUE_EQUIP || this.state == STATE_CONTINUE_HOLD)
this.callEntityMethodOnGrabbed("releaseEquip");
}
return;
}
@ -1446,11 +1555,25 @@ function MyController(hand) {
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerTipPosition); // meters
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
if (deltaTime > 0.0) {
var worldDeltaPosition = Vec3.subtract(props.position, this.currentObjectPosition);
var previousEulers = Quat.safeEulerAngles(this.currentObjectRotation);
var newEulers = Quat.safeEulerAngles(props.rotation);
var worldDeltaRotation = Vec3.subtract(newEulers, previousEulers);
this.currentVelocity = Vec3.multiply(worldDeltaPosition, 1.0 / deltaTime);
this.currentAngularVelocity = Vec3.multiply(worldDeltaRotation, Math.PI / (deltaTime * 180.0));
this.currentObjectPosition = props.position;
this.currentObjectRotation = props.rotation;
}
this.currentHandControllerTipPosition = handControllerPosition;
this.currentObjectTime = now;
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, this.grabbedEntity, {});
if (this.state === STATE_CONTINUE_EQUIP) {
if (this.state === STATE_CONTINUE_EQUIP || this.state === STATE_CONTINUE_HOLD) {
this.callEntityMethodOnGrabbed("continueEquip");
}
if (this.state == STATE_CONTINUE_NEAR_GRABBING) {
@ -1479,14 +1602,19 @@ function MyController(hand) {
}
};
this.waitingForBumperRelease = function() {
if (this.bumperReleased()) {
this.waitingForEquipThumbRelease = function() {
if (this.thumbReleased() && this.triggerSmoothedReleased()) {
this.setState(STATE_EQUIP);
}
};
this.waitingForReleaseThumbRelease = function() {
if (this.thumbReleased() && this.triggerSmoothedReleased()) {
this.setState(STATE_RELEASE);
}
};
this.nearTrigger = function() {
if (this.triggerSmoothedReleased()) {
if (this.triggerSmoothedReleased() && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("stopNearTrigger");
return;
@ -1496,7 +1624,7 @@ function MyController(hand) {
};
this.farTrigger = function() {
if (this.triggerSmoothedReleased()) {
if (this.triggerSmoothedReleased() && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("stopFarTrigger");
return;
@ -1506,7 +1634,7 @@ function MyController(hand) {
};
this.continueNearTrigger = function() {
if (this.triggerSmoothedReleased()) {
if (this.triggerSmoothedReleased() && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("stopNearTrigger");
return;
@ -1515,7 +1643,7 @@ function MyController(hand) {
};
this.continueFarTrigger = function() {
if (this.triggerSmoothedReleased()) {
if (this.triggerSmoothedReleased() && this.bumperReleased()) {
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("stopFarTrigger");
return;
@ -1613,7 +1741,6 @@ function MyController(hand) {
};
this.release = function() {
this.turnLightsOff();
this.turnOffVisualizations();
@ -1673,6 +1800,11 @@ function MyController(hand) {
};
this.activateEntity = function(entityID, grabbedProperties, wasLoaded) {
if (this.entityActivated) {
return;
}
this.entityActivated = true;
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
var now = Date.now();
@ -1741,6 +1873,11 @@ function MyController(hand) {
}
this.deactivateEntity = function(entityID, noVelocity) {
if (!this.entityActivated) {
return;
}
this.entityActivated = false;
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) {
data["refCount"] = data["refCount"] - 1;
@ -1756,22 +1893,48 @@ function MyController(hand) {
// things that are held by parenting and dropped with no velocity will end up as "static" in bullet. If
// it looks like the dropped thing should fall, give it a little velocity.
var parentID = Entities.getEntityProperties(entityID, ["parentID"]).parentID;
var props = Entities.getEntityProperties(entityID, ["parentID", "velocity"])
var parentID = props.parentID;
var forceVelocity = false;
var doSetVelocity = false;
if (parentID != NULL_UUID && deactiveProps.parentID == NULL_UUID) {
// TODO: EntityScriptingInterface::convertLocationToScriptSemantics should be setting up
// props.velocity to be a world-frame velocity and localVelocity to be vs parent. Until that
// is done, we use a measured velocity here so that things held via a bumper-grab / parenting-grab
// can be thrown.
doSetVelocity = true;
}
if (!noVelocity &&
!doSetVelocity &&
parentID == MyAvatar.sessionUUID &&
Vec3.length(data["gravity"]) > 0.0 &&
data["dynamic"] &&
data["parentID"] == NULL_UUID &&
!data["collisionless"]) {
deactiveProps["velocity"] = {x: 0.0, y: 0.1, z: 0.0};
doSetVelocity = false;
}
if (noVelocity) {
deactiveProps["velocity"] = {x: 0.0, y: 0.0, z: 0.0};
deactiveProps["angularVelocity"] = {x: 0.0, y: 0.0, z: 0.0};
doSetVelocity = false;
}
Entities.editEntity(entityID, deactiveProps);
if (doSetVelocity) {
// this is a continuation of the TODO above -- we shouldn't need to set this here.
// do this after the parent has been reset. setting this at the same time as
// the parent causes it to go off in the wrong direction. This is a bug that should
// be fixed.
Entities.editEntity(entityID, {
velocity: this.currentVelocity,
// angularVelocity: this.currentAngularVelocity
});
}
data = null;
} else if (this.doubleParentGrab) {
// we parent-grabbed this from another parent grab. try to put it back where we found it.
@ -1795,7 +1958,7 @@ function MyController(hand) {
this.checkNewlyLoaded = function(loadedEntityID) {
if (this.state == STATE_OFF ||
this.state == STATE_SEARCHING ||
this.state == STATE_EQUIP_SEARCHING) {
this.state == STATE_HOLD_SEARCHING) {
var loadedProps = Entities.getEntityProperties(loadedEntityID);
if (loadedProps.parentID != MyAvatar.sessionUUID) {
return;
@ -1827,6 +1990,9 @@ mapping.from([Controller.Standard.LT]).peek().to(leftController.triggerPress);
mapping.from([Controller.Standard.RB]).peek().to(rightController.bumperPress);
mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress);
mapping.from([Controller.Standard.LeftPrimaryThumb]).peek().to(leftController.thumbPress);
mapping.from([Controller.Standard.RightPrimaryThumb]).peek().to(rightController.thumbPress);
Controller.enableMapping(MAPPING_NAME);
//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items

View file

@ -20,5 +20,5 @@ Script.load("controllers/squeezeHands.js");
Script.load("grab.js");
Script.load("directory.js");
Script.load("dialTone.js");
Script.load("attachedEntitiesManager.js");
// Script.load("attachedEntitiesManager.js");
Script.load("depthReticle.js");