diff --git a/scripts/system/assets/models/teleport-cancel.fbx b/scripts/system/assets/models/teleport-cancel.fbx new file mode 100644 index 0000000000..1c12e28159 Binary files /dev/null and b/scripts/system/assets/models/teleport-cancel.fbx differ diff --git a/scripts/system/assets/models/teleport-destination.fbx b/scripts/system/assets/models/teleport-destination.fbx new file mode 100644 index 0000000000..5fdb0d56af Binary files /dev/null and b/scripts/system/assets/models/teleport-destination.fbx differ diff --git a/scripts/system/assets/models/teleport.fbx b/scripts/system/assets/models/teleport.fbx deleted file mode 100644 index 831f152add..0000000000 Binary files a/scripts/system/assets/models/teleport.fbx and /dev/null differ diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index 5cd8460172..fae9b98b96 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -1,34 +1,18 @@ // Created by james b. pollack @imgntn on 7/2/2016 // Copyright 2016 High Fidelity, Inc. // -// Creates a beam and target and then teleports you there. +// Creates a beam and target and then teleports you there. Release when its close to you to cancel. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html var inTeleportMode = false; -// instant -// var NUMBER_OF_STEPS = 0; -// var SMOOTH_ARRIVAL_SPACING = 0; - -// // slow -// var SMOOTH_ARRIVAL_SPACING = 150; -// var NUMBER_OF_STEPS = 2; - -// medium-slow -// var SMOOTH_ARRIVAL_SPACING = 100; -// var NUMBER_OF_STEPS = 4; - -// medium-fast var SMOOTH_ARRIVAL_SPACING = 33; var NUMBER_OF_STEPS = 6; -//fast -// var SMOOTH_ARRIVAL_SPACING = 10; -// var NUMBER_OF_STEPS = 20; - -var TARGET_MODEL_URL = Script.resolvePath("../assets/models/teleport.fbx"); +var TARGET_MODEL_URL = Script.resolvePath("../assets/models/teleport-destination.fbx"); +var TOO_CLOSE_MODEL_URL = Script.resolvePath("../assets/models/teleport-cancel.fbx"); var TARGET_MODEL_DIMENSIONS = { x: 1.15, y: 0.5, @@ -47,7 +31,13 @@ var COLORS_TELEPORT_CANNOT_TELEPORT = { blue: 141 }; -var MAX_AVATAR_SPEED = 0.25; +var COLORS_TELEPORT_TOO_CLOSE = { + red: 255, + green: 184, + blue: 73 +}; + +var TELEPORT_CANCEL_RANGE = 1.5; function ThumbPad(hand) { this.hand = hand; @@ -86,29 +76,17 @@ function Teleporter() { this.rightOverlayLine = null; this.leftOverlayLine = null; this.targetOverlay = null; + this.cancelOverlay = null; this.updateConnected = null; this.smoothArrivalInterval = null; this.teleportHand = null; + this.tooClose = false; this.initialize = function() { this.createMappings(); this.disableGrab(); }; - this.createTargetOverlay = function() { - - if (_this.targetOverlay !== null) { - return; - } - var targetOverlayProps = { - url: TARGET_MODEL_URL, - dimensions: TARGET_MODEL_DIMENSIONS, - visible: true - }; - - _this.targetOverlay = Overlays.addOverlay("model", targetOverlayProps); - }; - this.createMappings = function() { teleporter.telporterMappingInternalName = 'Hifi-Teleporter-Internal-Dev-' + Math.random(); teleporter.teleportMappingInternal = Controller.newMapping(teleporter.telporterMappingInternalName); @@ -143,11 +121,56 @@ function Teleporter() { this.updateConnected = true; }; + this.createTargetOverlay = function() { + + if (_this.targetOverlay !== null) { + return; + } + var targetOverlayProps = { + url: TARGET_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + visible: true + }; + + var cancelOverlayProps = { + url: TOO_CLOSE_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + visible: true + }; + + _this.targetOverlay = Overlays.addOverlay("model", targetOverlayProps); + + }; + + this.createCancelOverlay = function() { + + if (_this.cancelOverlay !== null) { + return; + } + + var cancelOverlayProps = { + url: TOO_CLOSE_MODEL_URL, + dimensions: TARGET_MODEL_DIMENSIONS, + visible: true + }; + + _this.cancelOverlay = Overlays.addOverlay("model", cancelOverlayProps); + }; + + this.deleteCancelOverlay = function() { + if (this.cancelOverlay === null) { + return; + } + + Overlays.deleteOverlay(this.cancelOverlay); + this.cancelOverlay = null; + } this.deleteTargetOverlay = function() { if (this.targetOverlay === null) { return; } + Overlays.deleteOverlay(this.targetOverlay); this.intersection = null; this.targetOverlay = null; @@ -214,7 +237,7 @@ function Teleporter() { var rightControllerRotation = Controller.getPoseValue(Controller.Standard.RightHand).rotation; - var rightRotation = Quat.multiply(MyAvatar.orientation, rightControllerRotation) + var rightRotation = Quat.multiply(MyAvatar.orientation, rightControllerRotation); var rightFinal = Quat.multiply(rightRotation, Quat.angleAxis(90, { x: 1, @@ -235,11 +258,25 @@ function Teleporter() { var rightIntersection = Entities.findRayIntersection(teleporter.rightPickRay, true, [], [this.targetEntity]); if (rightIntersection.intersects) { - this.rightLineOn(rightPickRay.origin, rightIntersection.intersection, COLORS_TELEPORT_CAN_TELEPORT); - if (this.targetOverlay !== null) { - this.updateTargetOverlay(rightIntersection); + if (this.tooClose === true) { + this.deleteTargetOverlay(); + + this.rightLineOn(rightPickRay.origin, rightIntersection.intersection, COLORS_TELEPORT_TOO_CLOSE); + if (this.cancelOverlay !== null) { + this.updateCancelOverlay(rightIntersection); + } else { + this.createCancelOverlay(); + } } else { - this.createTargetOverlay(); + this.deleteCancelOverlay(); + + this.rightLineOn(rightPickRay.origin, rightIntersection.intersection, COLORS_TELEPORT_CAN_TELEPORT); + if (this.targetOverlay !== null) { + this.updateTargetOverlay(rightIntersection); + } else { + this.createTargetOverlay(); + } + } } else { @@ -275,13 +312,27 @@ function Teleporter() { if (leftIntersection.intersects) { - this.leftLineOn(leftPickRay.origin, leftIntersection.intersection, COLORS_TELEPORT_CAN_TELEPORT); - if (this.targetOverlay !== null) { - this.updateTargetOverlay(leftIntersection); + if (this.tooClose === true) { + this.deleteTargetOverlay(); + this.leftLineOn(leftPickRay.origin, leftIntersection.intersection, COLORS_TELEPORT_TOO_CLOSE); + if (this.cancelOverlay !== null) { + this.updateCancelOverlay(leftIntersection); + } else { + this.createCancelOverlay(); + } } else { - this.createTargetOverlay(); + this.deleteCancelOverlay(); + this.leftLineOn(leftPickRay.origin, leftIntersection.intersection, COLORS_TELEPORT_CAN_TELEPORT); + + if (this.targetOverlay !== null) { + this.updateTargetOverlay(leftIntersection); + } else { + this.createTargetOverlay(); + } + } + } else { this.deleteTargetOverlay(); @@ -355,20 +406,44 @@ function Teleporter() { this.updateTargetOverlay = function(intersection) { _this.intersection = intersection; - var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP) - var euler = Quat.safeEulerAngles(rotation) + var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP); + var euler = Quat.safeEulerAngles(rotation); var position = { x: intersection.intersection.x, y: intersection.intersection.y + TARGET_MODEL_DIMENSIONS.y / 2, z: intersection.intersection.z - } + }; + + this.tooClose = isTooCloseToTeleport(position); + var towardUs = Quat.fromPitchYawRollDegrees(0, euler.y, 0); + Overlays.editOverlay(this.targetOverlay, { position: position, - rotation: Quat.fromPitchYawRollDegrees(0, euler.y, 0), + rotation: towardUs }); }; + this.updateCancelOverlay = function(intersection) { + _this.intersection = intersection; + + var rotation = Quat.lookAt(intersection.intersection, MyAvatar.position, Vec3.UP); + var euler = Quat.safeEulerAngles(rotation); + var position = { + x: intersection.intersection.x, + y: intersection.intersection.y + TARGET_MODEL_DIMENSIONS.y / 2, + z: intersection.intersection.z + }; + + this.tooClose = isTooCloseToTeleport(position); + var towardUs = Quat.fromPitchYawRollDegrees(0, euler.y, 0); + + Overlays.editOverlay(this.cancelOverlay, { + position: position, + rotation: towardUs + }); + }; + this.disableGrab = function() { Messages.sendLocalMessage('Hifi-Hand-Disabler', this.teleportHand); }; @@ -383,10 +458,17 @@ function Teleporter() { }; this.teleport = function(value) { + if (value === undefined) { this.exitTeleportMode(); } + if (this.intersection !== null) { + if (this.tooClose === true) { + this.exitTeleportMode(); + this.deleteCancelOverlay(); + return; + } var offset = getAvatarFootOffset(); this.intersection.intersection.y += offset; this.exitTeleportMode(); @@ -394,7 +476,6 @@ function Teleporter() { } }; - this.findMidpoint = function(start, end) { var xy = Vec3.sum(start, end); var midpoint = Vec3.multiply(0.5, xy); @@ -433,13 +514,13 @@ function Teleporter() { if (_this.arrivalPoints.length === 1 || _this.arrivalPoints.length === 0) { _this.deleteTargetOverlay(); + _this.deleteCancelOverlay(); } }, SMOOTH_ARRIVAL_SPACING); } } - //related to repositioning the avatar after you teleport function getAvatarFootOffset() { var data = getJointData(); @@ -505,7 +586,11 @@ function isMoving() { } else { return false; } -} +}; + +function isTooCloseToTeleport(position) { + return Vec3.distance(MyAvatar.position, position) <= TELEPORT_CANCEL_RANGE; +}; function registerMappings() { mappingName = 'Hifi-Teleporter-Dev-' + Math.random(); @@ -559,7 +644,7 @@ function registerMappings() { }, TELEPORT_DELAY) return; }); -} +}; registerMappings(); @@ -573,6 +658,7 @@ function cleanup() { teleportMapping.disable(); teleporter.disableMappings(); teleporter.deleteTargetOverlay(); + teleporter.deleteCancelOverlay(); teleporter.turnOffOverlayBeams(); if (teleporter.updateConnected !== null) { Script.update.disconnect(teleporter.update);