Merge pull request #6437 from imgntn/grasp_equip

Grasp hands when equipping entities
This commit is contained in:
Brad Hefta-Gaub 2015-11-19 18:28:44 -08:00
commit e6db72c887
2 changed files with 234 additions and 67 deletions

View file

@ -37,9 +37,21 @@ var BUMPER_ON_VALUE = 0.5;
var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
var NO_INTERSECT_COLOR = { red: 10, green: 10, blue: 255}; // line color when pick misses
var INTERSECT_COLOR = { red: 250, green: 10, blue: 10}; // line color when pick hits
var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
var NO_INTERSECT_COLOR = {
red: 10,
green: 10,
blue: 255
}; // line color when pick misses
var INTERSECT_COLOR = {
red: 250,
green: 10,
blue: 10
}; // line color when pick hits
var LINE_ENTITY_DIMENSIONS = {
x: 1000,
y: 1000,
z: 1000
};
var LINE_LENGTH = 500;
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
@ -89,7 +101,8 @@ var GRABBABLE_PROPERTIES = ["position",
"ignoreForCollisions",
"collisionsWillMove",
"locked",
"name"];
"name"
];
var GRABBABLE_DATA_KEY = "grabbableKey"; // shared with grab.js
@ -187,7 +200,6 @@ function entityIsGrabbedByOther(entityID) {
return false;
}
function MyController(hand) {
this.hand = hand;
if (this.hand === RIGHT_HAND) {
@ -211,8 +223,17 @@ function MyController(hand) {
this.rawTriggerValue = 0;
this.rawBumperValue = 0;
this.offsetPosition = { x: 0.0, y: 0.0, z: 0.0 };
this.offsetRotation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 };
this.offsetPosition = {
x: 0.0,
y: 0.0,
z: 0.0
};
this.offsetRotation = {
x: 0.0,
y: 0.0,
z: 0.0,
w: 1.0
};
var _this = this;
@ -468,8 +489,7 @@ function MyController(hand) {
}
} else if (!entityIsGrabbedByOther(intersection.entityID)) {
// don't allow two people to distance grab the same object
if (intersection.properties.collisionsWillMove
&& !intersection.properties.locked) {
if (intersection.properties.collisionsWillMove && !intersection.properties.locked) {
// the hand is far from the intersected object. go into distance-holding mode
this.grabbedEntity = intersection.entityID;
if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) {
@ -494,10 +514,18 @@ function MyController(hand) {
Entities.addEntity({
type: "Sphere",
name: "Grab Debug Entity",
dimensions: {x: GRAB_RADIUS, y: GRAB_RADIUS, z: GRAB_RADIUS},
dimensions: {
x: GRAB_RADIUS,
y: GRAB_RADIUS,
z: GRAB_RADIUS
},
visible: true,
position: handPosition,
color: { red: 0, green: 255, blue: 0},
color: {
red: 0,
green: 255,
blue: 0
},
lifetime: 0.1
});
}
@ -604,6 +632,7 @@ function MyController(hand) {
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab");
}
@ -773,6 +802,8 @@ function MyController(hand) {
this.setState(STATE_CONTINUE_NEAR_GRABBING);
} else {
// equipping
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
this.startHandGrasp();
this.setState(STATE_CONTINUE_EQUIP_BD);
}
@ -781,6 +812,9 @@ function MyController(hand) {
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
}
@ -807,6 +841,7 @@ function MyController(hand) {
}
if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.bumperSqueezed()) {
this.setState(STATE_CONTINUE_EQUIP_BD);
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
return;
}
@ -827,6 +862,10 @@ function MyController(hand) {
this.currentObjectTime = now;
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
if (this.state === STATE_CONTINUE_EQUIP_BD) {
Entities.callEntityMethod(this.grabbedEntity, "continueEquip");
}
if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) {
// if less than a 5 seconds left, refresh the actions ttl
Entities.updateAction(this.grabbedEntity, this.actionID, {
@ -846,6 +885,8 @@ function MyController(hand) {
if (this.bumperReleased()) {
this.setState(STATE_RELEASE);
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
Entities.callEntityMethod(this.grabbedEntity, "unequip");
this.endHandGrasp();
}
};
@ -856,8 +897,17 @@ function MyController(hand) {
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
// use a spring to pull the object to where it will be when equipped
var relativeRotation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 };
var relativePosition = { x: 0.0, y: 0.0, z: 0.0 };
var relativeRotation = {
x: 0.0,
y: 0.0,
z: 0.0,
w: 1.0
};
var relativePosition = {
x: 0.0,
y: 0.0,
z: 0.0
};
if (grabbableData.spatialKey.relativePosition) {
relativePosition = grabbableData.spatialKey.relativePosition;
}
@ -913,6 +963,9 @@ function MyController(hand) {
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
Entities.callEntityMethod(this.grabbedEntity, "startNearTrigger");
this.setState(STATE_CONTINUE_NEAR_TRIGGER);
};
@ -929,6 +982,7 @@ function MyController(hand) {
} else {
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
}
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
Entities.callEntityMethod(this.grabbedEntity, "startFarTrigger");
this.setState(STATE_CONTINUE_FAR_TRIGGER);
};
@ -1061,6 +1115,7 @@ function MyController(hand) {
this.cleanup = function() {
this.release();
this.endHandGrasp();
};
this.activateEntity = function(entityID, grabbedProperties) {
@ -1075,7 +1130,13 @@ function MyController(hand) {
data["gravity"] = grabbedProperties.gravity;
data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions;
data["collisionsWillMove"] = grabbedProperties.collisionsWillMove;
var whileHeldProperties = {gravity: {x:0, y:0, z:0}};
var whileHeldProperties = {
gravity: {
x: 0,
y: 0,
z: 0
}
};
if (invertSolidWhileHeld) {
whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions;
}
@ -1103,6 +1164,44 @@ function MyController(hand) {
}
setEntityCustomData(GRAB_USER_DATA_KEY, entityID, data);
};
//this is our handler, where we do the actual work of changing animation settings
this.graspHand = function(animationProperties) {
var result = {};
//full alpha on overlay for this hand
//set grab to true
//set idle to false
//full alpha on the blend btw open and grab
if (_this.hand === RIGHT_HAND) {
result['rightHandOverlayAlpha'] = 1.0;
result['isRightHandGrab'] = true;
result['isRightHandIdle'] = false;
result['rightHandGrabBlend'] = 1.0;
} else if (_this.hand === LEFT_HAND) {
result['leftHandOverlayAlpha'] = 1.0;
result['isLeftHandGrab'] = true;
result['isLeftHandIdle'] = false;
result['leftHandGrabBlend'] = 1.0;
}
//return an object with our updated settings
return result;
}
this.graspHandler = null
this.startHandGrasp = function() {
if (this.hand === RIGHT_HAND) {
this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']);
} else if (this.hand === LEFT_HAND) {
this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']);
}
}
this.endHandGrasp = function() {
// Tell the animation system we don't need any more callbacks.
MyAvatar.removeAnimationStateHandler(this.graspHandler);
}
}
var rightController = new MyController(RIGHT_HAND);

View file

@ -0,0 +1,68 @@
// graspHands.js
//
// Created by James B. Pollack @imgntn -- 11/19/2015
// Copyright 2015 High Fidelity, Inc.
//
// Shows how to use the animation API to grasp an Avatar's hands.
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//choose a hand. set it programatically if you'd like
var handToGrasp = 'LEFT_HAND';
//this is our handler, where we do the actual work of changing animation settings
function graspHand(animationProperties) {
var result = {};
//full alpha on overlay for this hand
//set grab to true
//set idle to false
//full alpha on the blend btw open and grab
if (handToGrasp === 'RIGHT_HAND') {
result['rightHandOverlayAlpha'] = 1.0;
result['isRightHandGrab'] = true;
result['isRightHandIdle'] = false;
result['rightHandGrabBlend'] = 1.0;
} else if (handToGrasp === 'LEFT_HAND') {
result['leftHandOverlayAlpha'] = 1.0;
result['isLeftHandGrab'] = true;
result['isLeftHandIdle'] = false;
result['leftHandGrabBlend'] = 1.0;
}
//return an object with our updated settings
return result;
}
//keep a reference to this so we can clear it
var handler;
//register our handler with the animation system
function startHandGrasp() {
if (handToGrasp === 'RIGHT_HAND') {
handler = MyAvatar.addAnimationStateHandler(graspHand, ['isRightHandGrab']);
} else if (handToGrasp === 'LEFT_HAND') {
handler = MyAvatar.addAnimationStateHandler(graspHand, ['isLeftHandGrab']);
}
}
function endHandGrasp() {
// Tell the animation system we don't need any more callbacks.
MyAvatar.removeAnimationStateHandler(handler);
}
//make sure to clean this up when the script ends so we don't get stuck.
Script.scriptEnding.connect(function() {
Script.clearInterval(graspInterval);
endHandGrasp();
})
//set an interval and toggle grasping
var isGrasping = false;
var graspInterval = Script.setInterval(function() {
if (isGrasping === false) {
startHandGrasp();
isGrasping = true;
} else {
endHandGrasp();
isGrasping = false
}
}, 1000)