mirror of
https://github.com/overte-org/overte.git
synced 2025-04-30 13:22:34 +02:00
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:
parent
1dd276c1a5
commit
0ba34c5635
1 changed files with 177 additions and 139 deletions
|
@ -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();
|
||||||
|
|
Loading…
Reference in a new issue