keep a heart-beat timestamp in userData of grabbed entities. if grabbing something with an out-of-date heartbeat, reset it before grabbing

This commit is contained in:
Seth Alves 2016-02-23 16:21:41 -08:00
parent f82e5e2cd6
commit 0e028fbac8

View file

@ -73,9 +73,7 @@ var PICK_MAX_DISTANCE = 500; // max length of pick-ray
var GRAB_RADIUS = 0.06; // if the ray misses but an object is this close, it will still be selected var GRAB_RADIUS = 0.06; // if the ray misses but an object is this close, it will still be selected
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object var PICK_BACKOFF_DISTANCE = 0.2; // helps when hand is intersecting the grabble object
var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed var NEAR_GRABBING_KINEMATIC = true; // force objects to be kinematic when near-grabbed
var SHOW_GRAB_SPHERE = false; // draw a green sphere to show the grab search position and size var SHOW_GRAB_SPHERE = false; // draw a green sphere to show the grab search position and size
@ -173,6 +171,10 @@ var STATE_WAITING_FOR_BUMPER_RELEASE = 15;
var COLLIDES_WITH_WHILE_GRABBED = "dynamic,otherAvatar"; var COLLIDES_WITH_WHILE_GRABBED = "dynamic,otherAvatar";
var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic"; var COLLIDES_WITH_WHILE_MULTI_GRABBED = "dynamic";
var HEART_BEAT_INTERVAL = 5; // seconds
var HEART_BEAT_TIMEOUT = 15;
function stateToName(state) { function stateToName(state) {
switch (state) { switch (state) {
case STATE_OFF: case STATE_OFF:
@ -1103,6 +1105,8 @@ function MyController(hand) {
return; return;
} }
this.heartBeat(this.grabbedEntity);
var handPosition = this.getHandPosition(); var handPosition = this.getHandPosition();
var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition; var handControllerPosition = (this.hand === RIGHT_HAND) ? MyAvatar.rightHandPosition : MyAvatar.leftHandPosition;
var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; var controllerHandInput = (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
@ -1438,6 +1442,8 @@ function MyController(hand) {
return; return;
} }
this.heartBeat(this.grabbedEntity);
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]); var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]);
if (props.parentID == MyAvatar.sessionUUID && if (props.parentID == MyAvatar.sessionUUID &&
Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) { Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) {
@ -1670,19 +1676,40 @@ function MyController(hand) {
Entities.deleteEntity(this.pointLight); Entities.deleteEntity(this.pointLight);
}; };
this.heartBeat = function(entityID) {
var now = Date.now();
if (now - this.lastHeartBeat > HEART_BEAT_INTERVAL) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["heartBeat"] = now;
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
this.lastHeartBeat = now;
}
};
this.resetAbandonedGrab = function(entityID) {
print("cleaning up abandoned grab on " + entityID);
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["refCount"] = 1;
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
this.deactivateEntity(entityID, false);
};
this.activateEntity = function(entityID, grabbedProperties, wasLoaded) { this.activateEntity = function(entityID, grabbedProperties, wasLoaded) {
print("activating: " + entityID + " " + (this.hand === RIGHT_HAND ? "right" : "left"));
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA);
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
data["activated"] = true; var now = Date.now();
data["avatarId"] = MyAvatar.sessionUUID;
if (wasLoaded) { if (wasLoaded) {
data["refCount"] = 1; data["refCount"] = 1;
data["avatarId"] = MyAvatar.sessionUUID;
} else { } else {
data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1; data["refCount"] = data["refCount"] ? data["refCount"] + 1 : 1;
// zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done
if (data["refCount"] == 1) { if (data["refCount"] == 1) {
data["heartBeat"] = now;
this.lastHeartBeat = now;
this.isInitialGrab = true; this.isInitialGrab = true;
data["gravity"] = grabbedProperties.gravity; data["gravity"] = grabbedProperties.gravity;
data["collidesWith"] = grabbedProperties.collidesWith; data["collidesWith"] = grabbedProperties.collidesWith;
@ -1698,12 +1725,20 @@ function MyController(hand) {
z: 0 z: 0
}, },
// bummer, it isn't easy to do bitwise collisionMask operations like this: // bummer, it isn't easy to do bitwise collisionMask operations like this:
//"collisionMask": COLLISION_MASK_WHILE_GRABBED | grabbedProperties.collisionMask // "collisionMask": COLLISION_MASK_WHILE_GRABBED | grabbedProperties.collisionMask
// when using string values // when using string values
"collidesWith": COLLIDES_WITH_WHILE_GRABBED "collidesWith": COLLIDES_WITH_WHILE_GRABBED
}; };
Entities.editEntity(entityID, whileHeldProperties); Entities.editEntity(entityID, whileHeldProperties);
} else if (data["refCount"] > 1) { } else if (data["refCount"] > 1) {
if (now - data["heartBeat"] > HEART_BEAT_TIMEOUT) {
// this entity has userData suggesting it is grabbed, but nobody is updating the hearbeat.
// deactivate it before grabbing.
this.resetAbandonedGrab(entityID);
grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
return this.activateEntity(entityID, grabbedProperties, wasLoaded);
}
this.isInitialGrab = false; this.isInitialGrab = false;
// if an object is being grabbed by more than one person (or the same person twice, but nevermind), switch // if an object is being grabbed by more than one person (or the same person twice, but nevermind), switch
// the collision groups so that it wont collide with "other" avatars. This avoids a situation where two // the collision groups so that it wont collide with "other" avatars. This avoids a situation where two