mirror of
https://thingvellir.net/git/overte
synced 2025-03-27 23:52:03 +01:00
Merge pull request #7355 from sethalves/equip-via-thumb
Equip via thumb
This commit is contained in:
commit
6f9b912f46
2 changed files with 256 additions and 90 deletions
examples
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue