mirror of
https://github.com/overte-org/overte.git
synced 2025-04-27 10:36:29 +02:00
203 lines
8.2 KiB
JavaScript
203 lines
8.2 KiB
JavaScript
"use strict";
|
|
|
|
// nearActionGrabEntity.js
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
|
|
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
|
getControllerJointIndex, getGrabbableData, NULL_UUID, enableDispatcherModule, disableDispatcherModule,
|
|
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, entityIsGrabbable,
|
|
Quat, Vec3, MSECS_PER_SEC, getControllerWorldLocation
|
|
*/
|
|
|
|
Script.include("/~/system/controllers/controllerDispatcherUtils.js");
|
|
Script.include("/~/system/libraries/controllers.js");
|
|
|
|
(function() {
|
|
|
|
function NearActionGrabEntity(hand) {
|
|
this.hand = hand;
|
|
this.grabbedThingID = null;
|
|
this.actionID = null; // action this script created...
|
|
|
|
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
|
var ACTION_TTL = 15; // seconds
|
|
var ACTION_TTL_REFRESH = 5;
|
|
|
|
// XXX does handJointIndex change if the avatar changes?
|
|
this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
|
this.controllerJointIndex = getControllerJointIndex(this.hand);
|
|
|
|
|
|
// handPosition is where the avatar's hand appears to be, in-world.
|
|
this.getHandPosition = function () {
|
|
if (this.hand === RIGHT_HAND) {
|
|
return MyAvatar.getRightPalmPosition();
|
|
} else {
|
|
return MyAvatar.getLeftPalmPosition();
|
|
}
|
|
};
|
|
|
|
this.getHandRotation = function () {
|
|
if (this.hand === RIGHT_HAND) {
|
|
return MyAvatar.getRightPalmRotation();
|
|
} else {
|
|
return MyAvatar.getLeftPalmRotation();
|
|
}
|
|
};
|
|
|
|
|
|
this.startNearGrabAction = function (controllerData, grabbedProperties) {
|
|
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
|
|
|
var grabbableData = getGrabbableData(grabbedProperties);
|
|
this.ignoreIK = grabbableData.ignoreIK;
|
|
this.kinematicGrab = grabbableData.kinematicGrab;
|
|
|
|
var handRotation;
|
|
var handPosition;
|
|
if (this.ignoreIK) {
|
|
var controllerID =
|
|
(this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand;
|
|
var controllerLocation = getControllerWorldLocation(controllerID, false);
|
|
handRotation = controllerLocation.orientation;
|
|
handPosition = controllerLocation.position;
|
|
} else {
|
|
handRotation = this.getHandRotation();
|
|
handPosition = this.getHandPosition();
|
|
}
|
|
|
|
var objectRotation = grabbedProperties.rotation;
|
|
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
|
|
|
var currentObjectPosition = grabbedProperties.position;
|
|
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
|
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
|
|
|
var now = Date.now();
|
|
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
|
|
|
if (this.actionID) {
|
|
Entities.deleteAction(this.grabbedThingID, this.actionID);
|
|
}
|
|
this.actionID = Entities.addAction("hold", this.grabbedThingID, {
|
|
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
|
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
|
relativePosition: this.offsetPosition,
|
|
relativeRotation: this.offsetRotation,
|
|
ttl: ACTION_TTL,
|
|
kinematic: this.kinematicGrab,
|
|
kinematicSetVelocity: true,
|
|
ignoreIK: this.ignoreIK
|
|
});
|
|
if (this.actionID === NULL_UUID) {
|
|
this.actionID = null;
|
|
return;
|
|
}
|
|
|
|
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
|
action: 'grab',
|
|
grabbedEntity: this.grabbedThingID,
|
|
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
|
}));
|
|
};
|
|
|
|
// this is for when the action creation failed, before
|
|
this.restartNearGrabAction = function (controllerData) {
|
|
var props = Entities.getEntityProperties(this.grabbedThingID, ["position", "rotation", "userData"]);
|
|
if (props && entityIsGrabbable(props)) {
|
|
this.startNearGrabAction(controllerData, props);
|
|
}
|
|
};
|
|
|
|
// this is for when the action is going to time-out
|
|
this.refreshNearGrabAction = function (controllerData) {
|
|
var now = Date.now();
|
|
if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) {
|
|
// if less than a 5 seconds left, refresh the actions ttl
|
|
var success = Entities.updateAction(this.grabbedThingID, this.actionID, {
|
|
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
|
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
|
relativePosition: this.offsetPosition,
|
|
relativeRotation: this.offsetRotation,
|
|
ttl: ACTION_TTL,
|
|
kinematic: this.kinematicGrab,
|
|
kinematicSetVelocity: true,
|
|
ignoreIK: this.ignoreIK
|
|
});
|
|
if (success) {
|
|
this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC);
|
|
} else {
|
|
print("continueNearGrabbing -- updateAction failed");
|
|
this.restartNearGrabAction(controllerData);
|
|
}
|
|
}
|
|
};
|
|
|
|
this.endNearGrabAction = function (controllerData) {
|
|
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
|
Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args);
|
|
|
|
Entities.deleteAction(this.grabbedThingID, this.actionID);
|
|
this.actionID = null;
|
|
|
|
this.grabbedThingID = null;
|
|
};
|
|
|
|
this.isReady = function (controllerData) {
|
|
if (controllerData.triggerClicks[this.hand] == 0) {
|
|
return false;
|
|
}
|
|
|
|
var grabbedProperties = null;
|
|
// nearbyEntityProperties is already sorted by length from controller
|
|
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
|
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
|
var props = nearbyEntityProperties[i];
|
|
if (entityIsGrabbable(props)) {
|
|
grabbedProperties = props;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (grabbedProperties) {
|
|
if (!propsArePhysical(grabbedProperties)) {
|
|
return false; // let nearParentGrabEntity handle it
|
|
}
|
|
this.grabbedThingID = grabbedProperties.id;
|
|
this.startNearGrabAction(controllerData, grabbedProperties);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
this.run = function (controllerData) {
|
|
if (controllerData.triggerClicks[this.hand] == 0) {
|
|
this.endNearGrabAction(controllerData);
|
|
return false;
|
|
}
|
|
|
|
if (!this.actionID) {
|
|
this.restartNearGrabAction(controllerData);
|
|
}
|
|
|
|
this.refreshNearGrabAction(controllerData);
|
|
|
|
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
|
Entities.callEntityMethod(this.grabbedThingID, "continueNearGrab", args);
|
|
|
|
return true;
|
|
};
|
|
}
|
|
|
|
enableDispatcherModule("LeftNearActionGrabEntity", new NearActionGrabEntity(LEFT_HAND), 500);
|
|
enableDispatcherModule("RightNearActionGrabEntity", new NearActionGrabEntity(RIGHT_HAND), 500);
|
|
|
|
this.cleanup = function () {
|
|
disableDispatcherModule("LeftNearActionGrabEntity");
|
|
disableDispatcherModule("RightNearActionGrabEntity");
|
|
};
|
|
Script.scriptEnding.connect(this.cleanup);
|
|
}());
|