put controller specific functions inside the controller object

This commit is contained in:
Seth Alves 2015-09-18 09:56:45 -07:00
parent b8c8ea2b53
commit b08f567999

View file

@ -58,9 +58,6 @@ var ZERO_VEC = {x: 0, y: 0, z: 0};
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;
var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK"));
var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK"));
// these control how long an abandoned pointer line will hang around // these control how long an abandoned pointer line will hang around
var startTime = Date.now(); var startTime = Date.now();
var LIFETIME = 10; var LIFETIME = 10;
@ -92,34 +89,32 @@ function controller(hand, triggerAction) {
this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing
this.pointer = null; // entity-id of line object this.pointer = null; // entity-id of line object
this.triggerValue = 0; // rolling average of trigger value this.triggerValue = 0; // rolling average of trigger value
}
this.update = function() {
controller.prototype.update = function() {
switch(this.state) { switch(this.state) {
case STATE_SEARCHING: case STATE_SEARCHING:
search(this); this.search();
break; break;
case STATE_DISTANCE_HOLDING: case STATE_DISTANCE_HOLDING:
distanceHolding(this); this.distanceHolding();
break; break;
case STATE_CLOSE_GRABBING: case STATE_CLOSE_GRABBING:
closeGrabbing(this); this.closeGrabbing();
break; break;
case STATE_CONTINUE_CLOSE_GRABBING: case STATE_CONTINUE_CLOSE_GRABBING:
continueCloseGrabbing(this); this.continueCloseGrabbing();
break; break;
case STATE_RELEASE: case STATE_RELEASE:
release(this); this.release();
break; break;
} }
} }
function lineOn(self, closePoint, farPoint, color) { this.lineOn = function(closePoint, farPoint, color) {
// draw a line // draw a line
if (self.pointer == null) { if (this.pointer == null) {
self.pointer = Entities.addEntity({ this.pointer = Entities.addEntity({
type: "Line", type: "Line",
name: "pointer", name: "pointer",
dimensions: LINE_ENTITY_DIMENSIONS, dimensions: LINE_ENTITY_DIMENSIONS,
@ -130,60 +125,63 @@ function lineOn(self, closePoint, farPoint, color) {
lifetime: LIFETIME lifetime: LIFETIME
}); });
} else { } else {
Entities.editEntity(self.pointer, { Entities.editEntity(this.pointer, {
position: closePoint, position: closePoint,
linePoints: [ ZERO_VEC, farPoint ], linePoints: [ ZERO_VEC, farPoint ],
color: color, color: color,
lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME lifetime: (Date.now() - startTime) / MSEC_PER_SEC + LIFETIME
}); });
} }
}
function lineOff(self) {
if (self.pointer != null) {
Entities.deleteEntity(self.pointer);
} }
self.pointer = null;
}
function triggerSmoothedSqueezed(self) {
var triggerValue = Controller.getActionValue(self.triggerAction); this.lineOff = function() {
if (this.pointer != null) {
Entities.deleteEntity(this.pointer);
}
this.pointer = null;
}
this.triggerSmoothedSqueezed = function() {
var triggerValue = Controller.getActionValue(this.triggerAction);
// smooth out trigger value // smooth out trigger value
self.triggerValue = (self.triggerValue * TRIGGER_SMOOTH_RATIO) + (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO)); this.triggerValue = (this.triggerValue * TRIGGER_SMOOTH_RATIO) +
return self.triggerValue > TRIGGER_ON_VALUE; (triggerValue * (1.0 - TRIGGER_SMOOTH_RATIO));
} return this.triggerValue > TRIGGER_ON_VALUE;
}
function triggerSqueezed(self) {
var triggerValue = Controller.getActionValue(self.triggerAction); this.triggerSqueezed = function() {
var triggerValue = Controller.getActionValue(this.triggerAction);
return triggerValue > TRIGGER_ON_VALUE; return triggerValue > TRIGGER_ON_VALUE;
} }
function search(self) { this.search = function() {
if (!triggerSmoothedSqueezed(self)) { if (!this.triggerSmoothedSqueezed()) {
self.state = STATE_RELEASE; this.state = STATE_RELEASE;
return; return;
} }
// the trigger is being pressed, do a ray test // the trigger is being pressed, do a ray test
var handPosition = self.getHandPosition(); var handPosition = this.getHandPosition();
var pickRay = {origin: handPosition, direction: Quat.getUp(self.getHandRotation())}; var pickRay = {origin: handPosition, direction: Quat.getUp(this.getHandRotation())};
var intersection = Entities.findRayIntersection(pickRay, true); var intersection = Entities.findRayIntersection(pickRay, true);
if (intersection.intersects && if (intersection.intersects &&
intersection.properties.collisionsWillMove === 1 && intersection.properties.collisionsWillMove === 1 &&
intersection.properties.locked === 0) { intersection.properties.locked === 0) {
// the ray is intersecting something we can move. // the ray is intersecting something we can move.
var handControllerPosition = Controller.getSpatialControlPosition(self.palm); var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection); var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
self.grabbedEntity = intersection.entityID; this.grabbedEntity = intersection.entityID;
if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) { if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) {
// the hand is very close to the intersected object. go into close-grabbing mode. // the hand is very close to the intersected object. go into close-grabbing mode.
self.state = STATE_CLOSE_GRABBING; this.state = STATE_CLOSE_GRABBING;
} else { } else {
// the hand is far from the intersected object. go into distance-holding mode // the hand is far from the intersected object. go into distance-holding mode
self.state = STATE_DISTANCE_HOLDING; this.state = STATE_DISTANCE_HOLDING;
lineOn(self, pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
} }
} else { } else {
// forward ray test failed, try sphere test. // forward ray test failed, try sphere test.
@ -196,158 +194,165 @@ function search(self) {
if (distance < minDistance && props.name !== "pointer" && if (distance < minDistance && props.name !== "pointer" &&
props.collisionsWillMove === 1 && props.collisionsWillMove === 1 &&
props.locked === 0) { props.locked === 0) {
self.grabbedEntity = nearbyEntities[i]; this.grabbedEntity = nearbyEntities[i];
minDistance = distance; minDistance = distance;
} }
} }
if (self.grabbedEntity === null) { if (this.grabbedEntity === null) {
lineOn(self, pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR); this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
} else { } else {
self.state = STATE_CLOSE_GRABBING; this.state = STATE_CLOSE_GRABBING;
}
} }
} }
}
function distanceHolding(self) { this.distanceHolding = function() {
if (!triggerSmoothedSqueezed(self)) { if (!this.triggerSmoothedSqueezed()) {
self.state = STATE_RELEASE; this.state = STATE_RELEASE;
return; return;
} }
var handPosition = self.getHandPosition(); var handPosition = this.getHandPosition();
var handControllerPosition = Controller.getSpatialControlPosition(self.palm); var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(self.palm)); var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity);
lineOn(self, handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR); this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
if (self.actionID === null) { if (this.actionID === null) {
// first time here since trigger pulled -- add the action and initialize some variables // first time here since trigger pulled -- add the action and initialize some variables
self.currentObjectPosition = grabbedProperties.position; this.currentObjectPosition = grabbedProperties.position;
self.currentObjectRotation = grabbedProperties.rotation; this.currentObjectRotation = grabbedProperties.rotation;
self.handPreviousPosition = handControllerPosition; this.handPreviousPosition = handControllerPosition;
self.handPreviousRotation = handRotation; this.handPreviousRotation = handRotation;
self.actionID = Entities.addAction("spring", self.grabbedEntity, { this.actionID = Entities.addAction("spring", this.grabbedEntity, {
targetPosition: self.currentObjectPosition, targetPosition: this.currentObjectPosition,
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: self.currentObjectRotation, targetRotation: this.currentObjectRotation,
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
}); });
if (self.actionID == NULL_ACTION_ID) { if (this.actionID == NULL_ACTION_ID) {
self.actionID = null; this.actionID = null;
} }
} else { } else {
// the action was set up on a previous call. update the targets. // the action was set up on a previous call. update the targets.
var radius = Math.max(Vec3.distance(self.currentObjectPosition, var radius = Math.max(Vec3.distance(this.currentObjectPosition,
handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR,
DISTANCE_HOLDING_RADIUS_FACTOR); DISTANCE_HOLDING_RADIUS_FACTOR);
var handMoved = Vec3.subtract(handControllerPosition, self.handPreviousPosition); var handMoved = Vec3.subtract(handControllerPosition, this.handPreviousPosition);
self.handPreviousPosition = handControllerPosition; this.handPreviousPosition = handControllerPosition;
var superHandMoved = Vec3.multiply(handMoved, radius); var superHandMoved = Vec3.multiply(handMoved, radius);
self.currentObjectPosition = Vec3.sum(self.currentObjectPosition, superHandMoved); this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, superHandMoved);
// this doubles hand rotation // this doubles hand rotation
var handChange = Quat.multiply(Quat.slerp(self.handPreviousRotation, handRotation, var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation,
DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR),
Quat.inverse(self.handPreviousRotation)); Quat.inverse(this.handPreviousRotation));
self.handPreviousRotation = handRotation; this.handPreviousRotation = handRotation;
self.currentObjectRotation = Quat.multiply(handChange, self.currentObjectRotation); this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
Entities.updateAction(self.grabbedEntity, self.actionID, { Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: self.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME, targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
targetRotation: self.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
}); });
} }
} }
function closeGrabbing(self) { this.closeGrabbing = function() {
if (!triggerSmoothedSqueezed(self)) { if (!this.triggerSmoothedSqueezed()) {
self.state = STATE_RELEASE; this.state = STATE_RELEASE;
return; return;
} }
lineOff(self); this.lineOff();
var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity);
var handRotation = self.getHandRotation(); var handRotation = this.getHandRotation();
var handPosition = self.getHandPosition(); var handPosition = this.getHandPosition();
var objectRotation = grabbedProperties.rotation; var objectRotation = grabbedProperties.rotation;
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation); var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
self.currentObjectPosition = grabbedProperties.position; this.currentObjectPosition = grabbedProperties.position;
self.currentObjectTime = Date.now(); this.currentObjectTime = Date.now();
var offset = Vec3.subtract(self.currentObjectPosition, handPosition); var offset = Vec3.subtract(this.currentObjectPosition, handPosition);
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset); var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
self.actionID = Entities.addAction("hold", self.grabbedEntity, { this.actionID = Entities.addAction("hold", this.grabbedEntity, {
hand: self.hand == RIGHT_HAND ? "right" : "left", hand: this.hand == RIGHT_HAND ? "right" : "left",
timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME, timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME,
relativePosition: offsetPosition, relativePosition: offsetPosition,
relativeRotation: offsetRotation relativeRotation: offsetRotation
}); });
if (self.actionID == NULL_ACTION_ID) { if (this.actionID == NULL_ACTION_ID) {
self.actionID = null; this.actionID = null;
} else { } else {
self.state = STATE_CONTINUE_CLOSE_GRABBING; this.state = STATE_CONTINUE_CLOSE_GRABBING;
}
} }
}
function continueCloseGrabbing(self) { this.continueCloseGrabbing = function() {
if (!triggerSmoothedSqueezed(self)) { if (!this.triggerSmoothedSqueezed()) {
self.state = STATE_RELEASE; this.state = STATE_RELEASE;
return; return;
} }
// keep track of the measured velocity of the held object // keep track of the measured velocity of the held object
var grabbedProperties = Entities.getEntityProperties(self.grabbedEntity); var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity);
var now = Date.now(); var now = Date.now();
var deltaPosition = Vec3.subtract(grabbedProperties.position, self.currentObjectPosition); // meters var deltaPosition = Vec3.subtract(grabbedProperties.position, this.currentObjectPosition); // meters
var deltaTime = (now - self.currentObjectTime) / MSEC_PER_SEC; // convert to seconds var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
if (deltaTime > 0.0) { if (deltaTime > 0.0) {
var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime); var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime);
// don't update grabbedVelocity if the trigger is off. the smoothing of the trigger // don't update grabbedVelocity if the trigger is off. the smoothing of the trigger
// value would otherwise give the held object time to slow down. // value would otherwise give the held object time to slow down.
if (triggerSqueezed(self)) { if (this.triggerSqueezed()) {
self.grabbedVelocity = Vec3.sum(Vec3.multiply(self.grabbedVelocity, (1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)), this.grabbedVelocity =
Vec3.sum(Vec3.multiply(this.grabbedVelocity,
(1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)),
Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)); Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO));
} }
} }
self.currentObjectPosition = grabbedProperties.position; this.currentObjectPosition = grabbedProperties.position;
self.currentObjectTime = now; this.currentObjectTime = now;
} }
function release(self) { this.release = function() {
lineOff(self); this.lineOff();
if (self.grabbedEntity != null && self.actionID != null) { if (this.grabbedEntity != null && this.actionID != null) {
Entities.deleteAction(self.grabbedEntity, self.actionID); Entities.deleteAction(this.grabbedEntity, this.actionID);
} }
// the action will tend to quickly bring an object's velocity to zero. now that // the action will tend to quickly bring an object's velocity to zero. now that
// the action is gone, set the objects velocity to something the holder might expect. // the action is gone, set the objects velocity to something the holder might expect.
Entities.editEntity(self.grabbedEntity, {velocity: self.grabbedVelocity}); Entities.editEntity(this.grabbedEntity, {velocity: this.grabbedVelocity});
self.grabbedVelocity = ZERO_VEC; this.grabbedVelocity = ZERO_VEC;
self.grabbedEntity = null; this.grabbedEntity = null;
self.actionID = null; this.actionID = null;
self.state = STATE_SEARCHING; this.state = STATE_SEARCHING;
}
this.cleanup = function() {
release();
}
} }
controller.prototype.cleanup = function() { var rightController = new controller(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK"));
release(this); var leftController = new controller(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK"));
}
function update() { function update() {