// Simulator Controller|SDK_Simulator|003 namespace VRTK { using UnityEngine; using System.Collections.Generic; /// /// The Sim Controller SDK script provides functions to help simulate VR controllers. /// [SDK_Description(typeof(SDK_SimSystem))] public class SDK_SimController : SDK_BaseController { protected SDK_ControllerSim rightController; protected SDK_ControllerSim leftController; protected Dictionary keyMappings = new Dictionary() { {"Trigger", KeyCode.Mouse1 }, {"Grip", KeyCode.Mouse0 }, {"TouchpadPress", KeyCode.Q }, {"ButtonOne", KeyCode.E }, {"ButtonTwo", KeyCode.R }, {"StartMenu", KeyCode.F }, {"TouchModifier", KeyCode.T}, {"HairTouchModifier", KeyCode.H} }; protected const string RIGHT_HAND_CONTROLLER_NAME = "RightHand"; protected const string LEFT_HAND_CONTROLLER_NAME = "LeftHand"; public virtual void SetKeyMappings(Dictionary givenKeyMappings) { keyMappings = givenKeyMappings; } /// /// The ProcessUpdate method enables an SDK to run logic for every Unity Update /// /// The reference for the controller. /// A dictionary of generic options that can be used to within the update. public override void ProcessUpdate(VRTK_ControllerReference controllerReference, Dictionary options) { } /// /// The ProcessFixedUpdate method enables an SDK to run logic for every Unity FixedUpdate /// /// The reference for the controller. /// A dictionary of generic options that can be used to within the fixed update. public override void ProcessFixedUpdate(VRTK_ControllerReference controllerReference, Dictionary options) { } /// /// The GetCurrentControllerType method returns the current used ControllerType based on the SDK and headset being used. /// /// The ControllerType based on the SDK and headset being used. public override ControllerType GetCurrentControllerType() { return ControllerType.Simulator_Hand; } /// /// The GetControllerDefaultColliderPath returns the path to the prefab that contains the collider objects for the default controller of this SDK. /// /// The controller hand to check for /// A path to the resource that contains the collider GameObject. public override string GetControllerDefaultColliderPath(ControllerHand hand) { return "ControllerColliders/Simulator"; } /// /// The GetControllerElementPath returns the path to the game object that the given controller element for the given hand resides in. /// /// The controller element to look up. /// The controller hand to look up. /// Whether to get the initial path or the full path to the element. /// A string containing the path to the game object that the controller element resides in. public override string GetControllerElementPath(ControllerElements element, ControllerHand hand, bool fullPath = false) { string suffix = (fullPath ? "/attach" : ""); switch (element) { case ControllerElements.AttachPoint: return ""; case ControllerElements.Trigger: return "" + suffix; case ControllerElements.GripLeft: return "" + suffix; case ControllerElements.GripRight: return "" + suffix; case ControllerElements.Touchpad: return "" + suffix; case ControllerElements.ButtonOne: return "" + suffix; case ControllerElements.SystemMenu: return "" + suffix; case ControllerElements.Body: return ""; } return null; } /// /// The GetControllerIndex method returns the index of the given controller. /// /// The GameObject containing the controller. /// The index of the given controller. public override uint GetControllerIndex(GameObject controller) { if (CheckActualOrScriptAliasControllerIsRightHand(controller)) { return 1; } if (CheckActualOrScriptAliasControllerIsLeftHand(controller)) { return 2; } return uint.MaxValue; } /// /// The GetControllerByIndex method returns the GameObject of a controller with a specific index. /// /// The index of the controller to find. /// If true it will return the actual controller, if false it will return the script alias controller GameObject. /// The GameObject of the controller public override GameObject GetControllerByIndex(uint index, bool actual = false) { SetupPlayer(); VRTK_SDKManager sdkManager = VRTK_SDKManager.instance; switch (index) { case 1: return (sdkManager != null && !actual ? sdkManager.scriptAliasRightController : (rightController != null ? rightController.gameObject : null)); case 2: return (sdkManager != null && !actual ? sdkManager.scriptAliasLeftController : (leftController != null ? leftController.gameObject : null)); default: return null; } } /// /// The GetControllerOrigin method returns the origin of the given controller. /// /// The reference to the controller to retrieve the origin from. /// A Transform containing the origin of the controller. public override Transform GetControllerOrigin(VRTK_ControllerReference controllerReference) { return (controllerReference != null && controllerReference.actual != null ? controllerReference.actual.transform : null); } /// /// The GenerateControllerPointerOrigin method can create a custom pointer origin Transform to represent the pointer position and forward. /// /// The GameObject that the origin will become parent of. If it is a controller then it will also be used to determine the hand if required. /// A generated Transform that contains the custom pointer origin. public override Transform GenerateControllerPointerOrigin(GameObject parent) { return null; } /// /// The GetControllerLeftHand method returns the GameObject containing the representation of the left hand controller. /// /// If true it will return the actual controller, if false it will return the script alias controller GameObject. /// The GameObject containing the left hand controller. public override GameObject GetControllerLeftHand(bool actual = false) { // use the basic base functionality to find the left hand controller GameObject controller = GetSDKManagerControllerLeftHand(actual); // if the controller cannot be found with default settings, try finding it below the InputSimulator by name if (controller == null && actual) { controller = GetActualController(ControllerHand.Left); } return controller; } /// /// The GetControllerRightHand method returns the GameObject containing the representation of the right hand controller. /// /// If true it will return the actual controller, if false it will return the script alias controller GameObject. /// The GameObject containing the right hand controller. public override GameObject GetControllerRightHand(bool actual = false) { // use the basic base functionality to find the right hand controller GameObject controller = GetSDKManagerControllerRightHand(actual); // if the controller cannot be found with default settings, try finding it below the InputSimulator by name if (controller == null && actual) { controller = GetActualController(ControllerHand.Right); } return controller; } /// /// The IsControllerLeftHand/1 method is used to check if the given controller is the the left hand controller. /// /// The GameObject to check. /// Returns true if the given controller is the left hand controller. public override bool IsControllerLeftHand(GameObject controller) { return CheckActualOrScriptAliasControllerIsLeftHand(controller); } /// /// The IsControllerRightHand/1 method is used to check if the given controller is the the right hand controller. /// /// The GameObject to check. /// Returns true if the given controller is the right hand controller. public override bool IsControllerRightHand(GameObject controller) { return CheckActualOrScriptAliasControllerIsRightHand(controller); } /// /// The IsControllerLeftHand/2 method is used to check if the given controller is the the left hand controller. /// /// The GameObject to check. /// If true it will check the actual controller, if false it will check the script alias controller. /// Returns true if the given controller is the left hand controller. public override bool IsControllerLeftHand(GameObject controller, bool actual) { return CheckControllerLeftHand(controller, actual); } /// /// The IsControllerRightHand/2 method is used to check if the given controller is the the right hand controller. /// /// The GameObject to check. /// If true it will check the actual controller, if false it will check the script alias controller. /// Returns true if the given controller is the right hand controller. public override bool IsControllerRightHand(GameObject controller, bool actual) { return CheckControllerRightHand(controller, actual); } /// /// The GetControllerModel method returns the model alias for the given GameObject. /// /// The GameObject to get the model alias for. /// The GameObject that has the model alias within it. public override GameObject GetControllerModel(GameObject controller) { return GetControllerModelFromController(controller); } /// /// The GetControllerModel method returns the model alias for the given controller hand. /// /// The hand enum of which controller model to retrieve. /// The GameObject that has the model alias within it. public override GameObject GetControllerModel(ControllerHand hand) { GameObject model = null; GameObject simPlayer = SDK_InputSimulator.FindInScene(); if (simPlayer != null) { switch (hand) { case ControllerHand.Left: model = simPlayer.transform.Find(string.Format("{0}/Hand", LEFT_HAND_CONTROLLER_NAME)).gameObject; break; case ControllerHand.Right: model = simPlayer.transform.Find(string.Format("{0}/Hand", RIGHT_HAND_CONTROLLER_NAME)).gameObject; break; } } return model; } /// /// The GetControllerRenderModel method gets the game object that contains the given controller's render model. /// /// The reference to the controller to check. /// A GameObject containing the object that has a render model for the controller. public override GameObject GetControllerRenderModel(VRTK_ControllerReference controllerReference) { return controllerReference.scriptAlias.transform.parent.Find("Hand").gameObject; } /// /// The SetControllerRenderModelWheel method sets the state of the scroll wheel on the controller render model. /// /// The GameObject containing the controller render model. /// If true and the render model has a scroll wheen then it will be displayed, if false then the scroll wheel will be hidden. public override void SetControllerRenderModelWheel(GameObject renderModel, bool state) { } /// /// The HapticPulse/2 method is used to initiate a simple haptic pulse on the tracked object of the given controller reference. /// /// The reference to the tracked object to initiate the haptic pulse on. /// The intensity of the rumble of the controller motor. `0` to `1`. public override void HapticPulse(VRTK_ControllerReference controllerReference, float strength = 0.5f) { } /// /// The HapticPulse/2 method is used to initiate a haptic pulse based on an audio clip on the tracked object of the given controller reference. /// /// The reference to the tracked object to initiate the haptic pulse on. /// The audio clip to use for the haptic pattern. public override bool HapticPulse(VRTK_ControllerReference controllerReference, AudioClip clip) { //Return true so it just always prevents doing a fallback routine. return true; } /// /// The GetHapticModifiers method is used to return modifiers for the duration and interval if the SDK handles it slightly differently. /// /// An SDK_ControllerHapticModifiers object with a given `durationModifier` and an `intervalModifier`. public override SDK_ControllerHapticModifiers GetHapticModifiers() { return new SDK_ControllerHapticModifiers(); } /// /// The GetVelocity method is used to determine the current velocity of the tracked object on the given controller reference. /// /// The reference to the tracked object to check for. /// A Vector3 containing the current velocity of the tracked object. public override Vector3 GetVelocity(VRTK_ControllerReference controllerReference) { SetupPlayer(); uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); switch (index) { case 1: return (rightController != null ? rightController.GetVelocity() : Vector3.zero); case 2: return (leftController != null ? leftController.GetVelocity() : Vector3.zero); default: return Vector3.zero; } } /// /// The GetAngularVelocity method is used to determine the current angular velocity of the tracked object on the given controller reference. /// /// The reference to the tracked object to check for. /// A Vector3 containing the current angular velocity of the tracked object. public override Vector3 GetAngularVelocity(VRTK_ControllerReference controllerReference) { SetupPlayer(); uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); switch (index) { case 1: return (rightController != null ? rightController.GetAngularVelocity() : Vector3.zero); case 2: return (leftController != null ? leftController.GetAngularVelocity() : Vector3.zero); default: return Vector3.zero; } } /// /// The IsTouchpadStatic method is used to determine if the touchpad is currently not being moved. /// /// /// /// /// Returns true if the touchpad is not currently being touched or moved. public override bool IsTouchpadStatic(bool isTouched, Vector2 currentAxisValues, Vector2 previousAxisValues, int compareFidelity) { return (!isTouched || VRTK_SharedMethods.Vector2ShallowCompare(currentAxisValues, previousAxisValues, compareFidelity)); } /// /// The GetButtonAxis method retrieves the current X/Y axis values for the given button type on the given controller reference. /// /// The type of button to check for the axis on. /// The reference to the controller to check the button axis on. /// A Vector2 of the X/Y values of the button axis. If no axis values exist for the given button, then a Vector2.Zero is returned. public override Vector2 GetButtonAxis(ButtonTypes buttonType, VRTK_ControllerReference controllerReference) { return Vector2.zero; } /// /// The GetButtonHairlineDelta method is used to get the difference between the current button press and the previous frame button press. /// /// The type of button to get the hairline delta for. /// The reference to the controller to get the hairline delta for. /// The delta between the button presses. public override float GetButtonHairlineDelta(ButtonTypes buttonType, VRTK_ControllerReference controllerReference) { return 0f; } /// /// The GetControllerButtonState method is used to determine if the given controller button for the given press type on the given controller reference is currently taking place. /// /// The type of button to check for the state of. /// The button state to check for. /// The reference to the controller to check the button state on. /// Returns true if the given button is in the state of the given press type on the given controller reference. public override bool GetControllerButtonState(ButtonTypes buttonType, ButtonPressTypes pressType, VRTK_ControllerReference controllerReference) { uint index = VRTK_ControllerReference.GetRealIndex(controllerReference); switch (buttonType) { case ButtonTypes.Trigger: case ButtonTypes.TriggerHairline: return GetControllerButtonState(index, "Trigger", pressType); case ButtonTypes.Grip: case ButtonTypes.GripHairline: return GetControllerButtonState(index, "Grip", pressType); case ButtonTypes.Touchpad: return GetControllerButtonState(index, "TouchpadPress", pressType); case ButtonTypes.ButtonOne: return GetControllerButtonState(index, "ButtonOne", pressType); case ButtonTypes.ButtonTwo: return GetControllerButtonState(index, "ButtonTwo", pressType); case ButtonTypes.StartMenu: return GetControllerButtonState(index, "StartMenu", pressType); } return false; } protected virtual void OnEnable() { SetupPlayer(); } protected virtual void SetupPlayer() { if (rightController == null || leftController == null) { GameObject simPlayer = SDK_InputSimulator.FindInScene(); if (simPlayer != null) { rightController = (rightController == null ? simPlayer.transform.Find(RIGHT_HAND_CONTROLLER_NAME).GetComponent() : rightController); leftController = (leftController == null ? simPlayer.transform.Find(LEFT_HAND_CONTROLLER_NAME).GetComponent() : leftController); } } } /// /// whether or not the touch modifier is currently pressed /// if so, pressing a key on the keyboard will only emit touch events, /// but not a real press (or hair touch events). /// /// whether or not the TouchModifier is active protected virtual bool IsTouchModifierPressed() { return Input.GetKey(keyMappings["TouchModifier"]); } /// /// whether or not the hair touch modifier is currently pressed /// if so, pressing a key on the keyboard will only emit touch and hair touch events, /// but not a real press. /// /// whether or not the HairTouchModifier is active protected virtual bool IsHairTouchModifierPressed() { return Input.GetKey(keyMappings["HairTouchModifier"]); } /// /// whether or not a button press shall be ignored, e.g. because of the /// use of the touch or hair touch modifier /// /// Returns true if the button press is ignored. protected virtual bool IsButtonPressIgnored() { // button presses shall be ignored if the hair touch or touch modifiers are used return IsHairTouchModifierPressed() || IsTouchModifierPressed(); } /// /// whether or not a button press shall be ignored, e.g. because of the /// use of the touch or hair touch modifier /// /// Returns true if the hair trigger touch should be ignored. protected virtual bool IsButtonHairTouchIgnored() { // button presses shall be ignored if the hair touch or touch modifiers are used return IsTouchModifierPressed() && !IsHairTouchModifierPressed(); } /// /// Gets the state of the given button key mapping for the press type on the controller index. /// /// The index of the controller. /// The key mapping key to check. /// The type of button press to check. /// Returns true if the button state matches the given data. protected virtual bool GetControllerButtonState(uint index, string keyMapping, ButtonPressTypes pressType) { if (pressType == ButtonPressTypes.Touch) { return IsButtonPressed(index, ButtonPressTypes.Press, keyMappings[keyMapping]); } else if (pressType == ButtonPressTypes.TouchDown) { return IsButtonPressed(index, ButtonPressTypes.PressDown, keyMappings[keyMapping]); } else if (pressType == ButtonPressTypes.TouchUp) { return IsButtonPressed(index, ButtonPressTypes.PressUp, keyMappings[keyMapping]); } else if (pressType == ButtonPressTypes.Press) { return !IsButtonPressIgnored() && IsButtonPressed(index, ButtonPressTypes.Press, keyMappings[keyMapping]); } else if (pressType == ButtonPressTypes.PressDown) { return !IsButtonPressIgnored() && IsButtonPressed(index, ButtonPressTypes.PressDown, keyMappings[keyMapping]); } else if (pressType == ButtonPressTypes.PressUp) { return !IsButtonPressIgnored() && IsButtonPressed(index, ButtonPressTypes.PressUp, keyMappings[keyMapping]); } return false; } /// /// checks if the given button (KeyCode) is currently in a specific pressed state (ButtonPressTypes) on the keyboard /// also asserts that button presses are only handled for the currently active controller by comparing the controller indices /// /// unique index of the controller for which the button press is to be checked /// the type of press (up, down, hold) /// the button on the keyboard /// Returns true if the button is being pressed. protected virtual bool IsButtonPressed(uint index, ButtonPressTypes type, KeyCode button) { SetupPlayer(); if (index >= uint.MaxValue) { return false; } if (index == 1) { if (!rightController.Selected) { return false; } } else if (index == 2) { if (!leftController.Selected) { return false; } } else { return false; } switch (type) { case ButtonPressTypes.Press: return Input.GetKey(button); case ButtonPressTypes.PressDown: return Input.GetKeyDown(button); case ButtonPressTypes.PressUp: return Input.GetKeyUp(button); } return false; } /// /// finds the actual controller for the specified hand (identified by name) and returns it /// /// the for which to find the respective controller gameobject /// the gameobject of the actual controller corresponding to the specified hand protected virtual GameObject GetActualController(ControllerHand hand) { GameObject simPlayer = SDK_InputSimulator.FindInScene(); GameObject controller = null; if (simPlayer != null) { switch (hand) { case ControllerHand.Right: controller = simPlayer.transform.Find(RIGHT_HAND_CONTROLLER_NAME).gameObject; break; case ControllerHand.Left: controller = simPlayer.transform.Find(LEFT_HAND_CONTROLLER_NAME).gameObject; break; default: break; } } return controller; } } }