mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 03:24:13 +02:00
Merge pull request #9180 from huffman/feat/tutorial-touch
Add touch support to tutorial
This commit is contained in:
commit
59f6c8857d
31 changed files with 932 additions and 354 deletions
interface
resources/meshes/controller/touch
Oculus-Labels-L.fbxOculus-Labels-R.fbxtouch_l.fbxtouch_l_body.fbxtouch_l_bumper.fbxtouch_l_button_x.fbxtouch_l_button_y.fbxtouch_l_joystick.fbxtouch_l_trigger.fbxtouch_r.fbxtouch_r_body.fbxtouch_r_bumper.fbxtouch_r_button_a.fbxtouch_r_button_b.fbxtouch_r_joystick.fbxtouch_r_trigger.fbx
src
libraries
networking/src
plugins/src/plugins
render-utils/src
scripts/system/controllers
controllerDisplay.jscontrollerDisplayManager.jstouchControllerConfiguration.jsviveControllerConfiguration.js
tutorial
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-L.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-L.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-R.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/Oculus-Labels-R.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_body.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_body.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_bumper.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_bumper.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_button_x.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_button_x.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_button_y.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_button_y.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_joystick.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_joystick.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_l_trigger.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_l_trigger.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_body.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_body.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_bumper.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_bumper.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_button_a.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_button_a.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_button_b.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_button_b.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_joystick.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_joystick.fbx
Normal file
Binary file not shown.
BIN
interface/resources/meshes/controller/touch/touch_r_trigger.fbx
Normal file
BIN
interface/resources/meshes/controller/touch/touch_r_trigger.fbx
Normal file
Binary file not shown.
|
@ -1389,16 +1389,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
}
|
||||
qCDebug(interfaceapp) << "Server content version: " << contentVersion;
|
||||
|
||||
bool hasTutorialContent = contentVersion >= 1;
|
||||
static const int MIN_VIVE_CONTENT_VERSION = 1;
|
||||
static const int MIN_OCULUS_TOUCH_CONTENT_VERSION = 27;
|
||||
|
||||
bool hasSufficientTutorialContent = false;
|
||||
bool hasHandControllers = false;
|
||||
|
||||
// Only specific hand controllers are currently supported, so only send users to the tutorial
|
||||
// if they have one of those hand controllers.
|
||||
if (PluginUtils::isViveControllerAvailable()) {
|
||||
hasHandControllers = true;
|
||||
hasSufficientTutorialContent = contentVersion >= MIN_VIVE_CONTENT_VERSION;
|
||||
} else if (PluginUtils::isOculusTouchControllerAvailable()) {
|
||||
hasHandControllers = true;
|
||||
hasSufficientTutorialContent = contentVersion >= MIN_OCULUS_TOUCH_CONTENT_VERSION;
|
||||
}
|
||||
|
||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||
bool hasHMDAndHandControllers = PluginUtils::isHMDAvailable("OpenVR (Vive)") && PluginUtils::isHandControllerAvailable();
|
||||
|
||||
bool hasHMDAndHandControllers = PluginUtils::isHMDAvailable() && hasHandControllers;
|
||||
Setting::Handle<bool> tutorialComplete { "tutorialComplete", false };
|
||||
|
||||
bool shouldGoToTutorial = hasHMDAndHandControllers && hasTutorialContent && !tutorialComplete.get();
|
||||
bool shouldGoToTutorial = hasHMDAndHandControllers && hasSufficientTutorialContent && !tutorialComplete.get();
|
||||
|
||||
qCDebug(interfaceapp) << "Has HMD + Hand Controllers: " << hasHMDAndHandControllers << ", current plugin: " << _displayPlugin->getName();
|
||||
qCDebug(interfaceapp) << "Has tutorial content: " << hasTutorialContent;
|
||||
qCDebug(interfaceapp) << "Has sufficient tutorial content (" << contentVersion << ") : " << hasSufficientTutorialContent;
|
||||
qCDebug(interfaceapp) << "Tutorial complete: " << tutorialComplete.get();
|
||||
qCDebug(interfaceapp) << "Should go to tutorial: " << shouldGoToTutorial;
|
||||
|
||||
|
|
|
@ -49,12 +49,17 @@ glm::vec2 HMDScriptingInterface::overlayToSpherical(const glm::vec2 & position)
|
|||
return qApp->getApplicationCompositor().overlayToSpherical(position);
|
||||
}
|
||||
|
||||
bool HMDScriptingInterface::isHMDAvailable() {
|
||||
return PluginUtils::isHMDAvailable();
|
||||
bool HMDScriptingInterface::isHMDAvailable(const QString& name) {
|
||||
return PluginUtils::isHMDAvailable(name);
|
||||
}
|
||||
|
||||
bool HMDScriptingInterface::isHandControllerAvailable() {
|
||||
return PluginUtils::isHandControllerAvailable();
|
||||
bool HMDScriptingInterface::isHandControllerAvailable(const QString& name) {
|
||||
return PluginUtils::isHandControllerAvailable(name);
|
||||
}
|
||||
|
||||
|
||||
bool HMDScriptingInterface::isSubdeviceContainingNameAvailable(const QString& name) {
|
||||
return PluginUtils::isSubdeviceContainingNameAvailable(name);
|
||||
}
|
||||
|
||||
void HMDScriptingInterface::requestShowHandControllers() {
|
||||
|
|
|
@ -38,8 +38,9 @@ public:
|
|||
Q_INVOKABLE QString preferredAudioInput() const;
|
||||
Q_INVOKABLE QString preferredAudioOutput() const;
|
||||
|
||||
Q_INVOKABLE bool isHMDAvailable();
|
||||
Q_INVOKABLE bool isHandControllerAvailable();
|
||||
Q_INVOKABLE bool isHMDAvailable(const QString& name = "");
|
||||
Q_INVOKABLE bool isHandControllerAvailable(const QString& name = "");
|
||||
Q_INVOKABLE bool isSubdeviceContainingNameAvailable(const QString& name);
|
||||
|
||||
Q_INVOKABLE void requestShowHandControllers();
|
||||
Q_INVOKABLE void requestHideHandControllers();
|
||||
|
|
|
@ -25,14 +25,15 @@ void UserActivityLoggerScriptingInterface::toggledAway(bool isAway) {
|
|||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::tutorialProgress( QString stepName, int stepNumber, float secondsToComplete,
|
||||
float tutorialElapsedTime, QString tutorialRunID, int tutorialVersion) {
|
||||
float tutorialElapsedTime, QString tutorialRunID, int tutorialVersion, QString controllerType) {
|
||||
logAction("tutorial_progress", {
|
||||
{ "tutorial_run_id", tutorialRunID },
|
||||
{ "tutorial_version", tutorialVersion },
|
||||
{ "step", stepName },
|
||||
{ "step_number", stepNumber },
|
||||
{ "seconds_to_complete", secondsToComplete },
|
||||
{ "tutorial_elapsed_seconds", tutorialElapsedTime }
|
||||
{ "tutorial_elapsed_seconds", tutorialElapsedTime },
|
||||
{ "controller_type", controllerType }
|
||||
});
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public:
|
|||
Q_INVOKABLE void openedMarketplace();
|
||||
Q_INVOKABLE void toggledAway(bool isAway);
|
||||
Q_INVOKABLE void tutorialProgress(QString stepName, int stepNumber, float secondsToComplete,
|
||||
float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0);
|
||||
float tutorialElapsedTime, QString tutorialRunID = "", int tutorialVersion = 0, QString controllerType = "");
|
||||
|
||||
private:
|
||||
void logAction(QString action, QJsonObject details = {});
|
||||
|
|
|
@ -24,16 +24,16 @@ bool PluginUtils::isHMDAvailable(const QString& pluginName) {
|
|||
return false;
|
||||
}
|
||||
|
||||
bool PluginUtils::isHandControllerAvailable() {
|
||||
bool PluginUtils::isHandControllerAvailable(const QString& pluginName) {
|
||||
for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isHandController()) {
|
||||
if (inputPlugin->isHandController() && (pluginName.isEmpty() || inputPlugin->getName() == pluginName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
bool isSubdeviceContainingNameAvailable(QString name) {
|
||||
bool PluginUtils::isSubdeviceContainingNameAvailable(QString name) {
|
||||
for (auto& inputPlugin : PluginManager::getInstance()->getInputPlugins()) {
|
||||
if (inputPlugin->isActive()) {
|
||||
auto subdeviceNames = inputPlugin->getSubdeviceNames();
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
class PluginUtils {
|
||||
public:
|
||||
static bool isHMDAvailable(const QString& pluginName = "");
|
||||
static bool isHandControllerAvailable();
|
||||
static bool isHandControllerAvailable(const QString& pluginName = "");
|
||||
static bool isSubdeviceContainingNameAvailable(QString name);
|
||||
static bool isViveControllerAvailable();
|
||||
static bool isOculusTouchControllerAvailable();
|
||||
static bool isXboxControllerAvailable();
|
||||
|
|
|
@ -850,6 +850,12 @@ void Model::setTextures(const QVariantMap& textures) {
|
|||
_needsUpdateTextures = true;
|
||||
_needsFixupInScene = true;
|
||||
_renderGeometry->setTextures(textures);
|
||||
} else {
|
||||
// FIXME(Huffman): Disconnect previously connected lambdas so we don't set textures multiple
|
||||
// after the geometry has finished loading.
|
||||
connect(&_renderWatcher, &GeometryResourceWatcher::finished, this, [this, textures]() {
|
||||
_renderGeometry->setTextures(textures);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,14 +21,17 @@ function clamp(value, min, max) {
|
|||
}
|
||||
|
||||
function resolveHardware(path) {
|
||||
var parts = path.split(".");
|
||||
function resolveInner(base, path, i) {
|
||||
if (i >= path.length) {
|
||||
return base;
|
||||
if (typeof path === 'string') {
|
||||
var parts = path.split(".");
|
||||
function resolveInner(base, path, i) {
|
||||
if (i >= path.length) {
|
||||
return base;
|
||||
}
|
||||
return resolveInner(base[path[i]], path, ++i);
|
||||
}
|
||||
return resolveInner(base[path[i]], path, ++i);
|
||||
return resolveInner(Controller.Hardware, parts, 0);
|
||||
}
|
||||
return resolveInner(Controller.Hardware, parts, 0);
|
||||
return path;
|
||||
}
|
||||
|
||||
var DEBUG = true;
|
||||
|
@ -132,7 +135,9 @@ createControllerDisplay = function(config) {
|
|||
overlayID = Overlays.addOverlay("model", properties);
|
||||
|
||||
if (part.type === "rotational") {
|
||||
mapping.from([part.input]).peek().to(function(controller, overlayID, part) {
|
||||
var input = resolveHardware(part.input);
|
||||
print("Mapping to: ", part.input, input);
|
||||
mapping.from([input]).peek().to(function(controller, overlayID, part) {
|
||||
return function(value) {
|
||||
value = clamp(value, part.minValue, part.maxValue);
|
||||
|
||||
|
@ -157,18 +162,85 @@ createControllerDisplay = function(config) {
|
|||
}(controller, overlayID, part));
|
||||
} else if (part.type === "touchpad") {
|
||||
var visibleInput = resolveHardware(part.visibleInput);
|
||||
var xinput = resolveHardware(part.xInput);
|
||||
var yinput = resolveHardware(part.yInput);
|
||||
var xInput = resolveHardware(part.xInput);
|
||||
var yInput = resolveHardware(part.yInput);
|
||||
|
||||
// TODO: Touchpad inputs are currently only working for half
|
||||
// of the touchpad. When that is fixed, it would be useful
|
||||
// to update these to display the current finger position.
|
||||
mapping.from([visibleInput]).peek().to(function(value) {
|
||||
});
|
||||
mapping.from([xinput]).peek().to(function(value) {
|
||||
mapping.from([xInput]).peek().to(function(value) {
|
||||
});
|
||||
mapping.from([yinput]).peek().invert().to(function(value) {
|
||||
mapping.from([yInput]).peek().invert().to(function(value) {
|
||||
});
|
||||
} else if (part.type === "joystick") {
|
||||
(function(controller, overlayID, part) {
|
||||
const xInput = resolveHardware(part.xInput);
|
||||
const yInput = resolveHardware(part.yInput);
|
||||
|
||||
var xvalue = 0;
|
||||
var yvalue = 0;
|
||||
|
||||
function calculatePositionAndRotation(xValue, yValue) {
|
||||
var rotation = Quat.fromPitchYawRollDegrees(yValue * part.xHalfAngle, 0, xValue * part.yHalfAngle);
|
||||
|
||||
var offset = { x: 0, y: 0, z: 0 };
|
||||
if (part.originOffset) {
|
||||
offset = Vec3.multiplyQbyV(rotation, part.originOffset);
|
||||
offset = Vec3.subtract(part.originOffset, offset);
|
||||
}
|
||||
|
||||
var partPosition = Vec3.sum(controller.position,
|
||||
Vec3.multiplyQbyV(controller.rotation, Vec3.sum(offset, part.naturalPosition)));
|
||||
|
||||
var partRotation = Quat.multiply(controller.rotation, rotation)
|
||||
|
||||
return {
|
||||
position: partPosition,
|
||||
rotation: partRotation
|
||||
}
|
||||
}
|
||||
|
||||
mapping.from([xInput]).peek().to(function(value) {
|
||||
xvalue = value;
|
||||
//print(overlayID, xvalue.toFixed(3), yvalue.toFixed(3));
|
||||
var posRot = calculatePositionAndRotation(xvalue, yvalue);
|
||||
Overlays.editOverlay(overlayID, {
|
||||
localPosition: posRot.position,
|
||||
localRotation: posRot.rotation
|
||||
});
|
||||
});
|
||||
|
||||
mapping.from([yInput]).peek().to(function(value) {
|
||||
yvalue = value;
|
||||
var posRot = calculatePositionAndRotation(xvalue, yvalue);
|
||||
Overlays.editOverlay(overlayID, {
|
||||
localPosition: posRot.position,
|
||||
localRotation: posRot.rotation
|
||||
});
|
||||
});
|
||||
})(controller, overlayID, part);
|
||||
|
||||
} else if (part.type === "linear") {
|
||||
(function(controller, overlayID, part) {
|
||||
const input = resolveHardware(part.input);
|
||||
|
||||
mapping.from([input]).peek().to(function(value) {
|
||||
//print(value);
|
||||
var axis = Vec3.multiplyQbyV(controller.rotation, part.axis);
|
||||
var offset = Vec3.multiply(part.maxTranslation * value, axis);
|
||||
|
||||
var partPosition = Vec3.sum(controller.position, Vec3.multiplyQbyV(controller.rotation, part.naturalPosition));
|
||||
var position = Vec3.sum(partPosition, offset);
|
||||
|
||||
Overlays.editOverlay(overlayID, {
|
||||
localPosition: position
|
||||
});
|
||||
});
|
||||
|
||||
})(controller, overlayID, part);
|
||||
|
||||
} else if (part.type === "static") {
|
||||
// do nothing
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
Script.include("controllerDisplay.js");
|
||||
Script.include("viveControllerConfiguration.js");
|
||||
Script.include("touchControllerConfiguration.js");
|
||||
|
||||
var HIDE_CONTROLLERS_ON_EQUIP = false;
|
||||
|
||||
|
@ -41,12 +42,28 @@ ControllerDisplayManager = function() {
|
|||
|
||||
function updateControllers() {
|
||||
if (HMD.active && HMD.shouldShowHandControllers()) {
|
||||
var leftConfig = null;
|
||||
var rightConfig = null;
|
||||
|
||||
if ("Vive" in Controller.Hardware) {
|
||||
if (!controllerLeft) {
|
||||
controllerLeft = createControllerDisplay(VIVE_CONTROLLER_CONFIGURATION_LEFT);
|
||||
leftConfig = VIVE_CONTROLLER_CONFIGURATION_LEFT;
|
||||
rightConfig = VIVE_CONTROLLER_CONFIGURATION_RIGHT;
|
||||
}
|
||||
|
||||
if ("OculusTouch" in Controller.Hardware) {
|
||||
leftConfig = TOUCH_CONTROLLER_CONFIGURATION_LEFT;
|
||||
rightConfig = TOUCH_CONTROLLER_CONFIGURATION_RIGHT;
|
||||
}
|
||||
|
||||
if (leftConfig !== null && rightConfig !== null) {
|
||||
print("Loading controllers");
|
||||
if (controllerLeft === null) {
|
||||
controllerLeft = createControllerDisplay(leftConfig);
|
||||
controllerLeft.setVisible(true);
|
||||
}
|
||||
if (!controllerRight) {
|
||||
controllerRight = createControllerDisplay(VIVE_CONTROLLER_CONFIGURATION_RIGHT);
|
||||
if (controllerRight === null) {
|
||||
controllerRight = createControllerDisplay(rightConfig);
|
||||
controllerRight.setVisible(true);
|
||||
}
|
||||
// We've found the controllers, we no longer need to look for active controllers
|
||||
if (controllerCheckerIntervalID) {
|
||||
|
|
353
scripts/system/controllers/touchControllerConfiguration.js
Normal file
353
scripts/system/controllers/touchControllerConfiguration.js
Normal file
|
@ -0,0 +1,353 @@
|
|||
|
||||
//
|
||||
// touchControllerConfiguration.js
|
||||
//
|
||||
// Created by Ryan Huffman on 12/06/16
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* globals TOUCH_CONTROLLER_CONFIGURATION_LEFT:true TOUCH_CONTROLLER_CONFIGURATION_RIGHT:true */
|
||||
/* eslint camelcase: ["error", { "properties": "never" }] */
|
||||
|
||||
var leftBaseRotation = Quat.multiply(
|
||||
Quat.fromPitchYawRollDegrees(-90, 0, 0),
|
||||
Quat.fromPitchYawRollDegrees(0, 0, 90)
|
||||
);
|
||||
var rightBaseRotation = Quat.multiply(
|
||||
Quat.fromPitchYawRollDegrees(-90, 0, 0),
|
||||
Quat.fromPitchYawRollDegrees(0, 0, -90)
|
||||
);
|
||||
|
||||
// keep these in sync with the values from OculusHelpers.cpp
|
||||
var CONTROLLER_LENGTH_OFFSET = 0.0762;
|
||||
var CONTROLLER_LATERAL_OFFSET = 0.0381;
|
||||
var CONTROLLER_VERTICAL_OFFSET = 0.0381;
|
||||
var CONTROLLER_FORWARD_OFFSET = 0.1524;
|
||||
|
||||
var leftBasePosition = Vec3.multiplyQbyV(leftBaseRotation, {
|
||||
x: -CONTROLLER_LENGTH_OFFSET / 2.0,
|
||||
y: CONTROLLER_LENGTH_OFFSET / 2.0,
|
||||
z: CONTROLLER_LENGTH_OFFSET * 1.5
|
||||
});
|
||||
var rightBasePosition = Vec3.multiplyQbyV(rightBaseRotation, {
|
||||
x: CONTROLLER_LENGTH_OFFSET / 2.0,
|
||||
y: CONTROLLER_LENGTH_OFFSET / 2.0,
|
||||
z: CONTROLLER_LENGTH_OFFSET * 1.5
|
||||
});
|
||||
|
||||
var BASE_URL = Script.resourcesPath() + "meshes/controller/touch/";
|
||||
|
||||
TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||
name: "Touch",
|
||||
controllers: [
|
||||
{
|
||||
modelURL: BASE_URL + "touch_l_body.fbx",
|
||||
jointIndex: MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND"),
|
||||
naturalPosition: { x: 0.01648625358939171, y: -0.03551870584487915, z: -0.018527675420045853 },
|
||||
dimensions: { x: 0.11053799837827682, y: 0.0995776429772377, z: 0.10139888525009155 },
|
||||
rotation: leftBaseRotation,
|
||||
position: leftBasePosition,
|
||||
|
||||
parts: {
|
||||
tips: {
|
||||
type: "static",
|
||||
modelURL: BASE_URL + "Oculus-Labels-L.fbx",
|
||||
naturalPosition: { x: -0.022335469722747803, y: 0.00022516027092933655, z: 0.020340695977211 },
|
||||
|
||||
textureName: "blank",
|
||||
defaultTextureLayer: "blank",
|
||||
textureLayers: {
|
||||
blank: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Blank.png"
|
||||
},
|
||||
trigger: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Trigger.png"
|
||||
},
|
||||
arrows: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Rotate.png"
|
||||
},
|
||||
grip: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Grip-oculus.png"
|
||||
},
|
||||
teleport: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-L.fbx/Oculus-Labels-L.fbm/Teleport.png"
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
trigger: {
|
||||
type: "rotational",
|
||||
modelURL: BASE_URL + "touch_l_trigger.fbx",
|
||||
naturalPosition: { x: 0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 },
|
||||
|
||||
// rotational
|
||||
input: Controller.Standard.LT,
|
||||
origin: { x: 0, y: -0.015, z: -0.00 },
|
||||
minValue: 0.0,
|
||||
maxValue: 1.0,
|
||||
axis: { x: 1, y: 0, z: 0 },
|
||||
maxAngle: 17,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_trigger.fbx/touch_l_trigger.fbm/L_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_trigger.fbx/touch_l_trigger.fbm/L_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
grip: {
|
||||
type: "linear",
|
||||
modelURL: BASE_URL + "touch_l_bumper.fbx",
|
||||
naturalPosition: { x: 0.00008066371083259583, y: -0.02715788595378399, z: -0.02448512241244316 },
|
||||
|
||||
// linear properties
|
||||
// Offset from origin = 0.36470, 0.11048, 0.11066
|
||||
input: "OculusTouch.LeftGrip",
|
||||
axis: { x: 1, y: 0.302933918, z: 0.302933918 },
|
||||
maxTranslation: 0.003967,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_bumper.fbx/touch_l_bumper.fbm/L_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_bumper.fbx/touch_l_bumper.fbm/L_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
joystick: {
|
||||
type: "joystick",
|
||||
modelURL: BASE_URL + "touch_l_joystick.fbx",
|
||||
naturalPosition: { x: 0.0075613949447870255, y: -0.008225866593420506, z: 0.004792703315615654 },
|
||||
|
||||
// joystick
|
||||
xInput: "OculusTouch.LX",
|
||||
yInput: "OculusTouch.LY",
|
||||
originOffset: { x: 0, y: -0.0028564, z: -0.00 },
|
||||
xHalfAngle: 20,
|
||||
yHalfAngle: 20,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_joystick.fbx/touch_l_joystick.fbm/L_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_joystick.fbx/touch_l_joystick.fbm/L_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
button_a: {
|
||||
type: "linear",
|
||||
modelURL: BASE_URL + "touch_l_button_x.fbx",
|
||||
naturalPosition: { x: -0.009307309985160828, y: -0.00005015172064304352, z: -0.012594521045684814 },
|
||||
|
||||
input: "OculusTouch.X",
|
||||
axis: { x: 0, y: -1, z: 0 },
|
||||
maxTranslation: 0.001,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_button_x.fbx/touch_l_button_x.fbm/L_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_button_x.fbx/touch_l_button_x.fbm/L_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
button_b: {
|
||||
type: "linear",
|
||||
modelURL: BASE_URL + "touch_l_button_y.fbx",
|
||||
naturalPosition: { x: -0.01616849936544895, y: -0.000050364527851343155, z: 0.0017703399062156677 },
|
||||
|
||||
input: "OculusTouch.Y",
|
||||
axis: { x: 0, y: -1, z: 0 },
|
||||
maxTranslation: 0.001,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_button_y.fbx/touch_l_button_y.fbm/L_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_l_button_y.fbx/touch_l_button_y.fbm/L_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||
name: "Touch",
|
||||
controllers: [
|
||||
{
|
||||
modelURL: BASE_URL + "touch_r_body.fbx",
|
||||
jointIndex: MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND"),
|
||||
naturalPosition: { x: -0.016486231237649918, y: -0.03551865369081497, z: -0.018527653068304062 },
|
||||
dimensions: { x: 0.11053784191608429, y: 0.09957750141620636, z: 0.10139875113964081 },
|
||||
rotation: rightBaseRotation,
|
||||
position: rightBasePosition,
|
||||
|
||||
parts: {
|
||||
tips: {
|
||||
type: "static",
|
||||
modelURL: BASE_URL + "Oculus-Labels-R.fbx",
|
||||
naturalPosition: { x: 0.009739525616168976, y: -0.0017818436026573181, z: 0.016794726252555847 },
|
||||
|
||||
textureName: "Texture",
|
||||
defaultTextureLayer: "blank",
|
||||
textureLayers: {
|
||||
blank: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Blank.png"
|
||||
},
|
||||
trigger: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Trigger.png"
|
||||
},
|
||||
arrows: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Rotate.png"
|
||||
},
|
||||
grip: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Grip-oculus.png"
|
||||
},
|
||||
teleport: {
|
||||
defaultTextureURL: BASE_URL + "Oculus-Labels-R.fbx/Oculus-Labels-R.fbm/Teleport.png"
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
trigger: {
|
||||
type: "rotational",
|
||||
modelURL: BASE_URL + "touch_r_trigger.fbx",
|
||||
naturalPosition: { x: -0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 },
|
||||
|
||||
// rotational
|
||||
input: "OculusTouch.RT",
|
||||
origin: { x: 0, y: -0.015, z: 0 },
|
||||
minValue: 0.0,
|
||||
maxValue: 1.0,
|
||||
axis: { x: 1, y: 0, z: 0 },
|
||||
maxAngle: 17,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_trigger.fbx/touch_r_trigger.fbm/R_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_trigger.fbx/touch_r_trigger.fbm/R_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
grip: {
|
||||
type: "linear",
|
||||
modelURL: BASE_URL + "touch_r_bumper.fbx",
|
||||
naturalPosition: { x: -0.0000806618481874466, y: -0.027157839387655258, z: -0.024485092610120773 },
|
||||
|
||||
// linear properties
|
||||
// Offset from origin = 0.36470, 0.11048, 0.11066
|
||||
input: "OculusTouch.RightGrip",
|
||||
axis: { x: -1, y: 0.302933918, z: 0.302933918 },
|
||||
maxTranslation: 0.003967,
|
||||
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_bumper.fbx/touch_r_bumper.fbm/R_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_bumper.fbx/touch_r_bumper.fbm/R_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
joystick: {
|
||||
type: "joystick",
|
||||
modelURL: BASE_URL + "touch_r_joystick.fbx",
|
||||
naturalPosition: { x: -0.007561382371932268, y: -0.008225853554904461, z: 0.00479268841445446 },
|
||||
|
||||
// joystick
|
||||
xInput: "OculusTouch.RX",
|
||||
yInput: "OculusTouch.RY",
|
||||
originOffset: { x: 0, y: -0.0028564, z: 0 },
|
||||
xHalfAngle: 20,
|
||||
yHalfAngle: 20,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_joystick.fbx/touch_r_joystick.fbm/R_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_joystick.fbx/touch_r_joystick.fbm/R_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
button_a: {
|
||||
type: "linear",
|
||||
modelURL: BASE_URL + "touch_r_button_a.fbx",
|
||||
naturalPosition: { x: 0.009307296946644783, y: -0.00005015172064304352, z: -0.012594504281878471 },
|
||||
|
||||
input: "OculusTouch.A",
|
||||
axis: { x: 0, y: -1, z: 0 },
|
||||
maxTranslation: 0.001,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_button_a.fbx/touch_r_button_a.fbm/R_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_button_a.fbx/touch_r_button_a.fbm/R_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
button_b: {
|
||||
type: "linear",
|
||||
modelURL: BASE_URL + "touch_r_button_b.fbx",
|
||||
naturalPosition: { x: 0.01616847701370716, y: -0.000050364527851343155, z: 0.0017703361809253693 },
|
||||
|
||||
input: "OculusTouch.B",
|
||||
axis: { x: 0, y: -1, z: 0 },
|
||||
maxTranslation: 0.001,
|
||||
|
||||
textureName: "tex-highlight",
|
||||
defaultTextureLayer: "normal",
|
||||
textureLayers: {
|
||||
normal: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_button_b.fbx/touch_r_button_b.fbm/R_controller_DIF.jpg",
|
||||
},
|
||||
highlight: {
|
||||
defaultTextureURL: BASE_URL + "touch_r_button_b.fbx/touch_r_button_b.fbm/R_controller-highlight_DIF.jpg",
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
|
@ -83,7 +83,6 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
|||
naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323},
|
||||
|
||||
textureName: "Tex.Blank",
|
||||
|
||||
defaultTextureLayer: "blank",
|
||||
textureLayers: {
|
||||
blank: {
|
||||
|
|
|
@ -58,11 +58,6 @@ function info() {
|
|||
}
|
||||
}
|
||||
|
||||
// Return a number between min (inclusive) and max (exclusive)
|
||||
function randomInt(min, max) {
|
||||
return min + Math.floor(Math.random() * (max - min))
|
||||
}
|
||||
|
||||
var NEAR_BOX_SPAWN_NAME = "tutorial/nearGrab/box_spawn";
|
||||
var FAR_BOX_SPAWN_NAME = "tutorial/farGrab/box_spawn";
|
||||
var GUN_SPAWN_NAME = "tutorial/gun_spawn";
|
||||
|
@ -78,10 +73,6 @@ function setAwayEnabled(value) {
|
|||
Messages.sendLocalMessage(CHANNEL_AWAY_ENABLE, message);
|
||||
}
|
||||
|
||||
function beginsWithFilter(value, key) {
|
||||
return value.indexOf(properties[key]) == 0;
|
||||
}
|
||||
|
||||
findEntity = function(properties, searchRadius, filterFn) {
|
||||
var entities = findEntities(properties, searchRadius, filterFn);
|
||||
return entities.length > 0 ? entities[0] : null;
|
||||
|
@ -116,32 +107,30 @@ findEntities = function(properties, searchRadius, filterFn) {
|
|||
return matchedEntities;
|
||||
}
|
||||
|
||||
function setControllerPartsVisible(parts) {
|
||||
Messages.sendLocalMessage('Controller-Display-Parts', JSON.stringify(parts));
|
||||
function findEntitiesWithTag(tag) {
|
||||
return findEntities({ userData: "" }, 10000, function(properties, key, value) {
|
||||
data = parseJSON(value);
|
||||
return data.tag === tag;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A controller in made up of parts, and each part can have multiple "layers,"
|
||||
* which are really just different texures. For example, the "trigger" part
|
||||
* has "normal" and "highlight" layers.
|
||||
*/
|
||||
function setControllerPartLayer(part, layer) {
|
||||
data = {};
|
||||
data[part] = layer;
|
||||
Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data));
|
||||
}
|
||||
|
||||
function triggerHapticPulse() {
|
||||
function scheduleHaptics(delay, strength, duration) {
|
||||
Script.setTimeout(function() {
|
||||
Controller.triggerHapticPulse(strength, duration, 0);
|
||||
Controller.triggerHapticPulse(strength, duration, 1);
|
||||
}, delay);
|
||||
}
|
||||
scheduleHaptics(0, 0.8, 100);
|
||||
scheduleHaptics(300, 0.5, 100);
|
||||
scheduleHaptics(600, 0.3, 100);
|
||||
scheduleHaptics(900, 0.2, 100);
|
||||
scheduleHaptics(1200, 0.1, 100);
|
||||
}
|
||||
|
||||
function spawn(entityData, transform, modifyFn) {
|
||||
debug("Creating: ", entityData);
|
||||
/**
|
||||
* Spawn entities and return the newly created entity's ids.
|
||||
* @param {object[]} entityPropertiesList A list of properties of the entities
|
||||
* to spawn.
|
||||
*/
|
||||
function spawn(entityPropertiesList, transform, modifyFn) {
|
||||
if (!transform) {
|
||||
transform = {
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
|
@ -149,9 +138,8 @@ function spawn(entityData, transform, modifyFn) {
|
|||
}
|
||||
}
|
||||
var ids = [];
|
||||
for (var i = 0; i < entityData.length; ++i) {
|
||||
var data = entityData[i];
|
||||
debug("Creating: ", data.name);
|
||||
for (var i = 0; i < entityPropertiesList.length; ++i) {
|
||||
var data = entityPropertiesList[i];
|
||||
data.position = Vec3.sum(transform.position, data.position);
|
||||
data.rotation = Quat.multiply(data.rotation, transform.rotation);
|
||||
if (modifyFn) {
|
||||
|
@ -159,11 +147,16 @@ function spawn(entityData, transform, modifyFn) {
|
|||
}
|
||||
var id = Entities.addEntity(data);
|
||||
ids.push(id);
|
||||
debug(id, "data:", JSON.stringify(data));
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @function parseJSON
|
||||
* @param {string} jsonString The string to parse.
|
||||
* @return {object} Return an empty if the string was not valid JSON, otherwise
|
||||
* the parsed object is returned.
|
||||
*/
|
||||
function parseJSON(jsonString) {
|
||||
var data;
|
||||
try {
|
||||
|
@ -174,6 +167,10 @@ function parseJSON(jsonString) {
|
|||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spawn entities with `tag` in the userData.
|
||||
* @function spawnWithTag
|
||||
*/
|
||||
function spawnWithTag(entityData, transform, tag) {
|
||||
function modifyFn(data) {
|
||||
var userData = parseJSON(data.userData);
|
||||
|
@ -185,6 +182,10 @@ function spawnWithTag(entityData, transform, tag) {
|
|||
return spawn(entityData, transform, modifyFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all entities with the tag `tag` in their userData.
|
||||
* @function deleteEntitiesWithTag
|
||||
*/
|
||||
function deleteEntitiesWithTag(tag) {
|
||||
debug("searching for...:", tag);
|
||||
var entityIDs = findEntitiesWithTag(tag);
|
||||
|
@ -192,6 +193,7 @@ function deleteEntitiesWithTag(tag) {
|
|||
Entities.deleteEntity(entityIDs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function editEntitiesWithTag(tag, propertiesOrFn) {
|
||||
var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];
|
||||
|
||||
|
@ -208,19 +210,130 @@ function editEntitiesWithTag(tag, propertiesOrFn) {
|
|||
}
|
||||
}
|
||||
|
||||
function findEntitiesWithTag(tag) {
|
||||
return findEntities({ userData: "" }, 10000, function(properties, key, value) {
|
||||
data = parseJSON(value);
|
||||
return data.tag == tag;
|
||||
});
|
||||
}
|
||||
|
||||
// From http://stackoverflow.com/questions/5999998/how-can-i-check-if-a-javascript-variable-is-function-type
|
||||
function isFunction(functionToCheck) {
|
||||
var getType = {};
|
||||
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return `true` if `entityID` can be found in the local entity tree, otherwise `false`.
|
||||
*/
|
||||
function isEntityInLocalTree(entityID) {
|
||||
return Entities.getEntityProperties(entityID, 'visible').visible !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function showEntitiesWithTags(tags) {
|
||||
for (var i = 0; i < tags.length; ++i) {
|
||||
showEntitiesWithTag(tags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function showEntitiesWithTag(tag) {
|
||||
var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];
|
||||
if (entities) {
|
||||
for (entityID in entities) {
|
||||
var data = entities[entityID];
|
||||
|
||||
var collisionless = data.visible === false ? true : false;
|
||||
if (data.collidable !== undefined) {
|
||||
collisionless = data.collidable === true ? false : true;
|
||||
}
|
||||
if (data.soundKey) {
|
||||
data.soundKey.playing = true;
|
||||
}
|
||||
var newProperties = {
|
||||
visible: data.visible == false ? false : true,
|
||||
collisionless: collisionless,
|
||||
userData: JSON.stringify(data),
|
||||
};
|
||||
debug("Showing: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
} else {
|
||||
debug("ERROR | No entities for tag: ", tag);
|
||||
}
|
||||
|
||||
return;
|
||||
// Dynamic method, suppressed for now
|
||||
//editEntitiesWithTag(tag, function(entityID) {
|
||||
// var userData = Entities.getEntityProperties(entityID, "userData").userData;
|
||||
// var data = parseJSON(userData);
|
||||
// var collisionless = data.visible === false ? true : false;
|
||||
// if (data.collidable !== undefined) {
|
||||
// collisionless = data.collidable === true ? false : true;
|
||||
// }
|
||||
// if (data.soundKey) {
|
||||
// data.soundKey.playing = true;
|
||||
// }
|
||||
// var newProperties = {
|
||||
// visible: data.visible == false ? false : true,
|
||||
// collisionless: collisionless,
|
||||
// userData: JSON.stringify(data),
|
||||
// };
|
||||
// Entities.editEntity(entityID, newProperties);
|
||||
//});
|
||||
}
|
||||
|
||||
function hideEntitiesWithTags(tags) {
|
||||
for (var i = 0; i < tags.length; ++i) {
|
||||
hideEntitiesWithTag(tags[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function hideEntitiesWithTag(tag) {
|
||||
var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];
|
||||
if (entities) {
|
||||
for (entityID in entities) {
|
||||
var data = entities[entityID];
|
||||
|
||||
if (data.soundKey) {
|
||||
data.soundKey.playing = false;
|
||||
}
|
||||
var newProperties = {
|
||||
visible: false,
|
||||
collisionless: 1,
|
||||
ignoreForCollisions: 1,
|
||||
userData: JSON.stringify(data),
|
||||
};
|
||||
|
||||
debug("Hiding: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
// Dynamic method, suppressed for now
|
||||
//editEntitiesWithTag(tag, function(entityID) {
|
||||
// var userData = Entities.getEntityProperties(entityID, "userData").userData;
|
||||
// var data = parseJSON(userData);
|
||||
// if (data.soundKey) {
|
||||
// data.soundKey.playing = false;
|
||||
// }
|
||||
// var newProperties = {
|
||||
// visible: false,
|
||||
// collisionless: 1,
|
||||
// ignoreForCollisions: 1,
|
||||
// userData: JSON.stringify(data),
|
||||
// };
|
||||
// Entities.editEntity(entityID, newProperties);
|
||||
//});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the entity properties for an entity with a given name if it is in our
|
||||
* cached list of entities. Otherwise, return undefined.
|
||||
*/
|
||||
function getEntityWithName(name) {
|
||||
debug("Getting entity with name:", name);
|
||||
var entityID = TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP[name];
|
||||
debug("Entity id: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));
|
||||
return entityID;
|
||||
}
|
||||
|
||||
function playSuccessSound() {
|
||||
Audio.playSound(successSound, {
|
||||
position: MyAvatar.position,
|
||||
|
@ -229,7 +342,6 @@ function playSuccessSound() {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
function playFirecrackerSound(position) {
|
||||
Audio.playSound(firecrackerSound, {
|
||||
position: position,
|
||||
|
@ -238,27 +350,17 @@ function playFirecrackerSound(position) {
|
|||
});
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// STEP: DISABLE CONTROLLERS //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepStart = function(name) {
|
||||
this.tag = name;
|
||||
}
|
||||
stepStart.prototype = {
|
||||
start: function(onFinish) {
|
||||
disableEverything();
|
||||
|
||||
HMD.requestShowHandControllers();
|
||||
|
||||
onFinish();
|
||||
},
|
||||
cleanup: function() {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This disables everything, including:
|
||||
*
|
||||
* - The door to leave the tutorial
|
||||
* - Overlays
|
||||
* - Hand controlelrs
|
||||
* - Teleportation
|
||||
* - Advanced movement
|
||||
* - Equip and far grab
|
||||
* - Away mode
|
||||
*/
|
||||
function disableEverything() {
|
||||
editEntitiesWithTag('door', { visible: true, collisionless: false });
|
||||
Menu.setIsOptionChecked("Overlays", false);
|
||||
|
@ -271,6 +373,11 @@ function disableEverything() {
|
|||
farGrabEnabled: false,
|
||||
}));
|
||||
setControllerPartLayer('touchpad', 'blank');
|
||||
setControllerPartLayer('trigger', 'blank');
|
||||
setControllerPartLayer('joystick', 'blank');
|
||||
setControllerPartLayer('grip', 'blank');
|
||||
setControllerPartLayer('button_a', 'blank');
|
||||
setControllerPartLayer('button_b', 'blank');
|
||||
setControllerPartLayer('tips', 'blank');
|
||||
|
||||
hideEntitiesWithTag('finish');
|
||||
|
@ -278,6 +385,10 @@ function disableEverything() {
|
|||
setAwayEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* This reenables everything that disableEverything() disables. This can be
|
||||
* used when leaving the tutorial to ensure that nothing is left disabled.
|
||||
*/
|
||||
function reenableEverything() {
|
||||
editEntitiesWithTag('door', { visible: false, collisionless: true });
|
||||
Menu.setIsOptionChecked("Overlays", true);
|
||||
|
@ -290,11 +401,39 @@ function reenableEverything() {
|
|||
farGrabEnabled: true,
|
||||
}));
|
||||
setControllerPartLayer('touchpad', 'blank');
|
||||
setControllerPartLayer('trigger', 'blank');
|
||||
setControllerPartLayer('joystick', 'blank');
|
||||
setControllerPartLayer('grip', 'blank');
|
||||
setControllerPartLayer('button_a', 'blank');
|
||||
setControllerPartLayer('button_b', 'blank');
|
||||
setControllerPartLayer('tips', 'blank');
|
||||
MyAvatar.shouldRenderLocally = true;
|
||||
setAwayEnabled(true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// STEP: DISABLE CONTROLLERS //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepStart = function() {
|
||||
this.name = 'start';
|
||||
};
|
||||
stepStart.prototype = {
|
||||
start: function(onFinish) {
|
||||
disableEverything();
|
||||
|
||||
HMD.requestShowHandControllers();
|
||||
|
||||
onFinish();
|
||||
},
|
||||
cleanup: function() {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
|
@ -302,10 +441,9 @@ function reenableEverything() {
|
|||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var stepEnableControllers = function(name) {
|
||||
this.tag = name;
|
||||
var stepEnableControllers = function() {
|
||||
this.shouldLog = false;
|
||||
}
|
||||
};
|
||||
stepEnableControllers.prototype = {
|
||||
start: function(onFinish) {
|
||||
reenableEverything();
|
||||
|
@ -316,28 +454,6 @@ stepEnableControllers.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// STEP: Welcome //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepWelcome = function(name) {
|
||||
this.tag = name;
|
||||
}
|
||||
stepWelcome.prototype = {
|
||||
start: function(onFinish) {
|
||||
this.timerID = Script.setTimeout(onFinish, 8000);
|
||||
showEntitiesWithTag(this.tag);
|
||||
},
|
||||
cleanup: function() {
|
||||
if (this.timerID) {
|
||||
Script.clearTimeout(this.timerID);
|
||||
this.timerID = null;
|
||||
}
|
||||
hideEntitiesWithTag(this.tag);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -346,9 +462,9 @@ stepWelcome.prototype = {
|
|||
// STEP: Orient and raise hands above head //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepOrient = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepOrient = function(tutorialManager) {
|
||||
this.name = 'orient';
|
||||
this.tags = ["orient", "orient-" + tutorialManager.controllerName];
|
||||
}
|
||||
stepOrient.prototype = {
|
||||
start: function(onFinish) {
|
||||
|
@ -357,7 +473,8 @@ stepOrient.prototype = {
|
|||
var tag = this.tag;
|
||||
|
||||
// Spawn content set
|
||||
editEntitiesWithTag(this.tag, { visible: true });
|
||||
//editEntitiesWithTag(this.tag, { visible: true });
|
||||
showEntitiesWithTags(this.tags);
|
||||
|
||||
this.checkIntervalID = null;
|
||||
function checkForHandsAboveHead() {
|
||||
|
@ -386,8 +503,8 @@ stepOrient.prototype = {
|
|||
Script.clearInterval(this.checkIntervalID);
|
||||
this.checkIntervalID = null;
|
||||
}
|
||||
editEntitiesWithTag(this.tag, { visible: false, collisionless: 1 });
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
//editEntitiesWithTag(this.tag, { visible: false, collisionless: 1 });
|
||||
hideEntitiesWithTags(this.tags);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -399,9 +516,10 @@ stepOrient.prototype = {
|
|||
// STEP: Near Grab //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepNearGrab = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepNearGrab = function() {
|
||||
this.name = 'nearGrab';
|
||||
this.tag = "nearGrab";
|
||||
this.tempTag = "nearGrab-temporary";
|
||||
this.birdIDs = [];
|
||||
|
||||
Messages.subscribe("Entity-Exploded");
|
||||
|
@ -414,7 +532,6 @@ stepNearGrab.prototype = {
|
|||
|
||||
setControllerPartLayer('tips', 'trigger');
|
||||
setControllerPartLayer('trigger', 'highlight');
|
||||
var tag = this.tag;
|
||||
|
||||
// Spawn content set
|
||||
showEntitiesWithTag(this.tag, { visible: true });
|
||||
|
@ -457,6 +574,7 @@ stepNearGrab.prototype = {
|
|||
setControllerPartLayer('tips', 'blank');
|
||||
setControllerPartLayer('trigger', 'normal');
|
||||
hideEntitiesWithTag(this.tag, { visible: false});
|
||||
hideEntitiesWithTag('bothGrab', { visible: false});
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
if (this.positionWatcher) {
|
||||
this.positionWatcher.destroy();
|
||||
|
@ -473,9 +591,10 @@ stepNearGrab.prototype = {
|
|||
// STEP: Far Grab //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepFarGrab = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepFarGrab = function() {
|
||||
this.name = 'farGrab';
|
||||
this.tag = "farGrab";
|
||||
this.tempTag = "farGrab-temporary";
|
||||
this.finished = true;
|
||||
this.birdIDs = [];
|
||||
|
||||
|
@ -535,7 +654,6 @@ stepFarGrab.prototype = {
|
|||
setControllerPartLayer('tips', 'blank');
|
||||
setControllerPartLayer('trigger', 'normal');
|
||||
hideEntitiesWithTag(this.tag, { visible: false});
|
||||
hideEntitiesWithTag('bothGrab', { visible: false});
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
if (this.positionWatcher) {
|
||||
this.positionWatcher.destroy();
|
||||
|
@ -576,11 +694,16 @@ PositionWatcher.prototype = {
|
|||
// STEP: Equip //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepEquip = function(name) {
|
||||
this.tag = name;
|
||||
this.tagPart1 = name + "-part1";
|
||||
this.tagPart2 = name + "-part2";
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepEquip = function(tutorialManager) {
|
||||
const controllerName = tutorialManager.controllerName;
|
||||
|
||||
this.name = 'equip';
|
||||
|
||||
this.tags = ["equip", "equip-" + controllerName];
|
||||
this.tagsPart1 = ["equip-part1", "equip-part1-" + controllerName];
|
||||
this.tagsPart2 = ["equip-part2", "equip-part2-" + controllerName];
|
||||
this.tempTag = "equip-temporary";
|
||||
|
||||
this.PART1 = 0;
|
||||
this.PART2 = 1;
|
||||
this.PART3 = 2;
|
||||
|
@ -593,6 +716,7 @@ stepEquip.prototype = {
|
|||
start: function(onFinish) {
|
||||
setControllerPartLayer('tips', 'trigger');
|
||||
setControllerPartLayer('trigger', 'highlight');
|
||||
|
||||
Messages.sendLocalMessage('Hifi-Grab-Disable', JSON.stringify({
|
||||
holdEnabled: true,
|
||||
}));
|
||||
|
@ -600,8 +724,8 @@ stepEquip.prototype = {
|
|||
var tag = this.tag;
|
||||
|
||||
// Spawn content set
|
||||
showEntitiesWithTag(this.tag);
|
||||
showEntitiesWithTag(this.tagPart1);
|
||||
showEntitiesWithTags(this.tags);
|
||||
showEntitiesWithTags(this.tagsPart1);
|
||||
|
||||
this.currentPart = this.PART1;
|
||||
|
||||
|
@ -658,9 +782,10 @@ stepEquip.prototype = {
|
|||
Script.setTimeout(function() {
|
||||
debug("Equip | Starting part 3");
|
||||
this.currentPart = this.PART3;
|
||||
hideEntitiesWithTag(this.tagPart1);
|
||||
showEntitiesWithTag(this.tagPart2);
|
||||
hideEntitiesWithTags(this.tagsPart1);
|
||||
showEntitiesWithTags(this.tagsPart2);
|
||||
setControllerPartLayer('trigger', 'normal');
|
||||
setControllerPartLayer('grip', 'highlight');
|
||||
setControllerPartLayer('tips', 'grip');
|
||||
Messages.subscribe('Hifi-Object-Manipulation');
|
||||
debug("Equip | Finished starting part 3");
|
||||
|
@ -687,16 +812,19 @@ stepEquip.prototype = {
|
|||
}
|
||||
|
||||
setControllerPartLayer('tips', 'blank');
|
||||
setControllerPartLayer('grip', 'normal');
|
||||
setControllerPartLayer('trigger', 'normal');
|
||||
this.stopWatchingGun();
|
||||
this.currentPart = this.COMPLETE;
|
||||
|
||||
if (this.checkCollidesTimer) {
|
||||
Script.clearInterval(this.checkCollidesTimer);
|
||||
this.checkColllidesTimer = null;
|
||||
}
|
||||
hideEntitiesWithTag(this.tagPart1);
|
||||
hideEntitiesWithTag(this.tagPart2);
|
||||
hideEntitiesWithTag(this.tag);
|
||||
|
||||
hideEntitiesWithTags(this.tagsPart1);
|
||||
hideEntitiesWithTags(this.tagsPart2);
|
||||
hideEntitiesWithTags(this.tags);
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
}
|
||||
};
|
||||
|
@ -710,9 +838,11 @@ stepEquip.prototype = {
|
|||
// STEP: Turn Around //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepTurnAround = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepTurnAround = function(tutorialManager) {
|
||||
this.name = 'turnAround';
|
||||
|
||||
this.tags = ["turnAround", "turnAround-" + tutorialManager.controllerName];
|
||||
this.tempTag = "turnAround-temporary";
|
||||
|
||||
this.onActionBound = this.onAction.bind(this);
|
||||
this.numTimesSnapTurnPressed = 0;
|
||||
|
@ -720,10 +850,11 @@ var stepTurnAround = function(name) {
|
|||
}
|
||||
stepTurnAround.prototype = {
|
||||
start: function(onFinish) {
|
||||
setControllerPartLayer('joystick', 'highlight');
|
||||
setControllerPartLayer('touchpad', 'arrows');
|
||||
setControllerPartLayer('tips', 'arrows');
|
||||
|
||||
showEntitiesWithTag(this.tag);
|
||||
showEntitiesWithTags(this.tags);
|
||||
|
||||
this.numTimesSnapTurnPressed = 0;
|
||||
this.numTimesSmoothTurnPressed = 0;
|
||||
|
@ -776,13 +907,14 @@ stepTurnAround.prototype = {
|
|||
} catch (e) {
|
||||
}
|
||||
|
||||
setControllerPartLayer('joystick', 'normal');
|
||||
setControllerPartLayer('touchpad', 'blank');
|
||||
setControllerPartLayer('tips', 'blank');
|
||||
|
||||
if (this.interval) {
|
||||
Script.clearInterval(this.interval);
|
||||
}
|
||||
hideEntitiesWithTag(this.tag);
|
||||
hideEntitiesWithTags(this.tags);
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
}
|
||||
};
|
||||
|
@ -796,12 +928,15 @@ stepTurnAround.prototype = {
|
|||
// STEP: Teleport //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepTeleport = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepTeleport = function(tutorialManager) {
|
||||
this.name = 'teleport';
|
||||
|
||||
this.tags = ["teleport", "teleport-" + tutorialManager.controllerName];
|
||||
this.tempTag = "teleport-temporary";
|
||||
}
|
||||
stepTeleport.prototype = {
|
||||
start: function(onFinish) {
|
||||
setControllerPartLayer('button_a', 'highlight');
|
||||
setControllerPartLayer('touchpad', 'teleport');
|
||||
setControllerPartLayer('tips', 'teleport');
|
||||
|
||||
|
@ -831,17 +966,18 @@ stepTeleport.prototype = {
|
|||
}
|
||||
this.checkCollidesTimer = Script.setInterval(checkCollides.bind(this), 500);
|
||||
|
||||
showEntitiesWithTag(this.tag);
|
||||
showEntitiesWithTags(this.tags);
|
||||
},
|
||||
cleanup: function() {
|
||||
debug("Teleport | Cleanup");
|
||||
setControllerPartLayer('button_a', 'normal');
|
||||
setControllerPartLayer('touchpad', 'blank');
|
||||
setControllerPartLayer('tips', 'blank');
|
||||
|
||||
if (this.checkCollidesTimer) {
|
||||
Script.clearInterval(this.checkCollidesTimer);
|
||||
}
|
||||
hideEntitiesWithTag(this.tag);
|
||||
hideEntitiesWithTags(this.tags);
|
||||
deleteEntitiesWithTag(this.tempTag);
|
||||
}
|
||||
};
|
||||
|
@ -856,9 +992,11 @@ stepTeleport.prototype = {
|
|||
// STEP: Finish //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
var stepFinish = function(name) {
|
||||
this.tag = name;
|
||||
this.tempTag = name + "-temporary";
|
||||
var stepFinish = function() {
|
||||
this.name = 'finish';
|
||||
|
||||
this.tag = "finish";
|
||||
this.tempTag = "finish-temporary";
|
||||
}
|
||||
stepFinish.prototype = {
|
||||
start: function(onFinish) {
|
||||
|
@ -872,6 +1010,8 @@ stepFinish.prototype = {
|
|||
};
|
||||
|
||||
var stepCleanupFinish = function() {
|
||||
this.name = 'cleanup';
|
||||
|
||||
this.shouldLog = false;
|
||||
}
|
||||
stepCleanupFinish.prototype = {
|
||||
|
@ -885,101 +1025,6 @@ stepCleanupFinish.prototype = {
|
|||
|
||||
|
||||
|
||||
function isEntityInLocalTree(entityID) {
|
||||
return Entities.getEntityProperties(entityID, 'visible').visible !== undefined;
|
||||
}
|
||||
|
||||
function showEntitiesWithTag(tag) {
|
||||
var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];
|
||||
if (entities) {
|
||||
for (entityID in entities) {
|
||||
var data = entities[entityID];
|
||||
|
||||
var collisionless = data.visible === false ? true : false;
|
||||
if (data.collidable !== undefined) {
|
||||
collisionless = data.collidable === true ? false : true;
|
||||
}
|
||||
if (data.soundKey) {
|
||||
data.soundKey.playing = true;
|
||||
}
|
||||
var newProperties = {
|
||||
visible: data.visible == false ? false : true,
|
||||
collisionless: collisionless,
|
||||
userData: JSON.stringify(data),
|
||||
};
|
||||
debug("Showing: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic method, suppressed for now
|
||||
return;
|
||||
editEntitiesWithTag(tag, function(entityID) {
|
||||
var userData = Entities.getEntityProperties(entityID, "userData").userData;
|
||||
var data = parseJSON(userData);
|
||||
var collisionless = data.visible === false ? true : false;
|
||||
if (data.collidable !== undefined) {
|
||||
collisionless = data.collidable === true ? false : true;
|
||||
}
|
||||
if (data.soundKey) {
|
||||
data.soundKey.playing = true;
|
||||
}
|
||||
var newProperties = {
|
||||
visible: data.visible == false ? false : true,
|
||||
collisionless: collisionless,
|
||||
userData: JSON.stringify(data),
|
||||
};
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
});
|
||||
}
|
||||
|
||||
function hideEntitiesWithTag(tag) {
|
||||
var entities = TUTORIAL_TAG_TO_ENTITY_IDS_MAP[tag];
|
||||
if (entities) {
|
||||
for (entityID in entities) {
|
||||
var data = entities[entityID];
|
||||
|
||||
if (data.soundKey) {
|
||||
data.soundKey.playing = false;
|
||||
}
|
||||
var newProperties = {
|
||||
visible: false,
|
||||
collisionless: 1,
|
||||
ignoreForCollisions: 1,
|
||||
userData: JSON.stringify(data),
|
||||
};
|
||||
|
||||
debug("Hiding: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
}
|
||||
}
|
||||
|
||||
// Dynamic method, suppressed for now
|
||||
return;
|
||||
editEntitiesWithTag(tag, function(entityID) {
|
||||
var userData = Entities.getEntityProperties(entityID, "userData").userData;
|
||||
var data = parseJSON(userData);
|
||||
if (data.soundKey) {
|
||||
data.soundKey.playing = false;
|
||||
}
|
||||
var newProperties = {
|
||||
visible: false,
|
||||
collisionless: 1,
|
||||
ignoreForCollisions: 1,
|
||||
userData: JSON.stringify(data),
|
||||
};
|
||||
Entities.editEntity(entityID, newProperties);
|
||||
});
|
||||
}
|
||||
|
||||
// Return the entity properties for an entity with a given name if it is in our
|
||||
// cached list of entities. Otherwise, return undefined.
|
||||
function getEntityWithName(name) {
|
||||
debug("Getting entity with name:", name);
|
||||
var entityID = TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP[name];
|
||||
debug("Entity id: ", entityID, ", Is in local tree: ", isEntityInLocalTree(entityID));
|
||||
return entityID;
|
||||
}
|
||||
|
||||
|
||||
TutorialManager = function() {
|
||||
|
@ -992,11 +1037,25 @@ TutorialManager = function() {
|
|||
var didFinishTutorial = false;
|
||||
|
||||
var wentToEntryStepNum;
|
||||
var VERSION = 1;
|
||||
var VERSION = 2;
|
||||
var tutorialID;
|
||||
|
||||
var self = this;
|
||||
|
||||
// The real controller name is the actual detected controller name, or 'unknown'
|
||||
// if one is not found.
|
||||
if (HMD.isSubdeviceContainingNameAvailable("OculusTouch")) {
|
||||
this.controllerName = "touch";
|
||||
this.realControllerName = "touch";
|
||||
} else if (HMD.isHandControllerAvailable("OpenVR")) {
|
||||
this.controllerName = "vive";
|
||||
this.realControllerName = "vive";
|
||||
} else {
|
||||
info("ERROR, no known hand controller found, defaulting to Vive");
|
||||
this.controllerName = "vive";
|
||||
this.realControllerName = "unknown";
|
||||
}
|
||||
|
||||
this.startTutorial = function() {
|
||||
currentStepNum = -1;
|
||||
currentStep = null;
|
||||
|
@ -1006,15 +1065,15 @@ TutorialManager = function() {
|
|||
// If Script.generateUUID is not available, default to an empty string.
|
||||
tutorialID = Script.generateUUID ? Script.generateUUID() : "";
|
||||
STEPS = [
|
||||
new stepStart("start"),
|
||||
new stepOrient("orient"),
|
||||
new stepNearGrab("nearGrab"),
|
||||
new stepFarGrab("farGrab"),
|
||||
new stepEquip("equip"),
|
||||
new stepTurnAround("turnAround"),
|
||||
new stepTeleport("teleport"),
|
||||
new stepFinish("finish"),
|
||||
new stepEnableControllers("enableControllers"),
|
||||
new stepStart(this),
|
||||
new stepOrient(this),
|
||||
new stepFarGrab(this),
|
||||
new stepNearGrab(this),
|
||||
new stepEquip(this),
|
||||
new stepTurnAround(this),
|
||||
new stepTeleport(this),
|
||||
new stepFinish(this),
|
||||
new stepEnableControllers(this),
|
||||
];
|
||||
wentToEntryStepNum = STEPS.length;
|
||||
for (var i = 0; i < STEPS.length; ++i) {
|
||||
|
@ -1027,7 +1086,7 @@ TutorialManager = function() {
|
|||
this.onFinish = function() {
|
||||
debug("onFinish", currentStepNum);
|
||||
if (currentStep && currentStep.shouldLog !== false) {
|
||||
self.trackStep(currentStep.tag, currentStepNum);
|
||||
self.trackStep(currentStep.name, currentStepNum);
|
||||
}
|
||||
|
||||
self.startNextStep();
|
||||
|
@ -1083,7 +1142,7 @@ TutorialManager = function() {
|
|||
var tutorialTimeElapsed = (Date.now() - startedTutorialAt) / 1000;
|
||||
UserActivityLogger.tutorialProgress(
|
||||
name, stepNum, timeToFinishStep, tutorialTimeElapsed,
|
||||
tutorialID, VERSION);
|
||||
tutorialID, VERSION, this.realControllerName);
|
||||
}
|
||||
|
||||
// This is a message sent from the "entry" portal in the courtyard,
|
||||
|
@ -1099,6 +1158,25 @@ TutorialManager = function() {
|
|||
|
||||
// To run the tutorial:
|
||||
//
|
||||
// var tutorialManager = new TutorialManager();
|
||||
// tutorialManager.startTutorial();
|
||||
//var tutorialManager = new TutorialManager();
|
||||
//tutorialManager.startTutorial();
|
||||
//
|
||||
//
|
||||
//var keyReleaseHandler = function(event) {
|
||||
// if (event.isShifted && event.isAlt) {
|
||||
// print('here', event.text);
|
||||
// if (event.text == "F12") {
|
||||
// if (!tutorialManager.startNextStep()) {
|
||||
// tutorialManager.startTutorial();
|
||||
// }
|
||||
// } else if (event.text == "F11") {
|
||||
// tutorialManager.restartStep();
|
||||
// } else if (event.text == "F10") {
|
||||
// MyAvatar.shouldRenderLocally = !MyAvatar.shouldRenderLocally;
|
||||
// } else if (event.text == "r") {
|
||||
// tutorialManager.stopTutorial();
|
||||
// tutorialManager.startTutorial();
|
||||
// }
|
||||
// }
|
||||
//};
|
||||
//Controller.keyReleaseEvent.connect(keyReleaseHandler);
|
||||
|
|
|
@ -1,8 +1,25 @@
|
|||
TUTORIAL_TAG_TO_ENTITY_IDS_MAP = {
|
||||
"teleport": {
|
||||
"teleport-vive": {
|
||||
"{7df1abc4-1b7c-4352-985c-f3f6ad8d65b7}": {
|
||||
"tag": "teleport-vive"
|
||||
}
|
||||
},
|
||||
"teleport-touch": {
|
||||
"{ff064b9e-7fa4-4693-a386-a67b9f92a948}": {
|
||||
"tag": "teleport"
|
||||
},
|
||||
"tag": "teleport-touch"
|
||||
}
|
||||
},
|
||||
"turnAround-vive": {
|
||||
"{9b14f224-b2f6-447f-bb86-f5d875cf4c33}": {
|
||||
"tag": "turnAround-vive"
|
||||
}
|
||||
},
|
||||
"turnAround-touch": {
|
||||
"{ce74b3ca-d1c7-4980-bd98-2d488095a39e}": {
|
||||
"tag": "turnAround-touch"
|
||||
}
|
||||
},
|
||||
"teleport": {
|
||||
"{4478f7b5-d3ac-4213-9a7b-ad8cd69575b8}": {
|
||||
"tag": "teleport"
|
||||
}
|
||||
|
@ -82,17 +99,19 @@ TUTORIAL_TAG_TO_ENTITY_IDS_MAP = {
|
|||
"tag": "equip-part1"
|
||||
}
|
||||
},
|
||||
"equip-part2": {
|
||||
"equip-part2-vive": {
|
||||
"{b5d17eda-90ab-40cf-b973-efcecb2e992e}": {
|
||||
"tag": "equip-part2"
|
||||
},
|
||||
"{6307cd16-dd1d-4988-a339-578178436b45}": {
|
||||
"tag": "equip-part2"
|
||||
"tag": "equip-part2-vive"
|
||||
}
|
||||
},
|
||||
"turnAround": {
|
||||
"{ce74b3ca-d1c7-4980-bd98-2d488095a39e}": {
|
||||
"tag": "turnAround"
|
||||
"equip-part2-touch": {
|
||||
"{69195139-e020-4739-bb2c-50faebc6860a}": {
|
||||
"tag": "equip-part2-touch"
|
||||
}
|
||||
},
|
||||
"equip-part2": {
|
||||
"{6307cd16-dd1d-4988-a339-578178436b45}": {
|
||||
"tag": "equip-part2"
|
||||
}
|
||||
},
|
||||
"bothGrab": {
|
||||
|
@ -143,133 +162,144 @@ TUTORIAL_TAG_TO_ENTITY_IDS_MAP = {
|
|||
"tag": "equip"
|
||||
}
|
||||
},
|
||||
"orient": {
|
||||
"orient-vive": {
|
||||
"{95d233ab-ed0a-46e1-b047-1c542688ef3f}": {
|
||||
"tag": "orient"
|
||||
"tag": "orient-vive"
|
||||
}
|
||||
},
|
||||
"orient-touch": {
|
||||
"{1c95f945-ec46-4aac-b0f1-e64e073dbfaa}": {
|
||||
"tag": "orient-touch"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TUTORIAL_NAME_TO_ENTITY_PROPERTIES_MAP = {
|
||||
"tutorial/gun_spawn": {
|
||||
"userData": "{\"tag\":\"equip\",\"visible\":false}",
|
||||
"dimensions": {
|
||||
"y": 0.0649842768907547,
|
||||
"x": 0.0649842768907547,
|
||||
"z": 0.0649842768907547
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"collisionless": 1,
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"color": {
|
||||
"blue": 0,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"queryAACube": {
|
||||
"y": 0.6283726096153259,
|
||||
"x": 0.6865367293357849,
|
||||
"scale": 0.11255607008934021,
|
||||
"z": 0.3359576463699341
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"dimensions": {
|
||||
"x": 0.0649842768907547,
|
||||
"y": 0.0649842768907547,
|
||||
"z": 0.0649842768907547
|
||||
},
|
||||
"visible": 0,
|
||||
"shape": "Cube",
|
||||
"clientOnly": 0,
|
||||
"id": "{9df518da-9e65-4b76-8a79-eeefdb0b7310}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1481926907366120,
|
||||
"lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}",
|
||||
"name": "tutorial/gun_spawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"y": 0.6846506595611572,
|
||||
"x": 0.7428147792816162,
|
||||
"z": 0.3922356963157654
|
||||
"x": 0.60231781005859375,
|
||||
"y": 0.68465065956115723,
|
||||
"z": 0.39223569631576538
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.11255607008934021,
|
||||
"x": 0.54603976011276245,
|
||||
"y": 0.62837260961532593,
|
||||
"z": 0.33595764636993408
|
||||
},
|
||||
"rotation": {
|
||||
"y": 0.7066605091094971,
|
||||
"x": 0.7066605091094971,
|
||||
"z": -0.025131583213806152,
|
||||
"w": -0.025101065635681152
|
||||
"w": -0.025101065635681152,
|
||||
"x": 0.70666050910949707,
|
||||
"y": 0.70666050910949707,
|
||||
"z": -0.025131583213806152
|
||||
},
|
||||
"ignoreForCollisions": 1,
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"id": "{9df518da-9e65-4b76-8a79-eeefdb0b7310}",
|
||||
"name": "tutorial/gun_spawn"
|
||||
"userData": "{\"visible\":false,\"tag\":\"equip\"}",
|
||||
"visible": 0
|
||||
},
|
||||
"tutorial/nearGrab/box_spawn": {
|
||||
"userData": "{\"tag\":\"nearGrab\",\"visible\":false}",
|
||||
"dimensions": {
|
||||
"y": 0.08225371688604355,
|
||||
"x": 0.08225371688604355,
|
||||
"z": 0.08225371688604355
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"collisionless": 1,
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"color": {
|
||||
"blue": 255,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"queryAACube": {
|
||||
"y": 0.738319456577301,
|
||||
"x": 0.8985498547554016,
|
||||
"scale": 0.14246761798858643,
|
||||
"z": 0.29067665338516235
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"dimensions": {
|
||||
"x": 0.082253716886043549,
|
||||
"y": 0.082253716886043549,
|
||||
"z": 0.082253716886043549
|
||||
},
|
||||
"visible": 0,
|
||||
"shape": "Cube",
|
||||
"clientOnly": 0,
|
||||
"id": "{5cf22b9c-fb22-4854-8821-554422980b24}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1481926907334206,
|
||||
"lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}",
|
||||
"name": "tutorial/nearGrab/box_spawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
"y": 0.8095532655715942,
|
||||
"x": 0.9697836637496948,
|
||||
"x": 0.61857688426971436,
|
||||
"y": 0.80955326557159424,
|
||||
"z": 0.36191046237945557
|
||||
},
|
||||
"rotation": {
|
||||
"y": -1.52587890625e-05,
|
||||
"x": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05,
|
||||
"w": 1
|
||||
"queryAACube": {
|
||||
"scale": 0.14246761798858643,
|
||||
"x": 0.54734307527542114,
|
||||
"y": 0.73831945657730103,
|
||||
"z": 0.29067665338516235
|
||||
},
|
||||
"ignoreForCollisions": 1,
|
||||
"rotation": {
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"id": "{5cf22b9c-fb22-4854-8821-554422980b24}",
|
||||
"name": "tutorial/nearGrab/box_spawn"
|
||||
"userData": "{\"visible\":false,\"tag\":\"nearGrab\"}",
|
||||
"visible": 0
|
||||
},
|
||||
"tutorial/farGrab/box_spawn": {
|
||||
"userData": "{\"tag\":\"farGrab\",\"visible\":false}",
|
||||
"dimensions": {
|
||||
"y": 0.37358683347702026,
|
||||
"x": 0.37358683347702026,
|
||||
"z": 0.37358683347702026
|
||||
},
|
||||
"clientOnly": 0,
|
||||
"collisionless": 1,
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"color": {
|
||||
"blue": 255,
|
||||
"green": 0,
|
||||
"red": 255
|
||||
},
|
||||
"queryAACube": {
|
||||
"y": 0.3304251432418823,
|
||||
"x": 3.0951309204101562,
|
||||
"scale": 0.647071361541748,
|
||||
"z": 0.18027013540267944
|
||||
"created": "2016-09-08T18:38:24Z",
|
||||
"dimensions": {
|
||||
"x": 0.16850528120994568,
|
||||
"y": 0.16850528120994568,
|
||||
"z": 0.16850528120994568
|
||||
},
|
||||
"visible": 0,
|
||||
"shape": "Cube",
|
||||
"clientOnly": 0,
|
||||
"id": "{70fcd96c-cd59-4f23-9ca5-a167f2f85680}",
|
||||
"ignoreForCollisions": 1,
|
||||
"lastEdited": 1481926908795578,
|
||||
"lastEditedBy": "{b80185ea-0936-4397-a5a4-3a64004f545f}",
|
||||
"name": "tutorial/farGrab/box_spawn",
|
||||
"owningAvatarID": "{00000000-0000-0000-0000-000000000000}",
|
||||
"position": {
|
||||
x: 3.4866,
|
||||
y: 0.6716,
|
||||
z: 0.4789
|
||||
"x": 3.4866282939910889,
|
||||
"y": 0.67159509658813477,
|
||||
"z": 0.47892442345619202
|
||||
},
|
||||
"queryAACube": {
|
||||
"scale": 0.64707136154174805,
|
||||
"x": 3.2037394046783447,
|
||||
"y": 0.33042514324188232,
|
||||
"z": 0.14542555809020996
|
||||
},
|
||||
"rotation": {
|
||||
"y": -1.52587890625e-05,
|
||||
"w": 1,
|
||||
"x": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05,
|
||||
"w": 1
|
||||
"y": -1.52587890625e-05,
|
||||
"z": -1.52587890625e-05
|
||||
},
|
||||
"ignoreForCollisions": 1,
|
||||
"shape": "Cube",
|
||||
"type": "Box",
|
||||
"id": "{70fcd96c-cd59-4f23-9ca5-a167f2f85680}",
|
||||
"name": "tutorial/farGrab/box_spawn"
|
||||
"userData": "{\"visible\":false,\"tag\":\"farGrab\"}",
|
||||
"visible": 0
|
||||
},
|
||||
"tutorial/teleport/pad": {
|
||||
"userData": "{\"tag\":\"teleport\"}",
|
||||
|
|
|
@ -45,7 +45,7 @@ if (!Function.prototype.bind) {
|
|||
keyReleaseHandler: function(event) {
|
||||
print(event.text);
|
||||
if (event.isShifted && event.isAlt) {
|
||||
if (event.text == ",") {
|
||||
if (event.text == "F12") {
|
||||
if (!this.tutorialManager.startNextStep()) {
|
||||
this.tutorialManager.startTutorial();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue