Remove input restrictions on grabbable web entities.

You no longer have to be grabbing a grabbable web entity to interact with it.
This commit is contained in:
Anthony J. Thibault 2016-08-05 15:25:54 -07:00
parent 1dd276c1a5
commit 0ba34c5635

View file

@ -170,6 +170,7 @@ var STATE_NEAR_GRABBING = 3;
var STATE_NEAR_TRIGGER = 4; var STATE_NEAR_TRIGGER = 4;
var STATE_FAR_TRIGGER = 5; var STATE_FAR_TRIGGER = 5;
var STATE_HOLD = 6; var STATE_HOLD = 6;
var STATE_ENTITY_TOUCHING = 7;
// "collidesWith" is specified by comma-separated list of group names // "collidesWith" is specified by comma-separated list of group names
// the possible group names are: static, dynamic, kinematic, myAvatar, otherAvatar // the possible group names are: static, dynamic, kinematic, myAvatar, otherAvatar
@ -185,6 +186,8 @@ var delayedDeactivateEntityID;
var CONTROLLER_STATE_MACHINE = {}; var CONTROLLER_STATE_MACHINE = {};
var mostRecentSearchingHand = RIGHT_HAND;
CONTROLLER_STATE_MACHINE[STATE_OFF] = { CONTROLLER_STATE_MACHINE[STATE_OFF] = {
name: "off", name: "off",
enterMethod: "offEnter", enterMethod: "offEnter",
@ -220,6 +223,40 @@ CONTROLLER_STATE_MACHINE[STATE_FAR_TRIGGER] = {
enterMethod: "farTriggerEnter", enterMethod: "farTriggerEnter",
updateMethod: "farTrigger" updateMethod: "farTrigger"
}; };
CONTROLLER_STATE_MACHINE[STATE_ENTITY_TOUCHING] = {
name: "entityTouching",
enterMethod: "entityTouchingEnter",
exitMethod: "entityTouchingExit",
updateMethod: "entityTouching"
};
function handLaserIntersectWebEntity(entityID, hand) {
var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
var pose = Controller.getPoseValue(standardControllerValue);
var worldHandPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position);
var worldHandRotation = Quat.multiply(MyAvatar.orientation, pose.rotation);
var props = entityPropertiesCache.getProps(entityID);
var planePosition = props.position;
var planeNormal = Vec3.multiplyQbyV(props.rotation, {x: 0, y: 0, z: 1.0});
var rayStart = worldHandPosition;
var rayDirection = Quat.getUp(worldHandRotation);
var intersectionInfo = rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection);
var intersectionPoint = planePosition;
if (intersectionInfo.hit && intersectionInfo.distance > 0) {
intersectionPoint = Vec3.sum(rayStart, Vec3.multiply(intersectionInfo.distance, rayDirection));
} else {
intersectionPoint = planePosition;
}
intersectionInfo.point = intersectionPoint;
intersectionInfo.searchRay = {
origin: rayStart,
direction: rayDirection,
length: PICK_MAX_DISTANCE
};
return intersectionInfo;
}
function rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection) { function rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection) {
var rayDirectionDotPlaneNormal = Vec3.dot(rayDirection, planeNormal); var rayDirectionDotPlaneNormal = Vec3.dot(rayDirection, planeNormal);
@ -743,8 +780,6 @@ function MyController(hand) {
} }
}; };
this.searchSphereOn = function(location, size, color) { this.searchSphereOn = function(location, size, color) {
var rotation = Quat.lookAt(location, Camera.getPosition(), Vec3.UP); var rotation = Quat.lookAt(location, Camera.getPosition(), Vec3.UP);
@ -1257,7 +1292,7 @@ function MyController(hand) {
}; };
this.searchEnter = function() { this.searchEnter = function() {
this.capturedWebEntity = null; mostRecentSearchingHand = this.hand;
}; };
this.search = function(deltaTime, timestamp) { this.search = function(deltaTime, timestamp) {
@ -1283,155 +1318,124 @@ function MyController(hand) {
entityPropertiesCache.addEntity(rayPickInfo.entityID); entityPropertiesCache.addEntity(rayPickInfo.entityID);
} }
// route simulated touch events to a webEntity. var candidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS);
if (this.capturedWebEntity || entityPropertiesCache.addEntities(candidateEntities);
(rayPickInfo.entityID && entityPropertiesCache.getProps(rayPickInfo.entityID).type === "Web" &&
(!this.entityIsGrabbable(rayPickInfo.entityID) || this.getOtherHandController().grabbedEntity == rayPickInfo.entityID))) {
var standardControllerValue = (hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities);
var pose = Controller.getPoseValue(standardControllerValue); if (potentialEquipHotspot) {
var worldHandPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position); if (this.triggerSmoothedGrab()) {
var worldHandRotation = Quat.multiply(MyAvatar.orientation, pose.rotation); this.grabbedHotspot = potentialEquipHotspot;
this.grabbedEntity = potentialEquipHotspot.entityID;
var focusedEntity = this.capturedWebEntity || rayPickInfo.entityID; this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedEntity).name + "'");
entityPropertiesCache.addEntity(focusedEntity); return;
var props = entityPropertiesCache.getProps(focusedEntity);
var planePosition = props.position
var planeNormal = Vec3.multiplyQbyV(props.rotation, {x: 0, y: 0, z: 1.0});
var rayStart = worldHandPosition;
var rayDirection = Quat.getUp(worldHandRotation);
var intersectionInfo = rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection);
var intersectionPoint = planePosition;
if (intersectionInfo.hit && intersectionInfo.distance > 0) {
intersectionPoint = Vec3.sum(rayStart, Vec3.multiply(intersectionInfo.distance, rayDirection));
} else {
intersectionPoint = planePosition;
} }
}
if (Reticle.keyboardFocusEntity != focusedEntity) { var grabbableEntities = candidateEntities.filter(function(entity) {
Reticle.keyboardFocusEntity = focusedEntity; return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE);
} });
if (!this.triggerSmoothedGrab()) { if (rayPickInfo.entityID) {
// send mouse events for button highlights and tooltips this.intersectionDistance = rayPickInfo.distance;
Reticle.sendEntityMouseMoveEvent(focusedEntity, intersectionPoint); if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) {
} else { grabbableEntities.push(rayPickInfo.entityID);
// but send touch updates when grab is pressed.
Reticle.sendEntityTouchUpdateEvent(focusedEntity, this.hand, intersectionPoint);
} }
} else if (rayPickInfo.overlayID) {
if (this.triggerSmoothedGrab() && !this.lastTriggerSmoothedGrab) { this.intersectionDistance = rayPickInfo.distance;
Reticle.sendEntityTouchBeginEvent(focusedEntity, this.hand, intersectionPoint);
this.capturedWebEntity = focusedEntity;
}
if (!this.triggerSmoothedGrab() && this.lastTriggerSmoothedGrab) {
Reticle.sendEntityTouchEndEvent(focusedEntity, this.hand, intersectionPoint);
this.capturedWebEntity = null;
}
this.lastTriggerSmoothedGrab = this.triggerSmoothedGrab();
equipHotspotBuddy.updateHotspots([], timestamp);
this.intersectionDistance = intersectionInfo.distance;
} else { } else {
this.intersectionDistance = 0;
}
var candidateEntities = Entities.findEntities(handPosition, NEAR_GRAB_RADIUS); var entity;
entityPropertiesCache.addEntities(candidateEntities); if (grabbableEntities.length > 0) {
// sort by distance
var potentialEquipHotspot = this.chooseBestEquipHotspot(candidateEntities); grabbableEntities.sort(function(a, b) {
if (potentialEquipHotspot) { var aDistance = Vec3.distance(entityPropertiesCache.getProps(a).position, handPosition);
if (this.triggerSmoothedGrab()) { var bDistance = Vec3.distance(entityPropertiesCache.getProps(b).position, handPosition);
this.grabbedHotspot = potentialEquipHotspot; return aDistance - bDistance;
this.grabbedEntity = potentialEquipHotspot.entityID;
this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedEntity).name + "'");
return;
}
}
var grabbableEntities = candidateEntities.filter(function(entity) {
return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE);
}); });
entity = grabbableEntities[0];
if (rayPickInfo.entityID) { name = entityPropertiesCache.getProps(entity).name;
this.intersectionDistance = rayPickInfo.distance; this.grabbedEntity = entity;
if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) { if (this.entityWantsTrigger(entity)) {
grabbableEntities.push(rayPickInfo.entityID); if (this.triggerSmoothedGrab()) {
} this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
} else if (rayPickInfo.overlayID) { return;
this.intersectionDistance = rayPickInfo.distance;
} else {
this.intersectionDistance = 0;
}
var entity;
if (grabbableEntities.length > 0) {
// sort by distance
grabbableEntities.sort(function(a, b) {
var aDistance = Vec3.distance(entityPropertiesCache.getProps(a).position, handPosition);
var bDistance = Vec3.distance(entityPropertiesCache.getProps(b).position, handPosition);
return aDistance - bDistance;
});
entity = grabbableEntities[0];
name = entityPropertiesCache.getProps(entity).name;
this.grabbedEntity = entity;
if (this.entityWantsTrigger(entity)) {
if (this.triggerSmoothedGrab()) {
this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'");
return;
} else {
// potentialNearTriggerEntity = entity;
}
} else { } else {
if (this.triggerSmoothedGrab()) { // potentialNearTriggerEntity = entity;
var props = entityPropertiesCache.getProps(entity); }
var grabProps = entityPropertiesCache.getGrabProps(entity); } else {
var refCount = grabProps.refCount ? grabProps.refCount : 0; if (this.triggerSmoothedGrab()) {
if (refCount >= 1) { var props = entityPropertiesCache.getProps(entity);
// if another person is holding the object, remember to restore the var grabProps = entityPropertiesCache.getGrabProps(entity);
// parent info, when we are finished grabbing it. var refCount = grabProps.refCount ? grabProps.refCount : 0;
this.shouldResetParentOnRelease = true; if (refCount >= 1) {
this.previousParentID = props.parentID; // if another person is holding the object, remember to restore the
this.previousParentJointIndex = props.parentJointIndex; // parent info, when we are finished grabbing it.
} this.shouldResetParentOnRelease = true;
this.previousParentID = props.parentID;
this.setState(STATE_NEAR_GRABBING, "near grab '" + name + "'"); this.previousParentJointIndex = props.parentJointIndex;
return;
} else {
// potentialNearGrabEntity = entity;
} }
this.setState(STATE_NEAR_GRABBING, "near grab '" + name + "'");
return;
} else {
// potentialNearGrabEntity = entity;
} }
} }
}
if (rayPickInfo.entityID) { if (rayPickInfo.entityID && entityPropertiesCache.getProps(rayPickInfo.entityID).type === "Web") {
entity = rayPickInfo.entityID; entity = rayPickInfo.entityID;
name = entityPropertiesCache.getProps(entity).name; name = entityPropertiesCache.getProps(entity).name;
if (this.entityWantsTrigger(entity)) {
if (this.triggerSmoothedGrab()) { if (Reticle.keyboardFocusEntity != entity) {
this.grabbedEntity = entity; Reticle.keyboardFocusEntity = entity;
this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'"); }
return;
} else { // send mouse events for button highlights and tooltips.
// potentialFarTriggerEntity = entity; if (this.hand == mostRecentSearchingHand || (this.hand !== mostRecentSearchingHand &&
} this.getOtherHandController().state !== STATE_SEARCHING &&
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) { this.getOtherHandController().state !== STATE_ENTITY_TOUCHING)) {
if (this.triggerSmoothedGrab() && !isEditing()) { // most recently searching hand has priority over other hand, for the purposes of button highlighting.
this.grabbedEntity = entity; Reticle.sendEntityMouseMoveEvent(entity, rayPickInfo.intersection);
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'"); }
return;
} else { if (this.triggerSmoothedGrab() && !isEditing()) {
// potentialFarGrabEntity = entity; this.grabbedEntity = entity;
} this.setState(STATE_ENTITY_TOUCHING, "begin touching entity '" + name + "'");
return;
}
}
if (rayPickInfo.entityID) {
entity = rayPickInfo.entityID;
name = entityPropertiesCache.getProps(entity).name;
if (this.entityWantsTrigger(entity)) {
if (this.triggerSmoothedGrab()) {
this.grabbedEntity = entity;
this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'");
return;
} else {
// potentialFarTriggerEntity = entity;
}
} else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) {
if (this.triggerSmoothedGrab() && !isEditing()) {
this.grabbedEntity = entity;
this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'");
return;
} else {
// potentialFarGrabEntity = entity;
} }
} }
}
this.updateEquipHaptics(potentialEquipHotspot, handPosition); this.updateEquipHaptics(potentialEquipHotspot, handPosition);
var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS); var nearEquipHotspots = this.chooseNearEquipHotspots(candidateEntities, EQUIP_HOTSPOT_RENDER_RADIUS);
equipHotspotBuddy.updateHotspots(nearEquipHotspots, timestamp); equipHotspotBuddy.updateHotspots(nearEquipHotspots, timestamp);
if (potentialEquipHotspot) { if (potentialEquipHotspot) {
equipHotspotBuddy.highlightHotspot(potentialEquipHotspot); equipHotspotBuddy.highlightHotspot(potentialEquipHotspot);
}
} }
this.searchIndicatorOn(rayPickInfo.searchRay); this.searchIndicatorOn(rayPickInfo.searchRay);
@ -1609,9 +1613,9 @@ function MyController(hand) {
// visualizations // visualizations
var rayPickInfo = this.calcRayPickInfo(this.hand); var rayPickInfo = this.calcRayPickInfo(this.hand);
this.overlayLineOn(rayPickInfo.searchRay.origin, grabbedProperties.position, COLORS_GRAB_DISTANCE_HOLD); this.overlayLineOn(rayPickInfo.searchRay.origin, grabbedProperties.position, COLORS_GRAB_DISTANCE_HOLD);
var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition)); var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition));
var success = Entities.updateAction(this.grabbedEntity, this.actionID, { var success = Entities.updateAction(this.grabbedEntity, this.actionID, {
@ -2044,6 +2048,40 @@ function MyController(hand) {
this.release(); this.release();
}; };
this.entityTouchingEnter = function() {
// test for intersection between controller laser and web entity plane.
var intersectInfo = handLaserIntersectWebEntity(this.grabbedEntity, this.hand);
Reticle.sendEntityTouchBeginEvent(this.grabbedEntity, this.hand, intersectInfo.point);
};
this.entityTouchingExit = function() {
// test for intersection between controller laser and web entity plane.
var intersectInfo = handLaserIntersectWebEntity(this.grabbedEntity, this.hand);
Reticle.sendEntityTouchEndEvent(this.grabbedEntity, this.hand, intersectInfo.point);
};
this.entityTouching = function() {
entityPropertiesCache.addEntity(this.grabbedEntity);
if (!this.triggerSmoothedGrab()) {
this.setState(STATE_OFF, "released trigger");
return;
}
// test for intersection between controller laser and web entity plane.
var intersectInfo = handLaserIntersectWebEntity(this.grabbedEntity, this.hand);
if (Reticle.keyboardFocusEntity != this.grabbedEntity) {
Reticle.keyboardFocusEntity = this.grabbedEntity;
}
Reticle.sendEntityTouchUpdateEvent(this.grabbedEntity, this.hand, intersectInfo.point);
this.intersectionDistance = intersectInfo.distance;
this.searchIndicatorOn(intersectInfo.searchRay);
Reticle.setVisible(false);
};
this.release = function() { this.release = function() {
Messages.sendLocalMessage('Hifi-Teleport-Disabler','none'); Messages.sendLocalMessage('Hifi-Teleport-Disabler','none');
this.turnOffVisualizations(); this.turnOffVisualizations();