mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
starting on controller-dispatcher experiment
This commit is contained in:
parent
bcb819206b
commit
f0c9f1d120
4 changed files with 340 additions and 7 deletions
|
@ -20,15 +20,15 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
||||||
"system/bubble.js",
|
"system/bubble.js",
|
||||||
"system/snapshot.js",
|
"system/snapshot.js",
|
||||||
"system/help.js",
|
"system/help.js",
|
||||||
"system/pal.js", // "system/mod.js", // older UX, if you prefer
|
// "system/pal.js", // "system/mod.js", // older UX, if you prefer
|
||||||
"system/makeUserConnection.js",
|
"system/makeUserConnection.js",
|
||||||
"system/tablet-goto.js",
|
"system/tablet-goto.js",
|
||||||
"system/marketplaces/marketplaces.js",
|
"system/marketplaces/marketplaces.js",
|
||||||
"system/edit.js",
|
// "system/edit.js",
|
||||||
"system/notifications.js",
|
"system/notifications.js",
|
||||||
"system/dialTone.js",
|
"system/dialTone.js",
|
||||||
"system/firstPersonHMD.js",
|
"system/firstPersonHMD.js",
|
||||||
"system/tablet-ui/tabletUI.js"
|
// "system/tablet-ui/tabletUI.js"
|
||||||
];
|
];
|
||||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||||
"system/controllers/controllerScripts.js",
|
"system/controllers/controllerScripts.js",
|
||||||
|
|
122
scripts/system/controllers/controllerDispatcher.js
Normal file
122
scripts/system/controllers/controllerDispatcher.js
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// controllerDispatcher.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, controllerDispatcherPlugins, Controller, Vec3, getControllerWorldLocation */
|
||||||
|
|
||||||
|
Script.include("/~/system/libraries/utils.js");
|
||||||
|
Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
// var LEFT_HAND = 0;
|
||||||
|
// var RIGHT_HAND = 1;
|
||||||
|
|
||||||
|
var NEAR_GRAB_RADIUS = 0.1;
|
||||||
|
var DISPATCHER_PROPERTIES = [
|
||||||
|
"position",
|
||||||
|
"registrationPoint",
|
||||||
|
"rotation",
|
||||||
|
"gravity",
|
||||||
|
"collidesWith",
|
||||||
|
"dynamic",
|
||||||
|
"collisionless",
|
||||||
|
"locked",
|
||||||
|
"name",
|
||||||
|
"shapeType",
|
||||||
|
"parentID",
|
||||||
|
"parentJointIndex",
|
||||||
|
"density",
|
||||||
|
"dimensions",
|
||||||
|
"userData"
|
||||||
|
];
|
||||||
|
|
||||||
|
this.runningPluginName = null;
|
||||||
|
|
||||||
|
this.leftTriggerPress = function(value) {
|
||||||
|
_this.leftTriggerValue = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.leftTriggerClick = function(value) {
|
||||||
|
_this.leftTriggerClicked = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.rightTriggerPress = function(value) {
|
||||||
|
_this.rightTriggerValue = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.rightTriggerClick = function(value) {
|
||||||
|
_this.rightTriggerClicked = value;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.update = function () {
|
||||||
|
|
||||||
|
var leftControllerLocation = getControllerWorldLocation(Controller.Standard.LeftHand, true);
|
||||||
|
var rightControllerLocation = getControllerWorldLocation(Controller.Standard.RightHand, true);
|
||||||
|
|
||||||
|
var leftNearbyEntityIDs = Entities.findEntities(leftControllerLocation, NEAR_GRAB_RADIUS);
|
||||||
|
var rightNearbyEntityIDs = Entities.findEntities(rightControllerLocation, NEAR_GRAB_RADIUS);
|
||||||
|
|
||||||
|
var leftNearbyEntityProperties = {};
|
||||||
|
leftNearbyEntityIDs.forEach(function (entityID) {
|
||||||
|
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
|
||||||
|
props.id = entityID;
|
||||||
|
props.distanceFromController = Vec3.length(Vec3.subtract(leftControllerLocation, props.position));
|
||||||
|
leftNearbyEntityProperties.push(props);
|
||||||
|
});
|
||||||
|
|
||||||
|
var rightNearbyEntityProperties = {};
|
||||||
|
rightNearbyEntityIDs.forEach(function (entityID) {
|
||||||
|
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
|
||||||
|
props.id = entityID;
|
||||||
|
props.distanceFromController = Vec3.length(Vec3.subtract(rightControllerLocation, props.position));
|
||||||
|
rightNearbyEntityProperties.push(props);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var controllerData = {
|
||||||
|
triggerValues: [this.leftTriggerValue, this.rightTriggerValue],
|
||||||
|
triggerPresses: [this.leftTriggerPress, this.rightTriggerPress],
|
||||||
|
controllerLocations: [ leftControllerLocation, rightControllerLocation ],
|
||||||
|
nearbyEntityProperties: [ leftNearbyEntityProperties, rightNearbyEntityProperties ],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.runningPluginName) {
|
||||||
|
var plugin = controllerDispatcherPlugins[this.runningPluginName];
|
||||||
|
if (!plugin || !plugin.run(controllerData)) {
|
||||||
|
this.runningPluginName = null;
|
||||||
|
}
|
||||||
|
} else if (controllerDispatcherPlugins) {
|
||||||
|
for (var pluginName in controllerDispatcherPlugins) {
|
||||||
|
// TODO sort names by plugin.priority
|
||||||
|
if (controllerDispatcherPlugins.hasOwnProperty(pluginName)) {
|
||||||
|
var candidatePlugin = controllerDispatcherPlugins[pluginName];
|
||||||
|
if (candidatePlugin.isReady(controllerData)) {
|
||||||
|
this.runningPluginName = candidatePlugin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var MAPPING_NAME = "com.highfidelity.controllerDispatcher";
|
||||||
|
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||||
|
mapping.from([Controller.Standard.RT]).peek().to(this.rightTriggerPress);
|
||||||
|
mapping.from([Controller.Standard.RTClick]).peek().to(this.rightTriggerClicked);
|
||||||
|
mapping.from([Controller.Standard.LT]).peek().to(this.leftTriggerPress);
|
||||||
|
mapping.from([Controller.Standard.LTClick]).peek().to(this.leftTriggerClicked);
|
||||||
|
Controller.enableMapping(MAPPING_NAME);
|
||||||
|
|
||||||
|
this.cleanup = function () {
|
||||||
|
Script.update.disconnect(this.update);
|
||||||
|
Controller.disableMapping(MAPPING_NAME);
|
||||||
|
};
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(this.cleanup);
|
||||||
|
Script.update.connect(this.update);
|
||||||
|
}());
|
|
@ -12,11 +12,14 @@
|
||||||
var CONTOLLER_SCRIPTS = [
|
var CONTOLLER_SCRIPTS = [
|
||||||
"squeezeHands.js",
|
"squeezeHands.js",
|
||||||
"controllerDisplayManager.js",
|
"controllerDisplayManager.js",
|
||||||
"handControllerGrab.js",
|
// "handControllerGrab.js",
|
||||||
"handControllerPointer.js",
|
// "handControllerPointer.js",
|
||||||
"grab.js",
|
// "grab.js",
|
||||||
"teleport.js",
|
// "teleport.js",
|
||||||
"toggleAdvancedMovementForHandControllers.js",
|
"toggleAdvancedMovementForHandControllers.js",
|
||||||
|
|
||||||
|
"ControllerDispatcher.js",
|
||||||
|
"nearGrab.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
|
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
|
||||||
|
|
208
scripts/system/controllers/nearGrab.js
Normal file
208
scripts/system/controllers/nearGrab.js
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// nearGrab.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, HMD, Camera, MyAvatar, Controller, controllerDispatcherPlugins */
|
||||||
|
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
var LEFT_HAND = 0;
|
||||||
|
var RIGHT_HAND = 1;
|
||||||
|
|
||||||
|
var HAPTIC_PULSE_STRENGTH = 1.0;
|
||||||
|
var HAPTIC_PULSE_DURATION = 13.0;
|
||||||
|
|
||||||
|
var FORBIDDEN_GRAB_TYPES = ["Unknown", "Light", "PolyLine", "Zone"];
|
||||||
|
var FORBIDDEN_GRAB_NAMES = ["Grab Debug Entity", "grab pointer"];
|
||||||
|
|
||||||
|
var NULL_UUID = "{00000000-0000-0000-0000-000000000000}";
|
||||||
|
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||||
|
|
||||||
|
function getControllerJointIndex(hand) {
|
||||||
|
if (HMD.isHandControllerAvailable()) {
|
||||||
|
var controllerJointIndex = -1;
|
||||||
|
if (Camera.mode === "first person") {
|
||||||
|
controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
|
||||||
|
"_CONTROLLER_RIGHTHAND" :
|
||||||
|
"_CONTROLLER_LEFTHAND");
|
||||||
|
} else if (Camera.mode === "third person") {
|
||||||
|
controllerJointIndex = MyAvatar.getJointIndex(hand === RIGHT_HAND ?
|
||||||
|
"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
|
||||||
|
"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
|
||||||
|
}
|
||||||
|
|
||||||
|
return controllerJointIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MyAvatar.getJointIndex("Head");
|
||||||
|
}
|
||||||
|
|
||||||
|
function propsArePhysical(props) {
|
||||||
|
if (!props.dynamic) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var isPhysical = (props.shapeType && props.shapeType != 'none');
|
||||||
|
return isPhysical;
|
||||||
|
}
|
||||||
|
|
||||||
|
function entityIsGrabbable(props) {
|
||||||
|
var grabbableProps = {};
|
||||||
|
var userDataParsed = JSON.parse(props.userData);
|
||||||
|
if (userDataParsed && userDataParsed.grabbable) {
|
||||||
|
grabbableProps = userDataParsed.grabbable;
|
||||||
|
}
|
||||||
|
var grabbable = propsArePhysical(props);
|
||||||
|
if (grabbableProps.hasOwnProperty("grabbable")) {
|
||||||
|
grabbable = grabbableProps.grabbable;
|
||||||
|
}
|
||||||
|
if (!grabbable) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (FORBIDDEN_GRAB_TYPES.indexOf(props.type) >= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (props.locked) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (FORBIDDEN_GRAB_NAMES.indexOf(props.name) >= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function NearGrab(hand) {
|
||||||
|
this.priority = 5;
|
||||||
|
|
||||||
|
this.hand = hand;
|
||||||
|
this.grabbedThingID = null;
|
||||||
|
this.previousParentID = {};
|
||||||
|
this.previousParentJointIndex = {};
|
||||||
|
this.previouslyUnhooked = {};
|
||||||
|
|
||||||
|
|
||||||
|
this.handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
||||||
|
|
||||||
|
this.thisHandIsParent = function(props) {
|
||||||
|
if (props.parentID !== MyAvatar.sessionUUID && props.parentID !== AVATAR_SELF_ID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
|
||||||
|
if (props.parentJointIndex == handJointIndex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var controllerJointIndex = this.controllerJointIndex;
|
||||||
|
if (props.parentJointIndex == controllerJointIndex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var controllerCRJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ?
|
||||||
|
"_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" :
|
||||||
|
"_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
|
||||||
|
if (props.parentJointIndex == controllerCRJointIndex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.startNearGrab = function (controllerData) {
|
||||||
|
var grabbedProperties = controllerData.nearbyEntityProperties[this.hand][this.grabbedThingID];
|
||||||
|
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||||
|
|
||||||
|
var reparentProps = {
|
||||||
|
parentID: AVATAR_SELF_ID,
|
||||||
|
parentJointIndex: getControllerJointIndex(this.hand),
|
||||||
|
velocity: {x: 0, y: 0, z: 0},
|
||||||
|
angularVelocity: {x: 0, y: 0, z: 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (this.thisHandIsParent(grabbedProperties)) {
|
||||||
|
// this should never happen, but if it does, don't set previous parent to be this hand.
|
||||||
|
// this.previousParentID[this.grabbedThingID] = NULL;
|
||||||
|
// this.previousParentJointIndex[this.grabbedThingID] = -1;
|
||||||
|
} else {
|
||||||
|
this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID;
|
||||||
|
this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex;
|
||||||
|
}
|
||||||
|
Entities.editEntity(this.grabbedThingID, reparentProps);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.endNearGrab = function (controllerData) {
|
||||||
|
if (this.previousParentID[this.grabbedThingID] === NULL_UUID) {
|
||||||
|
Entities.editEntity(this.grabbedThingID, {
|
||||||
|
parentID: this.previousParentID[this.grabbedThingID],
|
||||||
|
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID]
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// we're putting this back as a child of some other parent, so zero its velocity
|
||||||
|
Entities.editEntity(this.grabbedThingID, {
|
||||||
|
parentID: this.previousParentID[this.grabbedThingID],
|
||||||
|
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID],
|
||||||
|
velocity: {x: 0, y: 0, z: 0},
|
||||||
|
angularVelocity: {x: 0, y: 0, z: 0}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.grabbedThingID = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isReady = function (controllerData) {
|
||||||
|
if (!controllerData.triggerPresses[this.hand]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var grabbable = null;
|
||||||
|
var bestDistance = 1000;
|
||||||
|
controllerData.nearbyEntityProperties[this.hand].forEach(function(nearbyEntityProperties) {
|
||||||
|
if (entityIsGrabbable(nearbyEntityProperties)) {
|
||||||
|
if (nearbyEntityProperties.distanceFromController < bestDistance) {
|
||||||
|
bestDistance = nearbyEntityProperties.distanceFromController;
|
||||||
|
grabbable = nearbyEntityProperties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (grabbable) {
|
||||||
|
this.grabbedThingID = grabbable.id;
|
||||||
|
this.startNearGrab();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.run = function (controllerData) {
|
||||||
|
if (!controllerData.triggerPresses[this.hand]) {
|
||||||
|
this.endNearGrab(controllerData);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var leftNearGrab = new NearGrab(LEFT_HAND);
|
||||||
|
leftNearGrab.name = "leftNearGrab";
|
||||||
|
|
||||||
|
var rightNearGrab = new NearGrab(RIGHT_HAND);
|
||||||
|
rightNearGrab.name = "rightNearGrab";
|
||||||
|
|
||||||
|
if (!controllerDispatcherPlugins) {
|
||||||
|
controllerDispatcherPlugins = {};
|
||||||
|
}
|
||||||
|
controllerDispatcherPlugins.leftNearGrab = leftNearGrab;
|
||||||
|
controllerDispatcherPlugins.rightNearGrab = rightNearGrab;
|
||||||
|
|
||||||
|
|
||||||
|
this.cleanup = function () {
|
||||||
|
delete controllerDispatcherPlugins.leftNearGrab;
|
||||||
|
delete controllerDispatcherPlugins.rightNearGrab;
|
||||||
|
};
|
||||||
|
Script.scriptEnding.connect(this.cleanup);
|
||||||
|
}());
|
Loading…
Reference in a new issue