"use strict"; // 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. 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 /* jslint bitwise: true */ /* global Script, Entities, MyAvatar, Controller, Quat, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3, HMD, Uuid, AvatarList, Picks, Pointers, PickType*/ Script.include("/~/system/libraries/Xform.js");Script.include("/~/system/libraries/controllerDispatcherUtils.js");Script.include("/~/system/libraries/controllers.js"); (function() { // BEGIN LOCAL_SCOPE var controllerStandard = Controller.Standard; var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleportationSpotBasev8.fbx"); var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx"); var TARGET_MODEL_DIMENSIONS = { x: 0.6552, y: 0.3063, z: 0.6552 }; var COLORS_TELEPORT_SEAT = { red: 255, green: 0, blue: 170 }; var COLORS_TELEPORT_CAN_TELEPORT = { red: 97, green: 247, blue: 255 }; var COLORS_TELEPORT_CANCEL = { red: 255, green: 184, blue: 73 }; var handInfo = { right: { controllerInput: controllerStandard.RightHand }, left: { controllerInput: controllerStandard.LeftHand } }; var cancelPath = { color: COLORS_TELEPORT_CANCEL, alpha: 0.3, width: 0.025, drawInFront: true }; var teleportPath = { color: COLORS_TELEPORT_CAN_TELEPORT, alpha: 0.7, width: 0.025, drawInFront: true }; var seatPath = { color: COLORS_TELEPORT_SEAT, alpha: 0.7, width: 0.025, drawInFront: true }; var teleportEnd = { type: "Model", modelURL: TARGET_MODEL_URL, dimensions: TARGET_MODEL_DIMENSIONS, ignorePickIntersection: true }; var seatEnd = { type: "Model", modelURL: SEAT_MODEL_URL, dimensions: TARGET_MODEL_DIMENSIONS, ignorePickIntersection: true }; var collisionEnd = { type: "Box", dimensions: { x: 1.0, y: 0.001, z: 1.0 }, alpha: 0.0, ignorePickIntersection: true }; var teleportRenderStates = [{name: "cancel", path: cancelPath}, {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}, {name: "collision", end: collisionEnd}]; var DEFAULT_DISTANCE = 8.0; var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; var ignoredEntities = []; var TELEPORTER_STATES = { IDLE: 'idle', TARGETTING: 'targetting', TARGETTING_INVALID: 'targetting_invalid' }; var TARGET = { NONE: 'none', // Not currently targetting anything INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) COLLIDES: 'collides', // Insufficient space to accommodate the avatar capsule DISCREPANCY: 'discrepancy', // We are not 100% sure the avatar will fit so we trigger safe landing SURFACE: 'surface', // The current target is a valid surface SEAT: 'seat' // The current target is a seat }; var speed = 9.3; var accelerationAxis = {x: 0.0, y: -5.0, z: 0.0}; function Teleporter(hand) { var _this = this; this.init = false; this.hand = hand; this.buttonValue = 0; this.buttonTeleporting = false; // True if buttonValue is controlling teleport. this.standardAxisLY = 0.0; this.standardAxisRY = 0.0; this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler this.active = false; this.state = TELEPORTER_STATES.IDLE; this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; this.pickHeightOffset = 0.05; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; return otherModule; }; this.teleportHeadCollisionPick; this.teleportHandCollisionPick; this.teleportParabolaHandVisuals; this.teleportParabolaHandCollisions; this.teleportParabolaHeadVisuals; this.teleportParabolaHeadCollisions; this.PLAY_AREA_OVERLAY_MODEL = Script.resolvePath("../../assets/models/trackingSpacev18.fbx"); this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS = { x: 1.969, y: 0.001, z: 1.969 }; this.PLAY_AREA_FLOAT_ABOVE_FLOOR = 0.005; this.PLAY_AREA_OVERLAY_OFFSET = // Offset from floor. { x: 0, y: this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2 + this.PLAY_AREA_FLOAT_ABOVE_FLOOR, z: 0 }; this.PLAY_AREA_SENSOR_OVERLAY_MODEL = Script.resolvePath("../../assets/models/oculusSensorv11.fbx"); this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS = { x: 0.1198, y: 0.2981, z: 0.1198 }; this.PLAY_AREA_SENSOR_OVERLAY_ROTATION = Quat.fromVec3Degrees({ x: 0, y: -90, z: 0 }); this.PLAY_AREA_BOX_ALPHA = 1.0; this.PLAY_AREA_SENSOR_ALPHA = 0.8; this.playAreaSensorPositions = []; this.playArea = { x: 0, y: 0 }; this.playAreaCenterOffset = this.PLAY_AREA_OVERLAY_OFFSET; this.isPlayAreaVisible = false; this.wasPlayAreaVisible = false; this.isPlayAreaAvailable = false; this.targetOverlayID = null; this.playAreaOverlay = null; this.playAreaSensorPositionOverlays = []; this.TELEPORT_SCALE_DURATION = 130; this.TELEPORT_SCALE_TIMEOUT = 25; this.isTeleportVisible = false; this.teleportScaleTimer = null; this.teleportScaleStart = 0; this.teleportScaleFactor = 0; this.teleportScaleMode = "head"; this.TELEPORTED_FADE_DELAY_DURATION = 900; this.TELEPORTED_FADE_DURATION = 200; this.TELEPORTED_FADE_INTERVAL = 25; this.TELEPORTED_FADE_DELAY_DELTA = this.TELEPORTED_FADE_INTERVAL / this.TELEPORTED_FADE_DELAY_DURATION; this.TELEPORTED_FADE_DELTA = this.TELEPORTED_FADE_INTERVAL / this.TELEPORTED_FADE_DURATION; this.teleportedFadeTimer = null; this.teleportedFadeDelayFactor = 0; this.teleportedFadeFactor = 0; this.teleportedPosition = Vec3.ZERO; this.TELEPORTED_TARGET_ALPHA = 1.0; this.TELEPORTED_TARGET_ROTATION = Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }); this.teleportedTargetOverlay = null; this.setPlayAreaDimensions = function () { var avatarScale = MyAvatar.sensorToWorldScale; var playAreaOverlayProperties = { dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, { x: _this.playArea.width, y: _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, z: _this.playArea.height }) }; if (_this.teleportScaleFactor < 1) { // Adjust position of playAreOverlay so that its base is at correct height. // Always parenting to teleport target is good enough for this. var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix; var sensorToWorldRotation = Mat4.extractRotation(MyAvatar.sensorToWorldMatrix); var worldToSensorMatrix = Mat4.inverse(sensorToWorldMatrix); var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position); avatarSensorPosition.y = 0; var targetRotation = Entities.getEntityProperties(_this.targetOverlayID, ["rotation"]).rotation; if (targetRotation != null) { var relativePlayAreaCenterOffset = Vec3.sum(_this.playAreaCenterOffset, {x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0}); var localPosition = Vec3.multiplyQbyV(Quat.inverse(targetRotation), Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(avatarScale, Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition)))); localPosition.y = _this.teleportScaleFactor * localPosition.y; } else { print(""); } playAreaOverlayProperties.parentID = _this.targetOverlayID; if (targetRotation != null) { playAreaOverlayProperties.localPosition = localPosition; } } Entities.editEntity(_this.playAreaOverlay, playAreaOverlayProperties); for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { localPosition = _this.playAreaSensorPositions[i]; localPosition = Vec3.multiply(avatarScale, localPosition); // Position relative to the play area. localPosition.y = avatarScale * (_this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 - _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); Entities.editEntity(_this.playAreaSensorPositionOverlays[i], { dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), parentID: _this.playAreaOverlay, localPosition: localPosition }); } }; this.updatePlayAreaScale = function () { if (_this.isPlayAreaAvailable) { _this.setPlayAreaDimensions(); } }; this.teleporterSelectionName = "teleporterSelection" + hand.toString(); this.TELEPORTER_SELECTION_STYLE = { outlineUnoccludedColor: { red: 0, green: 0, blue: 0 }, outlineUnoccludedAlpha: 0, outlineOccludedColor: { red: 0, green: 0, blue: 0 }, outlineOccludedAlpha: 0, fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, fillUnoccludedAlpha: 0, fillOccludedColor: { red: 0, green: 0, blue: 255 }, fillOccludedAlpha: 0.84, outlineWidth: 0, isOutlineSmooth: false }; this.addToSelectedItemsList = function (properties) { for (var i = 0, length = teleportRenderStates.length; i < length; i++) { var state = properties.renderStates[teleportRenderStates[i].name]; if (state && state.end) { Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", state.end); } } }; this.cleanup = function() { Selection.removeListFromMap(_this.teleporterSelectionName); Pointers.removePointer(_this.teleportParabolaHandVisuals); Pointers.removePointer(_this.teleportParabolaHandCollisions); Pointers.removePointer(_this.teleportParabolaHeadVisuals); Pointers.removePointer(_this.teleportParabolaHeadCollisions); Picks.removePick(_this.teleportHandCollisionPick); Picks.removePick(_this.teleportHeadCollisionPick); Entities.deleteEntity(_this.teleportedTargetOverlay); Entities.deleteEntity(_this.playAreaOverlay); for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { Entities.deleteEntity(_this.playAreaSensorPositionOverlays[i]); } _this.playAreaSensorPositionOverlays = []; }; this.initPointers = function() { if (_this.init) { _this.cleanup(); } // FIXME: the documentation has Pointers.createPointer(PickType.Parabola, ...), // but that's a nonexistent function here. Is the documentation wrong or is // the Pointers here from a library that's getting included? _this.teleportParabolaHandVisuals = Pointers.createParabolaPointer({ joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates, maxDistance: 8.0 }); _this.teleportParabolaHandCollisions = Pointers.createParabolaPointer({ joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, maxDistance: 8.0 }); _this.teleportParabolaHeadVisuals = Pointers.createParabolaPointer({ joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates, maxDistance: 8.0 }); _this.teleportParabolaHeadCollisions = Pointers.createParabolaPointer({ joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, maxDistance: 8.0 }); _this.addToSelectedItemsList(Pointers.getPointerProperties(_this.teleportParabolaHandVisuals)); _this.addToSelectedItemsList(Pointers.getPointerProperties(_this.teleportParabolaHeadVisuals)); var capsuleData = MyAvatar.getCollisionCapsule(); var sensorToWorldScale = MyAvatar.getSensorToWorldScale(); var diameter = 2.0 * capsuleData.radius / sensorToWorldScale; var height = (Vec3.distance(capsuleData.start, capsuleData.end) + diameter) / sensorToWorldScale; var capsuleRatio = 5.0 * diameter / height; var offset = _this.pickHeightOffset * capsuleRatio; _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { enabled: false, parentID: Pointers.getPointerProperties(_this.teleportParabolaHandCollisions).renderStates["collision"].end, filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", dimensions: { x: diameter, y: height, z: diameter } }, position: { x: 0, y: offset + height * 0.5, z: 0 }, threshold: _this.capsuleThreshold }); _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { enabled: false, parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadCollisions).renderStates["collision"].end, filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", dimensions: { x: diameter, y: height, z: diameter } }, position: { x: 0, y: offset + height * 0.5, z: 0 }, threshold: _this.capsuleThreshold }); _this.playAreaOverlay = Entities.addEntity({ type: "Model", modelURL: _this.PLAY_AREA_OVERLAY_MODEL, drawInFront: false, visible: false }, "local"); _this.teleportedTargetOverlay = Entities.addEntity({ type: "Model", modelURL: TARGET_MODEL_URL, alpha: _this.TELEPORTED_TARGET_ALPHA, visible: false }, "local"); Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", _this.playAreaOverlay); Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", _this.teleportedTargetOverlay); _this.playArea = HMD.playArea; _this.isPlayAreaAvailable = HMD.active && _this.playArea.width !== 0 && _this.playArea.height !== 0; if (_this.isPlayAreaAvailable) { _this.playAreaCenterOffset = Vec3.sum({ x: _this.playArea.x, y: 0, z: _this.playArea.y }, _this.PLAY_AREA_OVERLAY_OFFSET); _this.playAreaSensorPositions = HMD.sensorPositions; for (var i = 0; i < _this.playAreaSensorPositions.length; i++) { if (i > _this.playAreaSensorPositionOverlays.length - 1) { var overlay = Entities.addEntity({ type: "Model", modelURL: _this.PLAY_AREA_SENSOR_OVERLAY_MODEL, dimensions: _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS, parentID: _this.playAreaOverlay, localRotation: _this.PLAY_AREA_SENSOR_OVERLAY_ROTATION, drawInFront: false, visible: false }, "local"); _this.playAreaSensorPositionOverlays.push(overlay); Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", overlay); } } _this.setPlayAreaDimensions(); } _this.init = true; }; _this.initPointers(); this.translateXAction = Controller.findAction("TranslateX"); this.translateYAction = Controller.findAction("TranslateY"); this.translateZAction = Controller.findAction("TranslateZ"); this.setPlayAreaVisible = function (visible, targetOverlayID, fade) { if (!_this.isPlayAreaAvailable || _this.isPlayAreaVisible === visible) { return; } _this.wasPlayAreaVisible = _this.isPlayAreaVisible; _this.isPlayAreaVisible = visible; _this.targetOverlayID = targetOverlayID; if (_this.teleportedFadeTimer !== null) { Script.clearTimeout(_this.teleportedFadeTimer); _this.teleportedFadeTimer = null; } if (visible || !fade) { // Immediately make visible or invisible. _this.isPlayAreaVisible = visible; Entities.editEntity(_this.playAreaOverlay, { dimensions: Vec3.ZERO, alpha: _this.PLAY_AREA_BOX_ALPHA, visible: visible }); for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { Entities.editEntity(_this.playAreaSensorPositionOverlays[i], { dimensions: Vec3.ZERO, alpha: _this.PLAY_AREA_SENSOR_ALPHA, visible: visible }); } Entities.editEntity(_this.teleportedTargetOverlay, { visible: false }); } else { // Fading out of overlays is initiated in setTeleportVisible(). } }; this.updatePlayArea = function (position) {Lines 1–500 of 1145. Load more
"use strict"; // 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. 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 /* jslint bitwise: true */ /* global Script, Entities, MyAvatar, Controller, Quat, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3, HMD, Uuid, AvatarList, Picks, Pointers, PickType */ Script.include("/~/system/libraries/Xform.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { // BEGIN LOCAL_SCOPE var controllerStandard = Controller.Standard; var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleportationSpotBasev8.fbx"); var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx"); var TARGET_MODEL_DIMENSIONS = { x: 0.6552, y: 0.3063, z: 0.6552 }; var COLORS_TELEPORT_SEAT = { red: 255, green: 0, blue: 170 }; var COLORS_TELEPORT_CAN_TELEPORT = { red: 97, green: 247, blue: 255 }; var COLORS_TELEPORT_CANCEL = { red: 255, green: 184, blue: 73 }; var handInfo = { right: { controllerInput: controllerStandard.RightHand }, left: { controllerInput: controllerStandard.LeftHand } }; var cancelPath = { color: COLORS_TELEPORT_CANCEL, alpha: 0.3, width: 0.025, drawInFront: true }; var teleportPath = { color: COLORS_TELEPORT_CAN_TELEPORT, alpha: 0.7, width: 0.025, drawInFront: true }; var seatPath = { color: COLORS_TELEPORT_SEAT, alpha: 0.7, width: 0.025, drawInFront: true }; var teleportEnd = { type: "Model", modelURL: TARGET_MODEL_URL, dimensions: TARGET_MODEL_DIMENSIONS, ignorePickIntersection: true }; var seatEnd = { type: "Model", modelURL: SEAT_MODEL_URL, dimensions: TARGET_MODEL_DIMENSIONS, ignorePickIntersection: true }; var collisionEnd = { type: "Box", dimensions: { x: 1.0, y: 0.001, z: 1.0 }, alpha: 0.0, ignorePickIntersection: true }; var teleportRenderStates = [{name: "cancel", path: cancelPath}, {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}, {name: "collision", end: collisionEnd}]; var DEFAULT_DISTANCE = 8.0; var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; var ignoredEntities = []; var TELEPORTER_STATES = { IDLE: 'idle', TARGETTING: 'targetting', TARGETTING_INVALID: 'targetting_invalid' }; var TARGET = { NONE: 'none', // Not currently targetting anything INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) COLLIDES: 'collides', // Insufficient space to accommodate the avatar capsule DISCREPANCY: 'discrepancy', // We are not 100% sure the avatar will fit so we trigger safe landing SURFACE: 'surface', // The current target is a valid surface SEAT: 'seat' // The current target is a seat }; var speed = 9.3; var accelerationAxis = {x: 0.0, y: -5.0, z: 0.0}; function Teleporter(hand) { var _this = this; this.init = false; this.hand = hand; this.buttonValue = 0; this.buttonTeleporting = false; // True if buttonValue is controlling teleport. this.standardAxisLY = 0.0; this.standardAxisRY = 0.0; this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler this.active = false; this.state = TELEPORTER_STATES.IDLE; this.currentTarget = TARGET.INVALID; this.currentResult = null; this.capsuleThreshold = 0.05; this.pickHeightOffset = 0.05; this.getOtherModule = function() { var otherModule = this.hand === RIGHT_HAND ? leftTeleporter : rightTeleporter; return otherModule; }; this.teleportHeadCollisionPick; this.teleportHandCollisionPick; this.teleportParabolaHandVisuals; this.teleportParabolaHandCollisions; this.teleportParabolaHeadVisuals; this.teleportParabolaHeadCollisions; this.PLAY_AREA_OVERLAY_MODEL = Script.resolvePath("../../assets/models/trackingSpacev18.fbx"); this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS = { x: 1.969, y: 0.001, z: 1.969 }; this.PLAY_AREA_FLOAT_ABOVE_FLOOR = 0.005; this.PLAY_AREA_OVERLAY_OFFSET = // Offset from floor. { x: 0, y: this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2 + this.PLAY_AREA_FLOAT_ABOVE_FLOOR, z: 0 }; this.PLAY_AREA_SENSOR_OVERLAY_MODEL = Script.resolvePath("../../assets/models/oculusSensorv11.fbx"); this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS = { x: 0.1198, y: 0.2981, z: 0.1198 }; this.PLAY_AREA_SENSOR_OVERLAY_ROTATION = Quat.fromVec3Degrees({ x: 0, y: -90, z: 0 }); this.PLAY_AREA_BOX_ALPHA = 1.0; this.PLAY_AREA_SENSOR_ALPHA = 0.8; this.playAreaSensorPositions = []; this.playArea = { x: 0, y: 0 }; this.playAreaCenterOffset = this.PLAY_AREA_OVERLAY_OFFSET; this.isPlayAreaVisible = false; this.wasPlayAreaVisible = false; this.isPlayAreaAvailable = false; this.targetOverlayID = null; this.playAreaOverlay = null; this.playAreaSensorPositionOverlays = []; this.TELEPORT_SCALE_DURATION = 130; this.TELEPORT_SCALE_TIMEOUT = 25; this.isTeleportVisible = false; this.teleportScaleTimer = null; this.teleportScaleStart = 0; this.teleportScaleFactor = 0; this.teleportScaleMode = "head"; this.TELEPORTED_FADE_DELAY_DURATION = 900; this.TELEPORTED_FADE_DURATION = 200; this.TELEPORTED_FADE_INTERVAL = 25; this.TELEPORTED_FADE_DELAY_DELTA = this.TELEPORTED_FADE_INTERVAL / this.TELEPORTED_FADE_DELAY_DURATION; this.TELEPORTED_FADE_DELTA = this.TELEPORTED_FADE_INTERVAL / this.TELEPORTED_FADE_DURATION; this.teleportedFadeTimer = null; this.teleportedFadeDelayFactor = 0; this.teleportedFadeFactor = 0; this.teleportedPosition = Vec3.ZERO; this.TELEPORTED_TARGET_ALPHA = 1.0; this.TELEPORTED_TARGET_ROTATION = Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }); this.teleportedTargetOverlay = null; this.setPlayAreaDimensions = function () { var avatarScale = MyAvatar.sensorToWorldScale; var playAreaOverlayProperties = { dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, { x: _this.playArea.width, y: _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y, z: _this.playArea.height }) }; if (_this.teleportScaleFactor < 1) { // Adjust position of playAreOverlay so that its base is at correct height. // Always parenting to teleport target is good enough for this. var sensorToWorldMatrix = MyAvatar.sensorToWorldMatrix; var sensorToWorldRotation = Mat4.extractRotation(MyAvatar.sensorToWorldMatrix); var worldToSensorMatrix = Mat4.inverse(sensorToWorldMatrix); var avatarSensorPosition = Mat4.transformPoint(worldToSensorMatrix, MyAvatar.position); avatarSensorPosition.y = 0; var targetRotation = Entities.getEntityProperties(_this.targetOverlayID, ["rotation"]).rotation; if (targetRotation != null) { var relativePlayAreaCenterOffset = Vec3.sum(_this.playAreaCenterOffset, {x: 0, y: -TARGET_MODEL_DIMENSIONS.y / 2, z: 0}); var localPosition = Vec3.multiplyQbyV(Quat.inverse(targetRotation), Vec3.multiplyQbyV(sensorToWorldRotation, Vec3.multiply(avatarScale, Vec3.subtract(relativePlayAreaCenterOffset, avatarSensorPosition)))); localPosition.y = _this.teleportScaleFactor * localPosition.y; } else { print(""); } playAreaOverlayProperties.parentID = _this.targetOverlayID; if (targetRotation != null) { playAreaOverlayProperties.localPosition = localPosition; } } Entities.editEntity(_this.playAreaOverlay, playAreaOverlayProperties); for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { localPosition = _this.playAreaSensorPositions[i]; localPosition = Vec3.multiply(avatarScale, localPosition); // Position relative to the play area. localPosition.y = avatarScale * (_this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS.y / 2 - _this.PLAY_AREA_OVERLAY_MODEL_DIMENSIONS.y / 2); Entities.editEntity(_this.playAreaSensorPositionOverlays[i], { dimensions: Vec3.multiply(_this.teleportScaleFactor * avatarScale, _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS), parentID: _this.playAreaOverlay, localPosition: localPosition }); } }; this.updatePlayAreaScale = function () { if (_this.isPlayAreaAvailable) { _this.setPlayAreaDimensions(); } }; this.teleporterSelectionName = "teleporterSelection" + hand.toString(); this.TELEPORTER_SELECTION_STYLE = { outlineUnoccludedColor: { red: 0, green: 0, blue: 0 }, outlineUnoccludedAlpha: 0, outlineOccludedColor: { red: 0, green: 0, blue: 0 }, outlineOccludedAlpha: 0, fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, fillUnoccludedAlpha: 0, fillOccludedColor: { red: 0, green: 0, blue: 255 }, fillOccludedAlpha: 0.84, outlineWidth: 0, isOutlineSmooth: false }; this.addToSelectedItemsList = function (properties) { for (var i = 0, length = teleportRenderStates.length; i < length; i++) { var state = properties.renderStates[teleportRenderStates[i].name]; if (state && state.end) { Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", state.end); } } }; this.cleanup = function() { Selection.removeListFromMap(_this.teleporterSelectionName); Pointers.removePointer(_this.teleportParabolaHandVisuals); Pointers.removePointer(_this.teleportParabolaHandCollisions); Pointers.removePointer(_this.teleportParabolaHeadVisuals); Pointers.removePointer(_this.teleportParabolaHeadCollisions); Picks.removePick(_this.teleportHandCollisionPick); Picks.removePick(_this.teleportHeadCollisionPick); Entities.deleteEntity(_this.teleportedTargetOverlay); Entities.deleteEntity(_this.playAreaOverlay); for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { Entities.deleteEntity(_this.playAreaSensorPositionOverlays[i]); } _this.playAreaSensorPositionOverlays = []; }; this.initPointers = function() { if (_this.init) { _this.cleanup(); } // FIXME: the documentation has Pointers.createPointer(PickType.Parabola, ...), // but that's a nonexistent function here. Is the documentation wrong or is // the Pointers here from a library that's getting included? _this.teleportParabolaHandVisuals = Pointers.createParabolaPointer({ joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates, maxDistance: 8.0 }); _this.teleportParabolaHandCollisions = Pointers.createParabolaPointer({ joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", dirOffset: { x: 0, y: 1, z: 0.1 }, posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 }, filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, maxDistance: 8.0 }); _this.teleportParabolaHeadVisuals = Pointers.createParabolaPointer({ joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates, maxDistance: 8.0 }); _this.teleportParabolaHeadCollisions = Pointers.createParabolaPointer({ joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, scaleWithParent: true, centerEndY: false, speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, maxDistance: 8.0 }); _this.addToSelectedItemsList(Pointers.getPointerProperties(_this.teleportParabolaHandVisuals)); _this.addToSelectedItemsList(Pointers.getPointerProperties(_this.teleportParabolaHeadVisuals)); var capsuleData = MyAvatar.getCollisionCapsule(); var sensorToWorldScale = MyAvatar.getSensorToWorldScale(); var diameter = 2.0 * capsuleData.radius / sensorToWorldScale; var height = (Vec3.distance(capsuleData.start, capsuleData.end) + diameter) / sensorToWorldScale; var capsuleRatio = 5.0 * diameter / height; var offset = _this.pickHeightOffset * capsuleRatio; _this.teleportHandCollisionPick = Picks.createPick(PickType.Collision, { enabled: false, parentID: Pointers.getPointerProperties(_this.teleportParabolaHandCollisions).renderStates["collision"].end, filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", dimensions: { x: diameter, y: height, z: diameter } }, position: { x: 0, y: offset + height * 0.5, z: 0 }, threshold: _this.capsuleThreshold }); _this.teleportHeadCollisionPick = Picks.createPick(PickType.Collision, { enabled: false, parentID: Pointers.getPointerProperties(_this.teleportParabolaHeadCollisions).renderStates["collision"].end, filter: Picks.PICK_ENTITIES | Picks.PICK_AVATARS, shape: { shapeType: "capsule-y", dimensions: { x: diameter, y: height, z: diameter } }, position: { x: 0, y: offset + height * 0.5, z: 0 }, threshold: _this.capsuleThreshold }); _this.playAreaOverlay = Entities.addEntity({ type: "Model", modelURL: _this.PLAY_AREA_OVERLAY_MODEL, drawInFront: false, visible: false }, "local"); _this.teleportedTargetOverlay = Entities.addEntity({ type: "Model", modelURL: TARGET_MODEL_URL, alpha: _this.TELEPORTED_TARGET_ALPHA, visible: false }, "local"); Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", _this.playAreaOverlay); Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", _this.teleportedTargetOverlay); _this.playArea = HMD.playArea; _this.isPlayAreaAvailable = HMD.active && _this.playArea.width !== 0 && _this.playArea.height !== 0; if (_this.isPlayAreaAvailable) { _this.playAreaCenterOffset = Vec3.sum({ x: _this.playArea.x, y: 0, z: _this.playArea.y }, _this.PLAY_AREA_OVERLAY_OFFSET); _this.playAreaSensorPositions = HMD.sensorPositions; for (var i = 0; i < _this.playAreaSensorPositions.length; i++) { if (i > _this.playAreaSensorPositionOverlays.length - 1) { var overlay = Entities.addEntity({ type: "Model", modelURL: _this.PLAY_AREA_SENSOR_OVERLAY_MODEL, dimensions: _this.PLAY_AREA_SENSOR_OVERLAY_DIMENSIONS, parentID: _this.playAreaOverlay, localRotation: _this.PLAY_AREA_SENSOR_OVERLAY_ROTATION, drawInFront: false, visible: false }, "local"); _this.playAreaSensorPositionOverlays.push(overlay); Selection.addToSelectedItemsList(_this.teleporterSelectionName, "entity", overlay); } } _this.setPlayAreaDimensions(); } _this.init = true; }; _this.initPointers(); this.translateXAction = Controller.findAction("TranslateX"); this.translateYAction = Controller.findAction("TranslateY"); this.translateZAction = Controller.findAction("TranslateZ"); this.setPlayAreaVisible = function (visible, targetOverlayID, fade) { if (!_this.isPlayAreaAvailable || _this.isPlayAreaVisible === visible) { return; } _this.wasPlayAreaVisible = _this.isPlayAreaVisible; _this.isPlayAreaVisible = visible; _this.targetOverlayID = targetOverlayID; if (_this.teleportedFadeTimer !== null) { Script.clearTimeout(_this.teleportedFadeTimer); _this.teleportedFadeTimer = null; } if (visible || !fade) { // Immediately make visible or invisible. _this.isPlayAreaVisible = visible; Entities.editEntity(_this.playAreaOverlay, { dimensions: Vec3.ZERO, alpha: _this.PLAY_AREA_BOX_ALPHA, visible: visible }); for (var i = 0; i < _this.playAreaSensorPositionOverlays.length; i++) { Entities.editEntity(_this.playAreaSensorPositionOverlays[i], { dimensions: Vec3.ZERO, alpha: _this.PLAY_AREA_SENSOR_ALPHA, visible: visible }); } Entities.editEntity(_this.teleportedTargetOverlay, { visible: false }); } else { // Fading out of overlays is initiated in setTeleportVisible(). } }; this.updatePlayArea = function (position) {