equip from a distance uses a spring to pull the object to the hand before equipping it

This commit is contained in:
Seth Alves 2015-11-17 17:18:16 -08:00
parent 5ae3c5aea0
commit 94f18672d4

View file

@ -55,6 +55,13 @@ 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
//
// equip
//
var EQUIP_SPRING_SHUTOFF_DISTANCE = 0.05;
var EQUIP_SPRING_TIMEFRAME = 0.4; // how quickly objects move to their new position
// //
// other constants // other constants
// //
@ -70,7 +77,7 @@ var ZERO_VEC = {
var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}"; var NULL_ACTION_ID = "{00000000-0000-0000-000000000000}";
var MSEC_PER_SEC = 1000.0; var MSEC_PER_SEC = 1000.0;
// these control how long an abandoned pointer line will hang around // these control how long an abandoned pointer line or action will hang around
var LIFETIME = 10; var LIFETIME = 10;
var ACTION_TTL = 15; // seconds var ACTION_TTL = 15; // seconds
var ACTION_TTL_REFRESH = 5; var ACTION_TTL_REFRESH = 5;
@ -113,6 +120,7 @@ var STATE_EQUIP = 12
var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down var STATE_CONTINUE_EQUIP_BD = 13; // equip while bumper is still held down
var STATE_CONTINUE_EQUIP = 14; var STATE_CONTINUE_EQUIP = 14;
var STATE_WAITING_FOR_BUMPER_RELEASE = 15; var STATE_WAITING_FOR_BUMPER_RELEASE = 15;
var STATE_EQUIP_SPRING = 16;
function stateToName(state) { function stateToName(state) {
@ -149,6 +157,8 @@ function stateToName(state) {
return "continue_equip"; return "continue_equip";
case STATE_WAITING_FOR_BUMPER_RELEASE: case STATE_WAITING_FOR_BUMPER_RELEASE:
return "waiting_for_bumper_release"; return "waiting_for_bumper_release";
case STATE_EQUIP_SPRING:
return "state_equip_spring";
} }
return "unknown"; return "unknown";
@ -228,14 +238,15 @@ function MyController(hand) {
this.continueDistanceHolding(); this.continueDistanceHolding();
break; break;
case STATE_NEAR_GRABBING: case STATE_NEAR_GRABBING:
this.nearGrabbing();
break;
case STATE_EQUIP: case STATE_EQUIP:
this.nearGrabbing(); this.nearGrabbing();
break; break;
case STATE_WAITING_FOR_BUMPER_RELEASE: case STATE_WAITING_FOR_BUMPER_RELEASE:
this.waitingForBumperRelease(); this.waitingForBumperRelease();
break; break;
case STATE_EQUIP_SPRING:
this.pullTowardEquipPosition()
break;
case STATE_CONTINUE_NEAR_GRABBING: case STATE_CONTINUE_NEAR_GRABBING:
case STATE_CONTINUE_EQUIP_BD: case STATE_CONTINUE_EQUIP_BD:
case STATE_CONTINUE_EQUIP: case STATE_CONTINUE_EQUIP:
@ -444,7 +455,15 @@ function MyController(hand) {
return; return;
} else if (!intersection.properties.locked) { } else if (!intersection.properties.locked) {
this.grabbedEntity = intersection.entityID; this.grabbedEntity = intersection.entityID;
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP) if (this.state == STATE_SEARCHING) {
this.setState(STATE_NEAR_GRABBING);
} else { // equipping
if (typeof grabbableData.spatialKey !== 'undefined') {
this.setState(STATE_EQUIP_SPRING);
} else {
this.setState(STATE_EQUIP);
}
}
return; return;
} }
} else if (! entityIsGrabbedByOther(intersection.entityID)) { } else if (! entityIsGrabbedByOther(intersection.entityID)) {
@ -455,7 +474,7 @@ function MyController(hand) {
this.grabbedEntity = intersection.entityID; this.grabbedEntity = intersection.entityID;
if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) { if (typeof grabbableData.spatialKey !== 'undefined' && this.state == STATE_EQUIP_SEARCHING) {
// if a distance pick in equip mode hits something with a spatialKey, equip it // if a distance pick in equip mode hits something with a spatialKey, equip it
this.setState(STATE_EQUIP); this.setState(STATE_EQUIP_SPRING);
return; return;
} else if (this.state == STATE_SEARCHING) { } else if (this.state == STATE_SEARCHING) {
this.setState(STATE_DISTANCE_HOLDING); this.setState(STATE_DISTANCE_HOLDING);
@ -750,7 +769,13 @@ function MyController(hand) {
this.actionID = null; this.actionID = null;
} else { } else {
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC); this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
this.setState(this.state == STATE_NEAR_GRABBING ? STATE_CONTINUE_NEAR_GRABBING : STATE_CONTINUE_EQUIP_BD) if (this.state == STATE_NEAR_GRABBING) {
this.setState(STATE_CONTINUE_NEAR_GRABBING);
} else {
// equipping
this.setState(STATE_CONTINUE_EQUIP_BD);
}
if (this.hand === RIGHT_HAND) { if (this.hand === RIGHT_HAND) {
Entities.callEntityMethod(this.grabbedEntity, "setRightHand"); Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
} else { } else {
@ -822,7 +847,60 @@ function MyController(hand) {
this.setState(STATE_RELEASE); this.setState(STATE_RELEASE);
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab"); Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
} }
} };
this.pullTowardEquipPosition = function() {
this.lineOff();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
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 };
if (grabbableData.spatialKey.relativePosition) {
relativePosition = grabbableData.spatialKey.relativePosition;
}
if (grabbableData.spatialKey.relativeRotation) {
relativeRotation = grabbableData.spatialKey.relativeRotation;
}
var handRotation = this.getHandRotation();
var handPosition = this.getHandPosition();
var targetRotation = Quat.multiply(handRotation, relativeRotation);
var offset = Vec3.multiplyQbyV(targetRotation, relativePosition);
var targetPosition = Vec3.sum(handPosition, offset);
if (typeof this.equipSpringID === 'undefined' ||
this.equipSpringID === null ||
this.equipSpringID === NULL_ACTION_ID) {
this.equipSpringID = Entities.addAction("spring", this.grabbedEntity, {
targetPosition: targetPosition,
linearTimeScale: EQUIP_SPRING_TIMEFRAME,
targetRotation: targetRotation,
angularTimeScale: EQUIP_SPRING_TIMEFRAME,
ttl: ACTION_TTL
});
if (this.equipSpringID === NULL_ACTION_ID) {
this.equipSpringID = null;
this.setState(STATE_OFF);
return;
}
} else {
Entities.updateAction(this.grabbedEntity, this.equipSpringID, {
targetPosition: targetPosition,
linearTimeScale: EQUIP_SPRING_TIMEFRAME,
targetRotation: targetRotation,
angularTimeScale: EQUIP_SPRING_TIMEFRAME,
ttl: ACTION_TTL
});
}
if (Vec3.distance(grabbedProperties.position, targetPosition) < EQUIP_SPRING_SHUTOFF_DISTANCE) {
Entities.deleteAction(this.grabbedEntity, this.equipSpringID);
this.equipSpringID = null;
this.setState(STATE_EQUIP);
}
};
this.nearTrigger = function() { this.nearTrigger = function() {
if (this.triggerSmoothedReleased()) { if (this.triggerSmoothedReleased()) {