Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Runtime Inspector and Hierarchy [Open Source]

Discussion in 'Assets and Asset Store' started by yasirkula, Oct 22, 2017.

  1. Mr_Mystery

    Mr_Mystery

    Joined:
    Feb 5, 2018
    Posts:
    12
    @yasirkula Where do you get the gameObjects from the scene? I added a toggle to the HierarchyItemTransform so when I tap on it that respective gameObject in the scene should be toggled on and off. And I'm not using RunTimeInspector.


    Found the fix. There's a BindTo(Transform target) method inside HierarchyItemTransform. You can use that parameter to get the gameObject in the scene.
     
    Last edited: Sep 30, 2019
    yasirkula likes this.
  2. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Yes, and you can use the BoundTransform property to access that Transform at any time.
     
    Mr_Mystery likes this.
  3. aitor_g

    aitor_g

    Joined:
    Feb 20, 2019
    Posts:
    8
    Hi @yasirkula,
    Is there any reason why the light properties are not being exposed on the RuntimeInspector prefab on standalone builds?
    Everything works fine on the editor, when I run my scene with the RuntimeInspector and a Directional Light I can see all the properties of the light, intensity, inner angles and all. EditorLightProperties.jpg
    Then, on the standalone version, this is what is see. RuntimeLightProperties.jpg
    I have tried explicitly telling the internal settings to show all light properties but nothing changes.

    I thought it could be the protection level of the variables but that shouldn't change on editor/run time, right?
    I also thought it could be something to do with inheritance and how the light specialized classes encapsulate the variables ...
    can you shed any light on the issue? (pun intended)
     
    Last edited: Oct 4, 2019
  4. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    This is caused by managed code stripping. If you don't want to preserve all properties of the Light class, then you can simply add dummy calls to the properties of Light that you want to preserve in your scripts. E.g. you can add the following line to preserve
    Light.intensity
    :

    Code (CSharp):
    1. void Start()
    2. {
    3.     if( Time.time < -999f ) // will never happen but will not be stripped
    4.         GetComponent<Light>().intensity = 1;
    5. }
    Alternatively, you can check out the link.xml file format: https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html
     
    aitor_g likes this.
  5. hellstorm

    hellstorm

    Joined:
    Jun 29, 2015
    Posts:
    41
    Greetings! im trying to use this with oculus, i have the canvases setup to use OVRPhysics raycaster, and all other buttons respond, i just Cannot select anything in the runtime hierarchy, the scroll bar and dropdown arrows work tho... there is no highlight and its never selected. i can see it propagate and highlight blue when manually clicking on something in the unity hierarchy, and then use dropdowns and scrolling on the runtime inspector.

    the canvas is also set to a world space


    all i need it to do is select when i click on it. cannot figure out why the scroll and dropdowns work but select doesnt..


    the OVR Raycaster is here :

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using System.Text;
    6. using UnityEngine;
    7. using UnityEngine.UI;
    8. using UnityEngine.EventSystems;
    9. using UnityEngine.Serialization;
    10.  
    11. /// <summary>
    12. /// Extension of GraphicRaycaster to support ray casting with world space rays instead of just screen-space
    13. /// pointer positions
    14. /// </summary>
    15. [RequireComponent(typeof(Canvas))]
    16. public class OVRRaycaster : GraphicRaycaster, IPointerEnterHandler
    17. {
    18.     [Tooltip("A world space pointer for this canvas")]
    19.     public GameObject pointer;
    20.  
    21.     public int sortOrder = 0;
    22.  
    23.     protected OVRRaycaster()
    24.     { }
    25.  
    26.     [NonSerialized]
    27.     private Canvas m_Canvas;
    28.  
    29.     private Canvas canvas
    30.     {
    31.         get
    32.         {
    33.             if (m_Canvas != null)
    34.                 return m_Canvas;
    35.  
    36.             m_Canvas = GetComponent<Canvas>();
    37.             return m_Canvas;
    38.         }
    39.     }
    40.  
    41.     public override Camera eventCamera
    42.     {
    43.         get
    44.         {
    45.             return canvas.worldCamera;
    46.         }
    47.     }
    48.  
    49.     public override int sortOrderPriority
    50.     {
    51.         get
    52.         {
    53.             return sortOrder;
    54.         }
    55.     }
    56.  
    57.     protected override void Start()
    58.     {
    59.         if(!canvas.worldCamera)
    60.         {
    61.             Debug.Log("Canvas does not have an event camera attached. Attaching OVRCameraRig.centerEyeAnchor as default.");
    62.             OVRCameraRig rig = FindObjectOfType<OVRCameraRig>();
    63.             canvas.worldCamera = rig.centerEyeAnchor.gameObject.GetComponent<Camera>();
    64.         }
    65.     }
    66.  
    67.     /// <summary>
    68.     /// For the given ray, find graphics on this canvas which it intersects and are not blocked by other
    69.     /// world objects
    70.     /// </summary>
    71.     [NonSerialized]
    72.     private List<RaycastHit> m_RaycastResults = new List<RaycastHit>();
    73.     private void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList, Ray ray, bool checkForBlocking)
    74.     {
    75.         //This function is closely based on
    76.         //void GraphicRaycaster.Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    77.  
    78.         if (canvas == null)
    79.             return;
    80.  
    81.         float hitDistance = float.MaxValue;
    82.  
    83.         if (checkForBlocking && blockingObjects != BlockingObjects.None)
    84.         {
    85.             float dist = eventCamera.farClipPlane;
    86.  
    87.             if (blockingObjects == BlockingObjects.ThreeD || blockingObjects == BlockingObjects.All)
    88.             {
    89.                 var hits = Physics.RaycastAll(ray, dist, m_BlockingMask);
    90.  
    91.                 if (hits.Length > 0 && hits[0].distance < hitDistance)
    92.                 {
    93.                     hitDistance = hits[0].distance;
    94.                 }
    95.             }
    96.  
    97.             if (blockingObjects == BlockingObjects.TwoD || blockingObjects == BlockingObjects.All)
    98.             {
    99.                 var hits = Physics2D.GetRayIntersectionAll(ray, dist, m_BlockingMask);
    100.  
    101.                 if (hits.Length > 0 && hits[0].fraction * dist < hitDistance)
    102.                 {
    103.                     hitDistance = hits[0].fraction * dist;
    104.                 }
    105.             }
    106.         }
    107.  
    108.         m_RaycastResults.Clear();
    109.  
    110.         GraphicRaycast(canvas, ray, m_RaycastResults);
    111.  
    112.         for (var index = 0; index < m_RaycastResults.Count; index++)
    113.         {
    114.             var go = m_RaycastResults[index].graphic.gameObject;
    115.             bool appendGraphic = true;
    116.  
    117.             if (ignoreReversedGraphics)
    118.             {
    119.                 // If we have a camera compare the direction against the cameras forward.
    120.                 var cameraFoward = ray.direction;
    121.                 var dir = go.transform.rotation * Vector3.forward;
    122.                 appendGraphic = Vector3.Dot(cameraFoward, dir) > 0;
    123.             }
    124.  
    125.             // Ignore points behind us (can happen with a canvas pointer)
    126.             if (eventCamera.transform.InverseTransformPoint(m_RaycastResults[index].worldPos).z <= 0)
    127.             {
    128.                 appendGraphic = false;
    129.             }
    130.  
    131.             if (appendGraphic)
    132.             {
    133.                 float distance = Vector3.Distance(ray.origin, m_RaycastResults[index].worldPos);
    134.  
    135.                 if (distance >= hitDistance)
    136.                 {
    137.                     continue;
    138.                 }
    139.  
    140.                 var castResult = new RaycastResult
    141.                 {
    142.                     gameObject = go,
    143.                     module = this,
    144.                     distance = distance,
    145.                     index = resultAppendList.Count,
    146.                     depth = m_RaycastResults[index].graphic.depth,
    147.  
    148.                     worldPosition = m_RaycastResults[index].worldPos
    149.                 };
    150.                 resultAppendList.Add(castResult);
    151.             }
    152.         }
    153.     }
    154.  
    155.     /// <summary>
    156.     /// Performs a raycast using eventData.worldSpaceRay
    157.     /// </summary>
    158.     /// <param name="eventData"></param>
    159.     /// <param name="resultAppendList"></param>
    160.     public override void Raycast(PointerEventData eventData, List<RaycastResult> resultAppendList)
    161.     {
    162.         if (eventData.IsVRPointer())
    163.         {
    164.             Raycast(eventData, resultAppendList, eventData.GetRay(), true);
    165.         }
    166.     }
    167.     /// <summary>
    168.     /// Performs a raycast using the pointer object attached to this OVRRaycaster
    169.     /// </summary>
    170.     /// <param name="eventData"></param>
    171.     /// <param name="resultAppendList"></param>
    172.     public void RaycastPointer(PointerEventData eventData, List<RaycastResult> resultAppendList)
    173.     {
    174.         if (pointer != null && pointer.activeInHierarchy)
    175.         {
    176.             Raycast(eventData, resultAppendList, new Ray(eventCamera.transform.position, (pointer.transform.position - eventCamera.transform.position).normalized), false);
    177.         }
    178.     }
    179.  
    180.  
    181.     /// <summary>
    182.     /// Perform a raycast into the screen and collect all graphics underneath it.
    183.     /// </summary>
    184.     [NonSerialized]
    185.     static readonly List<RaycastHit> s_SortedGraphics = new List<RaycastHit>();
    186.     private void GraphicRaycast(Canvas canvas, Ray ray, List<RaycastHit> results)
    187.     {
    188.         //This function is based closely on :
    189.         // void GraphicRaycaster.Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List<Graphic> results)
    190.         // But modified to take a Ray instead of a canvas pointer, and also to explicitly ignore
    191.         // the graphic associated with the pointer
    192.  
    193.         // Necessary for the event system
    194.         var foundGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas);
    195.         s_SortedGraphics.Clear();
    196.         for (int i = 0; i < foundGraphics.Count; ++i)
    197.         {
    198.             Graphic graphic = foundGraphics[i];
    199.  
    200.             // -1 means it hasn't been processed by the canvas, which means it isn't actually drawn
    201.             if (graphic.depth == -1 || (pointer == graphic.gameObject))
    202.                 continue;
    203.             Vector3 worldPos;
    204.             if (RayIntersectsRectTransform(graphic.rectTransform, ray, out worldPos))
    205.             {
    206.                 //Work out where this is on the screen for compatibility with existing Unity UI code
    207.                 Vector2 screenPos = eventCamera.WorldToScreenPoint(worldPos);
    208.                 // mask/image intersection - See Unity docs on eventAlphaThreshold for when this does anything
    209.                 if (graphic.Raycast(screenPos, eventCamera))
    210.                 {
    211.                     RaycastHit hit;
    212.                     hit.graphic = graphic;
    213.                     hit.worldPos = worldPos;
    214.                     hit.fromMouse = false;
    215.                     s_SortedGraphics.Add(hit);
    216.                 }
    217.             }
    218.         }
    219.  
    220.         s_SortedGraphics.Sort((g1, g2) => g2.graphic.depth.CompareTo(g1.graphic.depth));
    221.  
    222.         for (int i = 0; i < s_SortedGraphics.Count; ++i)
    223.         {
    224.             results.Add(s_SortedGraphics[i]);
    225.         }
    226.     }
    227.     /// <summary>
    228.     /// Get screen position of worldPosition contained in this RaycastResult
    229.     /// </summary>
    230.     /// <param name="worldPosition"></param>
    231.     /// <returns></returns>
    232.     public Vector2 GetScreenPosition(RaycastResult raycastResult)
    233.     {
    234.         // In future versions of Uinty RaycastResult will contain screenPosition so this will not be necessary
    235.         return eventCamera.WorldToScreenPoint(raycastResult.worldPosition);
    236.     }
    237.  
    238.  
    239.     /// <summary>
    240.     /// Detects whether a ray intersects a RectTransform and if it does also
    241.     /// returns the world position of the intersection.
    242.     /// </summary>
    243.     /// <param name="rectTransform"></param>
    244.     /// <param name="ray"></param>
    245.     /// <param name="worldPos"></param>
    246.     /// <returns></returns>
    247.     static bool RayIntersectsRectTransform(RectTransform rectTransform, Ray ray, out Vector3 worldPos)
    248.     {
    249.         Vector3[] corners = new Vector3[4];
    250.         rectTransform.GetWorldCorners(corners);
    251.         Plane plane = new Plane(corners[0], corners[1], corners[2]);
    252.  
    253.         float enter;
    254.         if (!plane.Raycast(ray, out enter))
    255.         {
    256.             worldPos = Vector3.zero;
    257.             return false;
    258.         }
    259.  
    260.         Vector3 intersection = ray.GetPoint(enter);
    261.  
    262.         Vector3 BottomEdge = corners[3] - corners[0];
    263.         Vector3 LeftEdge = corners[1] - corners[0];
    264.         float BottomDot = Vector3.Dot(intersection - corners[0], BottomEdge);
    265.         float LeftDot = Vector3.Dot(intersection - corners[0], LeftEdge);
    266.         if (BottomDot < BottomEdge.sqrMagnitude && // Can use sqrMag because BottomEdge is not normalized
    267.             LeftDot < LeftEdge.sqrMagnitude &&
    268.                 BottomDot >= 0 &&
    269.                 LeftDot >= 0)
    270.         {
    271.             worldPos = corners[0] + LeftDot * LeftEdge / LeftEdge.sqrMagnitude + BottomDot * BottomEdge / BottomEdge.sqrMagnitude;
    272.             return true;
    273.         }
    274.         else
    275.         {
    276.             worldPos = Vector3.zero;
    277.             return false;
    278.         }
    279.     }
    280.  
    281.  
    282.     struct RaycastHit
    283.     {
    284.         public Graphic graphic;
    285.         public Vector3 worldPos;
    286.         public bool fromMouse;
    287.     };
    288.  
    289.  
    290.     /// <summary>
    291.     /// Is this the currently focussed Raycaster according to the InputModule
    292.     /// </summary>
    293.     /// <returns></returns>
    294.     public bool IsFocussed()
    295.     {
    296.         OVRInputModule inputModule = EventSystem.current.currentInputModule as OVRInputModule;
    297.         return inputModule && inputModule.activeGraphicRaycaster == this;
    298.     }
    299.  
    300.     public void OnPointerEnter(PointerEventData e)
    301.     {
    302.         if (e.IsVRPointer())
    303.         {
    304.             // Gaze has entered this canvas. We'll make it the active one so that canvas-mouse pointer can be used.
    305.             OVRInputModule inputModule = EventSystem.current.currentInputModule as OVRInputModule;
    306.             if(inputModule != null)
    307.             {
    308.                 inputModule.activeGraphicRaycaster = this;
    309.             }
    310.  
    311.         }
    312.     }
    313. }
    314.  



    and the OVR input module , lives on the EventSystem


    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections.Generic;
    4.  
    5. namespace UnityEngine.EventSystems
    6. {
    7.     /// <summary>
    8.     /// VR extension of PointerInputModule which supports gaze and controller pointing.
    9.     /// </summary>
    10.     public class OVRInputModule : PointerInputModule
    11.     {
    12.         [Tooltip("Object which points with Z axis. E.g. CentreEyeAnchor from OVRCameraRig")]
    13.         public Transform rayTransform;
    14.  
    15.         public OVRCursor m_Cursor;
    16.  
    17.         [Tooltip("Gamepad button to act as gaze click")]
    18.         public OVRInput.Button joyPadClickButton = OVRInput.Button.One;
    19.  
    20.         [Tooltip("Keyboard button to act as gaze click")]
    21.         public KeyCode gazeClickKey = KeyCode.Space;
    22.  
    23.         [Header("Physics")]
    24.         [Tooltip("Perform an sphere cast to determine correct depth for gaze pointer")]
    25.         public bool performSphereCastForGazepointer;
    26.  
    27.         [Header("Gamepad Stick Scroll")]
    28.         [Tooltip("Enable scrolling with the right stick on a gamepad")]
    29.         public bool useRightStickScroll = true;
    30.  
    31.         [Tooltip("Deadzone for right stick to prevent accidental scrolling")]
    32.         public float rightStickDeadZone = 0.15f;
    33.  
    34.         [Header("Touchpad Swipe Scroll")]
    35.         [Tooltip("Enable scrolling by swiping the GearVR touchpad")]
    36.         public bool useSwipeScroll = true;
    37.         [Tooltip("Minimum trackpad movement in pixels to start swiping")]
    38.         public float swipeDragThreshold = 2;
    39.         [Tooltip("Distance scrolled when swipe scroll occurs")]
    40.         public float swipeDragScale = 1f;
    41.         /* It's debatable which way left and right are on the Gear VR touchpad since it's facing away from you
    42.          * the following bool allows this to be swapped*/
    43.         [Tooltip("Invert X axis on touchpad")]
    44.         public bool InvertSwipeXAxis = false;
    45.  
    46.  
    47.         // The raycaster that gets to do pointer interaction (e.g. with a mouse), gaze interaction always works
    48.         [NonSerialized]
    49.         public OVRRaycaster activeGraphicRaycaster;
    50.         [Header("Dragging")]
    51.         [Tooltip("Minimum pointer movement in degrees to start dragging")]
    52.         public float angleDragThreshold = 1;
    53.  
    54.         [SerializeField]
    55.         private float m_SpherecastRadius = 1.0f;    
    56.  
    57.  
    58.  
    59.  
    60.  
    61.         // The following region contains code exactly the same as the implementation
    62.         // of StandaloneInputModule. It is copied here rather than inheriting from StandaloneInputModule
    63.         // because most of StandaloneInputModule is private so it isn't possible to easily derive from.
    64.         // Future changes from Unity to StandaloneInputModule will make it possible for this class to
    65.         // derive from StandaloneInputModule instead of PointerInput module.
    66.         //
    67.         // The following functions are not present in the following region since they have modified
    68.         // versions in the next region:
    69.         // Process
    70.         // ProcessMouseEvent
    71.         // UseMouse
    72.         #region StandaloneInputModule code
    73.          private float m_NextAction;
    74.  
    75.         private Vector2 m_LastMousePosition;
    76.         private Vector2 m_MousePosition;
    77.  
    78.         protected OVRInputModule()
    79.         {}
    80.  
    81. #if UNITY_EDITOR
    82.         protected override void Reset()
    83.         {
    84.             allowActivationOnMobileDevice = true;
    85.         }
    86. #endif
    87.  
    88.         [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
    89.         public enum InputMode
    90.         {
    91.             Mouse,
    92.             Buttons
    93.         }
    94.  
    95.         [Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
    96.         public InputMode inputMode
    97.         {
    98.             get { return InputMode.Mouse; }
    99.         }
    100.         [Header("Standalone Input Module")]
    101.         [SerializeField]
    102.         private string m_HorizontalAxis = "Horizontal";
    103.  
    104.         /// <summary>
    105.         /// Name of the vertical axis for movement (if axis events are used).
    106.         /// </summary>
    107.         [SerializeField]
    108.         private string m_VerticalAxis = "Vertical";
    109.  
    110.         /// <summary>
    111.         /// Name of the submit button.
    112.         /// </summary>
    113.         [SerializeField]
    114.         private string m_SubmitButton = "Submit";
    115.  
    116.         /// <summary>
    117.         /// Name of the submit button.
    118.         /// </summary>
    119.         [SerializeField]
    120.         private string m_CancelButton = "Cancel";
    121.  
    122.         [SerializeField]
    123.         private float m_InputActionsPerSecond = 10;
    124.  
    125.         [SerializeField]
    126.         private bool m_AllowActivationOnMobileDevice;
    127.  
    128.         public bool allowActivationOnMobileDevice
    129.         {
    130.             get { return m_AllowActivationOnMobileDevice; }
    131.             set { m_AllowActivationOnMobileDevice = value; }
    132.         }
    133.  
    134.         public float inputActionsPerSecond
    135.         {
    136.             get { return m_InputActionsPerSecond; }
    137.             set { m_InputActionsPerSecond = value; }
    138.         }
    139.  
    140.         /// <summary>
    141.         /// Name of the horizontal axis for movement (if axis events are used).
    142.         /// </summary>
    143.         public string horizontalAxis
    144.         {
    145.             get { return m_HorizontalAxis; }
    146.             set { m_HorizontalAxis = value; }
    147.         }
    148.  
    149.         /// <summary>
    150.         /// Name of the vertical axis for movement (if axis events are used).
    151.         /// </summary>
    152.         public string verticalAxis
    153.         {
    154.             get { return m_VerticalAxis; }
    155.             set { m_VerticalAxis = value; }
    156.         }
    157.  
    158.         public string submitButton
    159.         {
    160.             get { return m_SubmitButton; }
    161.             set { m_SubmitButton = value; }
    162.         }
    163.  
    164.         public string cancelButton
    165.         {
    166.             get { return m_CancelButton; }
    167.             set { m_CancelButton = value; }
    168.         }
    169.  
    170.         public override void UpdateModule()
    171.         {
    172.             m_LastMousePosition = m_MousePosition;
    173.             m_MousePosition = Input.mousePosition;
    174.         }
    175.  
    176.         public override bool IsModuleSupported()
    177.         {
    178.             // Check for mouse presence instead of whether touch is supported,
    179.             // as you can connect mouse to a tablet and in that case we'd want
    180.             // to use StandaloneInputModule for non-touch input events.
    181.             return m_AllowActivationOnMobileDevice || Input.mousePresent;
    182.         }
    183.  
    184.         public override bool ShouldActivateModule()
    185.         {
    186.             if (!base.ShouldActivateModule())
    187.                 return false;
    188.  
    189.             var shouldActivate = Input.GetButtonDown(m_SubmitButton);
    190.             shouldActivate |= Input.GetButtonDown(m_CancelButton);
    191.             shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_HorizontalAxis), 0.0f);
    192.             shouldActivate |= !Mathf.Approximately(Input.GetAxisRaw(m_VerticalAxis), 0.0f);
    193.             shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f;
    194.             shouldActivate |= Input.GetMouseButtonDown(0);
    195.             return shouldActivate;
    196.         }
    197.  
    198.         public override void ActivateModule()
    199.         {
    200.             base.ActivateModule();
    201.             m_MousePosition = Input.mousePosition;
    202.             m_LastMousePosition = Input.mousePosition;
    203.  
    204.             var toSelect = eventSystem.currentSelectedGameObject;
    205.             if (toSelect == null)
    206.                 toSelect = eventSystem.firstSelectedGameObject;
    207.  
    208.             eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData());
    209.         }
    210.  
    211.         public override void DeactivateModule()
    212.         {
    213.             base.DeactivateModule();
    214.             ClearSelection();
    215.         }
    216.  
    217.  
    218.  
    219.         /// <summary>
    220.         /// Process submit keys.
    221.         /// </summary>
    222.         private bool SendSubmitEventToSelectedObject()
    223.         {
    224.             if (eventSystem.currentSelectedGameObject == null)
    225.                 return false;
    226.  
    227.             var data = GetBaseEventData();
    228.             if (Input.GetButtonDown(m_SubmitButton))
    229.                 ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler);
    230.  
    231.             if (Input.GetButtonDown(m_CancelButton))
    232.                 ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler);
    233.             return data.used;
    234.         }
    235.  
    236.         private bool AllowMoveEventProcessing(float time)
    237.         {
    238.             bool allow = Input.GetButtonDown(m_HorizontalAxis);
    239.             allow |= Input.GetButtonDown(m_VerticalAxis);
    240.             allow |= (time > m_NextAction);
    241.             return allow;
    242.         }
    243.  
    244.         private Vector2 GetRawMoveVector()
    245.         {
    246.             Vector2 move = Vector2.zero;
    247.             move.x = Input.GetAxisRaw(m_HorizontalAxis);
    248.             move.y = Input.GetAxisRaw(m_VerticalAxis);
    249.  
    250.             if (Input.GetButtonDown(m_HorizontalAxis))
    251.             {
    252.                 if (move.x < 0)
    253.                     move.x = -1f;
    254.                 if (move.x > 0)
    255.                     move.x = 1f;
    256.             }
    257.             if (Input.GetButtonDown(m_VerticalAxis))
    258.             {
    259.                 if (move.y < 0)
    260.                     move.y = -1f;
    261.                 if (move.y > 0)
    262.                     move.y = 1f;
    263.             }
    264.             return move;
    265.         }
    266.  
    267.         /// <summary>
    268.         /// Process keyboard events.
    269.         /// </summary>
    270.         private bool SendMoveEventToSelectedObject()
    271.         {
    272.             float time = Time.unscaledTime;
    273.  
    274.             if (!AllowMoveEventProcessing(time))
    275.                 return false;
    276.  
    277.             Vector2 movement = GetRawMoveVector();
    278.             // Debug.Log(m_ProcessingEvent.rawType + " axis:" + m_AllowAxisEvents + " value:" + "(" + x + "," + y + ")");
    279.             var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f);
    280.             if (!Mathf.Approximately(axisEventData.moveVector.x, 0f)
    281.                 || !Mathf.Approximately(axisEventData.moveVector.y, 0f))
    282.             {
    283.                 ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler);
    284.             }
    285.             m_NextAction = time + 1f / m_InputActionsPerSecond;
    286.             return axisEventData.used;
    287.         }
    288.  
    289.  
    290.  
    291.  
    292.  
    293.         private bool SendUpdateEventToSelectedObject()
    294.         {
    295.             if (eventSystem.currentSelectedGameObject == null)
    296.                 return false;
    297.  
    298.             var data = GetBaseEventData();
    299.             ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
    300.             return data.used;
    301.         }
    302.  
    303.         /// <summary>
    304.         /// Process the current mouse press.
    305.         /// </summary>
    306.         private void ProcessMousePress(MouseButtonEventData data)
    307.         {
    308.             var pointerEvent = data.buttonData;
    309.             var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
    310.  
    311.             // PointerDown notification
    312.             if (data.PressedThisFrame())
    313.             {
    314.                 pointerEvent.eligibleForClick = true;
    315.                 pointerEvent.delta = Vector2.zero;
    316.                 pointerEvent.dragging = false;
    317.                 pointerEvent.useDragThreshold = true;
    318.                 pointerEvent.pressPosition = pointerEvent.position;
    319.                 if (pointerEvent.IsVRPointer())
    320.                 {
    321.                     pointerEvent.SetSwipeStart(Input.mousePosition);
    322.                 }
    323.                 pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
    324.  
    325.                 DeselectIfSelectionChanged(currentOverGo, pointerEvent);
    326.  
    327.                 // search for the control that will receive the press
    328.                 // if we can't find a press handler set the press
    329.                 // handler to be what would receive a click.
    330.                 var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
    331.  
    332.                 // didnt find a press handler... search for a click handler
    333.                 if (newPressed == null)
    334.                     newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
    335.  
    336.                 // Debug.Log("Pressed: " + newPressed);
    337.  
    338.                 float time = Time.unscaledTime;
    339.  
    340.                 if (newPressed == pointerEvent.lastPress)
    341.                 {
    342.                     var diffTime = time - pointerEvent.clickTime;
    343.                     if (diffTime < 0.3f)
    344.                         ++pointerEvent.clickCount;
    345.                     else
    346.                         pointerEvent.clickCount = 1;
    347.  
    348.                     pointerEvent.clickTime = time;
    349.                 }
    350.                 else
    351.                 {
    352.                     pointerEvent.clickCount = 1;
    353.                 }
    354.  
    355.                 pointerEvent.pointerPress = newPressed;
    356.                 pointerEvent.rawPointerPress = currentOverGo;
    357.  
    358.                 pointerEvent.clickTime = time;
    359.  
    360.                 // Save the drag handler as well
    361.                 pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
    362.  
    363.                 if (pointerEvent.pointerDrag != null)
    364.                     ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
    365.             }
    366.  
    367.             // PointerUp notification
    368.             if (data.ReleasedThisFrame())
    369.             {
    370.                 // Debug.Log("Executing pressup on: " + pointer.pointerPress);
    371.                 ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
    372.  
    373.                 // Debug.Log("KeyCode: " + pointer.eventData.keyCode);
    374.  
    375.                 // see if we mouse up on the same element that we clicked on...
    376.                 var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
    377.  
    378.                 // PointerClick and Drop events
    379.                 if (pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick)
    380.                 {
    381.                     ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
    382.                 }
    383.                 else if (pointerEvent.pointerDrag != null)
    384.                 {
    385.                     ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
    386.                 }
    387.  
    388.                 pointerEvent.eligibleForClick = false;
    389.                 pointerEvent.pointerPress = null;
    390.                 pointerEvent.rawPointerPress = null;
    391.  
    392.                 if (pointerEvent.pointerDrag != null && pointerEvent.dragging)
    393.                     ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
    394.  
    395.                 pointerEvent.dragging = false;
    396.                 pointerEvent.pointerDrag = null;
    397.  
    398.                 // redo pointer enter / exit to refresh state
    399.                 // so that if we moused over somethign that ignored it before
    400.                 // due to having pressed on something else
    401.                 // it now gets it.
    402.                 if (currentOverGo != pointerEvent.pointerEnter)
    403.                 {
    404.                     HandlePointerExitAndEnter(pointerEvent, null);
    405.                     HandlePointerExitAndEnter(pointerEvent, currentOverGo);
    406.                 }
    407.             }
    408.         }
    409. #endregion
    410.         #region Modified StandaloneInputModule methods
    411.  
    412.         /// <summary>
    413.         /// Process all mouse events. This is the same as the StandaloneInputModule version except that
    414.         /// it takes MouseState as a parameter, allowing it to be used for both Gaze and Mouse
    415.         /// pointerss.
    416.         /// </summary>
    417.         private void ProcessMouseEvent(MouseState mouseData)
    418.         {
    419.             var pressed = mouseData.AnyPressesThisFrame();
    420.             var released = mouseData.AnyReleasesThisFrame();
    421.  
    422.             var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
    423.  
    424.             if (!UseMouse(pressed, released, leftButtonData.buttonData))
    425.                 return;
    426.  
    427.             // Process the first mouse button fully
    428.             ProcessMousePress(leftButtonData);
    429.             ProcessMove(leftButtonData.buttonData);
    430.             ProcessDrag(leftButtonData.buttonData);
    431.  
    432.             // Now process right / middle clicks
    433.             ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
    434.             ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
    435.             ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
    436.             ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);
    437.  
    438.             if (!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f))
    439.             {
    440.                 var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
    441.                 ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
    442.             }
    443.         }
    444.  
    445.         /// <summary>
    446.         /// Process this InputModule. Same as the StandaloneInputModule version, except that it calls
    447.         /// ProcessMouseEvent twice, once for gaze pointers, and once for mouse pointers.
    448.         /// </summary>
    449.         public override void Process()
    450.         {
    451.             bool usedEvent = SendUpdateEventToSelectedObject();
    452.  
    453.             if (eventSystem.sendNavigationEvents)
    454.             {
    455.                 if (!usedEvent)
    456.                     usedEvent |= SendMoveEventToSelectedObject();
    457.  
    458.                 if (!usedEvent)
    459.                     SendSubmitEventToSelectedObject();
    460.             }
    461.  
    462.             ProcessMouseEvent(GetGazePointerData());
    463. #if !UNITY_ANDROID
    464.             ProcessMouseEvent(GetCanvasPointerData());
    465. #endif
    466.         }
    467.         /// <summary>
    468.         /// Decide if mouse events need to be processed this frame. Same as StandloneInputModule except
    469.         /// that the IsPointerMoving method from this class is used, instead of the method on PointerEventData
    470.         /// </summary>
    471.        private static bool UseMouse(bool pressed, bool released, PointerEventData pointerData)
    472.         {
    473.             if (pressed || released || IsPointerMoving(pointerData) || pointerData.IsScrolling())
    474.                 return true;
    475.  
    476.             return false;
    477.         }
    478.         #endregion
    479.  
    480.  
    481.         /// <summary>
    482.         /// Convenience function for cloning PointerEventData
    483.         /// </summary>
    484.         /// <param name="from">Copy this value</param>
    485.         /// <param name="to">to this object</param>
    486.         protected void CopyFromTo(OVRPointerEventData @from, OVRPointerEventData @to)
    487.         {
    488.             @to.position = @from.position;
    489.             @to.delta = @from.delta;
    490.             @to.scrollDelta = @from.scrollDelta;
    491.             @to.pointerCurrentRaycast = @from.pointerCurrentRaycast;
    492.             @to.pointerEnter = @from.pointerEnter;
    493.             @to.worldSpaceRay = @from.worldSpaceRay;
    494.         }
    495.         /// <summary>
    496.         /// Convenience function for cloning PointerEventData
    497.         /// </summary>
    498.         /// <param name="from">Copy this value</param>
    499.         /// <param name="to">to this object</param>
    500.         protected new void CopyFromTo(PointerEventData @from, PointerEventData @to)
    501.         {
    502.             @to.position = @from.position;
    503.             @to.delta = @from.delta;
    504.             @to.scrollDelta = @from.scrollDelta;
    505.             @to.pointerCurrentRaycast = @from.pointerCurrentRaycast;
    506.             @to.pointerEnter = @from.pointerEnter;
    507.         }
    508.  
    509.  
    510.         // In the following region we extend the PointerEventData system implemented in PointerInputModule
    511.         // We define an additional dictionary for ray(e.g. gaze) based pointers. Mouse pointers still use the dictionary
    512.         // in PointerInputModule
    513. #region PointerEventData pool
    514.  
    515.         // Pool for OVRRayPointerEventData for ray based pointers
    516.         protected Dictionary<int, OVRPointerEventData> m_VRRayPointerData = new Dictionary<int, OVRPointerEventData>();
    517.  
    518.  
    519.         protected bool GetPointerData(int id, out OVRPointerEventData data, bool create)
    520.         {
    521.             if (!m_VRRayPointerData.TryGetValue(id, out data) && create)
    522.             {
    523.                 data = new OVRPointerEventData(eventSystem)
    524.                 {
    525.                     pointerId = id,
    526.                 };
    527.  
    528.                 m_VRRayPointerData.Add(id, data);
    529.                 return true;
    530.             }
    531.             return false;
    532.         }
    533.  
    534.         /// <summary>
    535.         /// Clear pointer state for both types of pointer
    536.         /// </summary>
    537.         protected new void ClearSelection()
    538.         {
    539.             var baseEventData = GetBaseEventData();
    540.  
    541.             foreach (var pointer in m_PointerData.Values)
    542.             {
    543.                 // clear all selection
    544.                 HandlePointerExitAndEnter(pointer, null);
    545.             }
    546.             foreach (var pointer in m_VRRayPointerData.Values)
    547.             {
    548.                 // clear all selection
    549.                 HandlePointerExitAndEnter(pointer, null);
    550.             }
    551.  
    552.             m_PointerData.Clear();
    553.             eventSystem.SetSelectedGameObject(null, baseEventData);
    554.         }
    555. #endregion
    556.  
    557.         /// <summary>
    558.         /// For RectTransform, calculate it's normal in world space
    559.         /// </summary>
    560.         static Vector3 GetRectTransformNormal(RectTransform rectTransform)
    561.         {
    562.             Vector3[] corners = new Vector3[4];
    563.             rectTransform.GetWorldCorners(corners);
    564.             Vector3 BottomEdge = corners[3] - corners[0];
    565.             Vector3 LeftEdge = corners[1] - corners[0];
    566.             rectTransform.GetWorldCorners(corners);
    567.             return Vector3.Cross(BottomEdge, LeftEdge).normalized;
    568.         }
    569.  
    570.         private readonly MouseState m_MouseState = new MouseState();
    571.  
    572.  
    573.         // The following 2 functions are equivalent to PointerInputModule.GetMousePointerEventData but are customized to
    574.         // get data for ray pointers and canvas mouse pointers.
    575.  
    576.         /// <summary>
    577.         /// State for a pointer controlled by a world space ray. E.g. gaze pointer
    578.         /// </summary>
    579.         /// <returns></returns>
    580.         virtual protected MouseState GetGazePointerData()
    581.         {
    582.             // Get the OVRRayPointerEventData reference
    583.             OVRPointerEventData leftData;
    584.             GetPointerData(kMouseLeftId, out leftData, true );
    585.             leftData.Reset();
    586.  
    587.             //Now set the world space ray. This ray is what the user uses to point at UI elements
    588.             leftData.worldSpaceRay = new Ray(rayTransform.position, rayTransform.forward);
    589.             leftData.scrollDelta = GetExtraScrollDelta();
    590.  
    591.             //Populate some default values
    592.             leftData.button = PointerEventData.InputButton.Left;
    593.             leftData.useDragThreshold = true;
    594.             // Perform raycast to find intersections with world
    595.             eventSystem.RaycastAll(leftData, m_RaycastResultCache);
    596.             var raycast = FindFirstRaycast(m_RaycastResultCache);
    597.             leftData.pointerCurrentRaycast = raycast;
    598.             m_RaycastResultCache.Clear();
    599.  
    600.             m_Cursor.SetCursorRay(rayTransform);
    601.  
    602.             OVRRaycaster ovrRaycaster = raycast.module as OVRRaycaster;
    603.             // We're only interested in intersections from OVRRaycasters
    604.             if (ovrRaycaster)
    605.             {
    606.                 // The Unity UI system expects event data to have a screen position
    607.                 // so even though this raycast came from a world space ray we must get a screen
    608.                 // space position for the camera attached to this raycaster for compatability
    609.                 leftData.position = ovrRaycaster.GetScreenPosition(raycast);
    610.  
    611.                 // Find the world position and normal the Graphic the ray intersected
    612.                 RectTransform graphicRect = raycast.gameObject.GetComponent<RectTransform>();
    613.                 if (graphicRect != null)
    614.                 {
    615.                     // Set are gaze indicator with this world position and normal
    616.                     Vector3 worldPos = raycast.worldPosition;
    617.                     Vector3 normal = GetRectTransformNormal(graphicRect);
    618.                     m_Cursor.SetCursorStartDest(rayTransform.position, worldPos, normal);
    619.                 }
    620.             }
    621.  
    622.             // Now process physical raycast intersections
    623.             OVRPhysicsRaycaster physicsRaycaster = raycast.module as OVRPhysicsRaycaster;
    624.             if (physicsRaycaster)
    625.             {
    626.                 Vector3 position =  raycast.worldPosition;
    627.  
    628.                 if (performSphereCastForGazepointer)
    629.                 {
    630.                     // Here we cast a sphere into the scene rather than a ray. This gives a more accurate depth
    631.                     // for positioning a circular gaze pointer
    632.                     List<RaycastResult> results = new List<RaycastResult>();
    633.                     physicsRaycaster.Spherecast(leftData, results, m_SpherecastRadius);
    634.                     if (results.Count > 0 && results[0].distance < raycast.distance)
    635.                     {
    636.                         position = results[0].worldPosition;
    637.                     }
    638.                 }
    639.  
    640.                 leftData.position = physicsRaycaster.GetScreenPos(raycast.worldPosition);
    641.  
    642.                 m_Cursor.SetCursorStartDest(rayTransform.position, position, raycast.worldNormal);
    643.             }
    644.  
    645.             // Stick default data values in right and middle slots for compatability
    646.  
    647.             // copy the apropriate data into right and middle slots
    648.             OVRPointerEventData rightData;
    649.             GetPointerData(kMouseRightId, out rightData, true );
    650.             CopyFromTo(leftData, rightData);
    651.             rightData.button = PointerEventData.InputButton.Right;
    652.  
    653.             OVRPointerEventData middleData;
    654.             GetPointerData(kMouseMiddleId, out middleData, true );
    655.             CopyFromTo(leftData, middleData);
    656.             middleData.button = PointerEventData.InputButton.Middle;
    657.  
    658.  
    659.             m_MouseState.SetButtonState(PointerEventData.InputButton.Left, GetGazeButtonState(), leftData);
    660.             m_MouseState.SetButtonState(PointerEventData.InputButton.Right, PointerEventData.FramePressState.NotChanged, rightData);
    661.             m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, PointerEventData.FramePressState.NotChanged, middleData);
    662.             return m_MouseState;
    663.         }
    664.  
    665.         /// <summary>
    666.         /// Get state for pointer which is a pointer moving in world space across the surface of a world space canvas.
    667.         /// </summary>
    668.         /// <returns></returns>
    669.         protected MouseState GetCanvasPointerData()
    670.         {
    671.             // Get the OVRRayPointerEventData reference
    672.             PointerEventData leftData;
    673.             GetPointerData(kMouseLeftId, out leftData, true );
    674.             leftData.Reset();
    675.  
    676.             // Setup default values here. Set position to zero because we don't actually know the pointer
    677.             // positions. Each canvas knows the position of its canvas pointer.
    678.             leftData.position = Vector2.zero;
    679.             leftData.scrollDelta = Input.mouseScrollDelta;
    680.             leftData.button = PointerEventData.InputButton.Left;
    681.  
    682.             if (activeGraphicRaycaster)
    683.             {
    684.                 // Let the active raycaster find intersections on its canvas
    685.                 activeGraphicRaycaster.RaycastPointer(leftData, m_RaycastResultCache);
    686.                 var raycast = FindFirstRaycast(m_RaycastResultCache);
    687.                 leftData.pointerCurrentRaycast = raycast;
    688.                 m_RaycastResultCache.Clear();
    689.  
    690.                 OVRRaycaster ovrRaycaster = raycast.module as OVRRaycaster;
    691.                 if (ovrRaycaster) // raycast may not actually contain a result
    692.                 {
    693.                     // The Unity UI system expects event data to have a screen position
    694.                     // so even though this raycast came from a world space ray we must get a screen
    695.                     // space position for the camera attached to this raycaster for compatability
    696.                     Vector2 position = ovrRaycaster.GetScreenPosition(raycast);
    697.  
    698.                     leftData.delta = position - leftData.position;
    699.                     leftData.position = position;
    700.                 }
    701.             }
    702.  
    703.             // copy the apropriate data into right and middle slots
    704.             PointerEventData rightData;
    705.             GetPointerData(kMouseRightId, out rightData, true );
    706.             CopyFromTo(leftData, rightData);
    707.             rightData.button = PointerEventData.InputButton.Right;
    708.  
    709.             PointerEventData middleData;
    710.             GetPointerData(kMouseMiddleId, out middleData, true );
    711.             CopyFromTo(leftData, middleData);
    712.             middleData.button = PointerEventData.InputButton.Middle;
    713.  
    714.             m_MouseState.SetButtonState(PointerEventData.InputButton.Left, StateForMouseButton(0), leftData);
    715.             m_MouseState.SetButtonState(PointerEventData.InputButton.Right, StateForMouseButton(1), rightData);
    716.             m_MouseState.SetButtonState(PointerEventData.InputButton.Middle, StateForMouseButton(2), middleData);
    717.             return m_MouseState;
    718.         }
    719.  
    720.         /// <summary>
    721.         /// New version of ShouldStartDrag implemented first in PointerInputModule. This version differs in that
    722.         /// for ray based pointers it makes a decision about whether a drag should start based on the angular change
    723.         /// the pointer has made so far, as seen from the camera. This also works when the world space ray is
    724.         /// translated rather than rotated, since the beginning and end of the movement are considered as angle from
    725.         /// the same point.
    726.         /// </summary>
    727.         private bool ShouldStartDrag(PointerEventData pointerEvent)
    728.         {
    729.             if (!pointerEvent.useDragThreshold)
    730.                 return true;
    731.  
    732.             if (!pointerEvent.IsVRPointer())
    733.             {
    734.                  // Same as original behaviour for canvas based pointers
    735.                 return (pointerEvent.pressPosition - pointerEvent.position).sqrMagnitude >= eventSystem.pixelDragThreshold * eventSystem.pixelDragThreshold;
    736.             }
    737.             else
    738.             {
    739. #if UNITY_ANDROID && !UNITY_EDITOR  // On android allow swiping to start drag
    740.                 if (useSwipeScroll && ((Vector3)pointerEvent.GetSwipeStart() - Input.mousePosition).magnitude > swipeDragThreshold)
    741.                 {
    742.                     return true;
    743.                 }
    744. #endif
    745.                 // When it's not a screen space pointer we have to look at the angle it moved rather than the pixels distance
    746.                 // For gaze based pointing screen-space distance moved will always be near 0
    747.                 Vector3 cameraPos = pointerEvent.pressEventCamera.transform.position;
    748.                 Vector3 pressDir = (pointerEvent.pointerPressRaycast.worldPosition - cameraPos).normalized;
    749.                 Vector3 currentDir = (pointerEvent.pointerCurrentRaycast.worldPosition - cameraPos).normalized;
    750.                 return Vector3.Dot(pressDir, currentDir) < Mathf.Cos(Mathf.Deg2Rad * (angleDragThreshold));
    751.             }
    752.         }
    753.  
    754.         /// <summary>
    755.         /// The purpose of this function is to allow us to switch between using the standard IsPointerMoving
    756.         /// method for mouse driven pointers, but to always return true when it's a ray based pointer.
    757.         /// All real-world ray-based input devices are always moving so for simplicity we just return true
    758.         /// for them.
    759.         ///
    760.         /// If PointerEventData.IsPointerMoving was virtual we could just override that in
    761.         /// OVRRayPointerEventData.
    762.         /// </summary>
    763.         /// <param name="pointerEvent"></param>
    764.         /// <returns></returns>
    765.         static bool IsPointerMoving(PointerEventData pointerEvent)
    766.         {
    767.             if (pointerEvent.IsVRPointer())
    768.                 return true;
    769.             else
    770.                 return pointerEvent.IsPointerMoving();
    771.         }
    772.  
    773.         protected Vector2 SwipeAdjustedPosition(Vector2 originalPosition, PointerEventData pointerEvent)
    774.         {
    775. #if UNITY_ANDROID && !UNITY_EDITOR
    776.             // On android we use the touchpad position (accessed through Input.mousePosition) to modify
    777.             // the effective cursor position for events related to dragging. This allows the user to
    778.             // use the touchpad to drag draggable UI elements
    779.             if (useSwipeScroll)
    780.             {
    781.                 Vector2 delta =  (Vector2)Input.mousePosition - pointerEvent.GetSwipeStart();
    782.                 if (InvertSwipeXAxis)
    783.                     delta.x *= -1;
    784.                 return originalPosition + delta * swipeDragScale;
    785.             }
    786. #endif
    787.             // If not Gear VR or swipe scroll isn't enabled just return original position
    788.             return originalPosition;
    789.  
    790.         }
    791.  
    792.         /// <summary>
    793.         /// Exactly the same as the code from PointerInputModule, except that we call our own
    794.         /// IsPointerMoving.
    795.         ///
    796.         /// This would also not be necessary if PointerEventData.IsPointerMoving was virtual
    797.         /// </summary>
    798.         /// <param name="pointerEvent"></param>
    799.         protected override void ProcessDrag(PointerEventData pointerEvent)
    800.         {
    801.             Vector2 originalPosition = pointerEvent.position;
    802.             bool moving = IsPointerMoving(pointerEvent);
    803.             if (moving && pointerEvent.pointerDrag != null
    804.                 && !pointerEvent.dragging
    805.                 && ShouldStartDrag(pointerEvent))
    806.             {
    807.                 if (pointerEvent.IsVRPointer())
    808.                 {
    809.                     //adjust the position used based on swiping action. Allowing the user to
    810.                     //drag items by swiping on the GearVR touchpad
    811.                     pointerEvent.position = SwipeAdjustedPosition (originalPosition, pointerEvent);
    812.                 }
    813.                 ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.beginDragHandler);
    814.                 pointerEvent.dragging = true;
    815.             }
    816.  
    817.             // Drag notification
    818.             if (pointerEvent.dragging && moving && pointerEvent.pointerDrag != null)
    819.             {
    820.                 if (pointerEvent.IsVRPointer())
    821.                 {
    822.                     pointerEvent.position = SwipeAdjustedPosition(originalPosition, pointerEvent);
    823.                 }
    824.                 // Before doing drag we should cancel any pointer down state
    825.                 // And clear selection!
    826.                 if (pointerEvent.pointerPress != pointerEvent.pointerDrag)
    827.                 {
    828.                     ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
    829.  
    830.                     pointerEvent.eligibleForClick = false;
    831.                     pointerEvent.pointerPress = null;
    832.                     pointerEvent.rawPointerPress = null;
    833.                 }
    834.                 ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.dragHandler);
    835.             }
    836.         }
    837.  
    838.         /// <summary>
    839.         /// Get state of button corresponding to gaze pointer
    840.         /// </summary>
    841.         /// <returns></returns>
    842.         virtual protected PointerEventData.FramePressState GetGazeButtonState()
    843.         {
    844.             var pressed = OVRInput.GetDown(OVRInput.Button.One) || OVRInput.GetDown(joyPadClickButton) ;
    845.             var released = OVRInput.GetUp(OVRInput.Button.One) || OVRInput.GetUp(joyPadClickButton) ;
    846.  
    847. #if UNITY_ANDROID && !UNITY_EDITOR
    848.             // On Gear VR the mouse button events correspond to touch pad events. We only use these as gaze pointer clicks
    849.             // on Gear VR because on PC the mouse clicks are used for actual mouse pointer interactions.
    850.             pressed |= Input.GetMouseButtonDown(0);
    851.             released |= Input.GetMouseButtonUp(0);
    852. #endif
    853.  
    854.             if (pressed && released)
    855.                 return PointerEventData.FramePressState.PressedAndReleased;
    856.             if (pressed)
    857.                 return PointerEventData.FramePressState.Pressed;
    858.             if (released)
    859.                 return PointerEventData.FramePressState.Released;
    860.             return PointerEventData.FramePressState.NotChanged;
    861.         }
    862.  
    863.         /// <summary>
    864.         /// Get extra scroll delta from gamepad
    865.         /// </summary>
    866.         protected Vector2 GetExtraScrollDelta()
    867.         {
    868.             Vector2 scrollDelta = new Vector2();
    869.             if (useRightStickScroll)
    870.             {
    871.                 Vector2 s = OVRInput.Get(OVRInput.Axis2D.SecondaryThumbstick);
    872.                 if (Mathf.Abs(s.x) < rightStickDeadZone) s.x = 0;
    873.                 if (Mathf.Abs(s.y) < rightStickDeadZone) s.y = 0;
    874.                 scrollDelta = s;
    875.             }
    876.             return scrollDelta;
    877.         }
    878.     };
    879. }
    880.  


    and the OVR gaze pointer is here


    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using UnityEngine.EventSystems;
    5. using UnityEngine.UI;
    6.  
    7. /// <summary>
    8. /// UI pointer driven by gaze input.
    9. /// </summary>
    10. public class OVRGazePointer : OVRCursor {
    11.     private Transform gazeIcon; //the transform that rotates according to our movement
    12.  
    13.     [Tooltip("Should the pointer be hidden when not over interactive objects.")]
    14.     public bool hideByDefault = true;
    15.  
    16.     [Tooltip("Time after leaving interactive object before pointer fades.")]
    17.     public float showTimeoutPeriod = 1;
    18.  
    19.     [Tooltip("Time after mouse pointer becoming inactive before pointer unfades.")]
    20.     public float hideTimeoutPeriod = 0.1f;
    21.  
    22.     [Tooltip("Keep a faint version of the pointer visible while using a mouse")]
    23.     public bool dimOnHideRequest = true;
    24.  
    25.     [Tooltip("Angular scale of pointer")]
    26.     public float depthScaleMultiplier = 0.03f;
    27.  
    28.     public bool matchNormalOnPhysicsColliders;
    29.  
    30.     [Header("PlayMaker Globals")]
    31.     public string[] onShow;
    32.     public string[] onHide;
    33.  
    34.  
    35.  
    36.     /// <summary>
    37.     /// The gaze ray.
    38.     /// </summary>
    39.     public Transform rayTransform;
    40.  
    41.     /// <summary>
    42.     /// Is gaze pointer current visible
    43.     /// </summary>
    44.     public bool hidden { get; private set; }
    45.  
    46.     /// <summary>
    47.     /// Current scale applied to pointer
    48.     /// </summary>
    49.     public float currentScale { get; private set; }
    50.  
    51.     /// <summary>
    52.     /// Current depth of pointer from camera
    53.     /// </summary>
    54.     private float depth;
    55.     private float hideUntilTime;
    56.     /// <summary>
    57.     /// How many times position has been set this frame. Used to detect when there are no position sets in a frame.
    58.     /// </summary>
    59.     private int positionSetsThisFrame = 0;
    60.     /// <summary>
    61.     /// Last time code requested the pointer be shown. Usually when pointer passes over interactive elements.
    62.     /// </summary>
    63.     private float lastShowRequestTime;
    64.     /// <summary>
    65.     /// Last time pointer was requested to be hidden. Usually mouse pointer activity.
    66.     /// </summary>
    67.     private float lastHideRequestTime;
    68.  
    69.     // Optionally present GUI element displaying progress when using gaze-to-select mechanics
    70.     private OVRProgressIndicator progressIndicator;
    71.  
    72.     private static OVRGazePointer _instance;
    73.     public static OVRGazePointer instance
    74.     {
    75.         // If there's no GazePointer already in the scene, instanciate one now.
    76.         get
    77.         {
    78.             if (_instance == null)
    79.             {
    80.                 Debug.Log(string.Format("Instanciating GazePointer", 0));
    81.                 _instance = (OVRGazePointer)GameObject.Instantiate((OVRGazePointer)Resources.Load("Prefabs/GazePointerRing", typeof(OVRGazePointer)));
    82.             }
    83.             return _instance;
    84.         }
    85.          
    86.     }
    87.  
    88.  
    89.     /// <summary>
    90.     /// Used to determine alpha level of gaze cursor. Could also be used to determine cursor size, for example, as the cursor fades out.
    91.     /// </summary>
    92.     public float visibilityStrength
    93.     {
    94.         get
    95.         {
    96.             // It's possible there are reasons to show the cursor - such as it hovering over some UI - and reasons to hide
    97.             // the cursor - such as another input method (e.g. mouse) being used. We take both of these in to account.
    98.          
    99.  
    100.             float strengthFromShowRequest;
    101.             if (hideByDefault)
    102.             {
    103.                 // fade the cursor out with time
    104.                 strengthFromShowRequest =  Mathf.Clamp01(1 - (Time.time - lastShowRequestTime) / showTimeoutPeriod);
    105.             }
    106.             else
    107.             {
    108.                 // keep it fully visible
    109.                 strengthFromShowRequest = 1;
    110.             }
    111.  
    112.             // Now consider factors requesting pointer to be hidden
    113.             float strengthFromHideRequest;
    114.          
    115.             strengthFromHideRequest = (lastHideRequestTime + hideTimeoutPeriod > Time.time) ? (dimOnHideRequest ? 0.1f : 0) : 1;
    116.          
    117.  
    118.             // Hide requests take priority
    119.             return Mathf.Min(strengthFromShowRequest, strengthFromHideRequest);
    120.         }
    121.     }
    122.  
    123.     public float SelectionProgress
    124.     {
    125.         get
    126.         {
    127.             return progressIndicator ? progressIndicator.currentProgress : 0;
    128.         }
    129.         set
    130.         {
    131.             if (progressIndicator)
    132.                 progressIndicator.currentProgress = value;
    133.         }
    134.     }
    135.  
    136.     public void Awake()
    137.     {
    138.         currentScale = 1;
    139.         // Only allow one instance at runtime.
    140.         if (_instance != null && _instance != this)
    141.         {
    142.             enabled = false;
    143.             DestroyImmediate(this);
    144.             return;
    145.         }
    146.  
    147.         _instance = this;
    148.  
    149.         gazeIcon = transform.Find("GazeIcon");
    150.         progressIndicator = transform.GetComponent<OVRProgressIndicator>();
    151.     }
    152.  
    153.     void Update ()
    154.     {
    155.         if (rayTransform == null && Camera.main != null)
    156.             rayTransform = Camera.main.transform;
    157.      
    158.         // Move the gaze cursor to keep it in the middle of the view
    159.         transform.position = rayTransform.position + rayTransform.forward * depth;
    160.  
    161.         // Should we show or hide the gaze cursor?
    162.         if (visibilityStrength == 0 && !hidden)
    163.         {
    164.             Hide();
    165.         }
    166.         else if (visibilityStrength > 0 && hidden)
    167.         {
    168.             Show();
    169.         }
    170.     }
    171.  
    172.     /// <summary>
    173.     /// Set position and orientation of pointer
    174.     /// </summary>
    175.     /// <param name="pos"></param>
    176.     /// <param name="normal"></param>
    177.     public override void SetCursorStartDest(Vector3 _, Vector3 pos, Vector3 normal)
    178.     {
    179.         transform.position = pos;
    180.  
    181.         if (!matchNormalOnPhysicsColliders) normal = rayTransform.forward;
    182.      
    183.         // Set the rotation to match the normal of the surface it's on.
    184.         Quaternion newRot = transform.rotation;
    185.         newRot.SetLookRotation(normal, rayTransform.up);
    186.         transform.rotation = newRot;
    187.  
    188.         // record depth so that distance doesn't pop when pointer leaves an object
    189.         depth = (rayTransform.position - pos).magnitude;
    190.  
    191.         //set scale based on depth
    192.         currentScale = depth * depthScaleMultiplier;
    193.         transform.localScale = new Vector3(currentScale, currentScale, currentScale);
    194.  
    195.         positionSetsThisFrame++;
    196.         RequestShow();
    197.     }
    198.  
    199.     public override void SetCursorRay(Transform ray)
    200.     {
    201.         // We don't do anything here, because we already set this properly by default in Update.
    202.     }
    203.  
    204.     void LateUpdate()
    205.     {
    206.         // This happens after all Updates so we know that if positionSetsThisFrame is zero then nothing set the position this frame
    207.         if (positionSetsThisFrame == 0)
    208.         {
    209.             // No geometry intersections, so gazing into space. Make the cursor face directly at the camera
    210.             Quaternion newRot = transform.rotation;
    211.             newRot.SetLookRotation(rayTransform.forward, rayTransform.up);
    212.             transform.rotation = newRot;
    213.         }
    214.  
    215.         Quaternion iconRotation = gazeIcon.rotation;
    216.         iconRotation.SetLookRotation(transform.rotation * new Vector3(0, 0, 1));
    217.         gazeIcon.rotation = iconRotation;
    218.  
    219.         positionSetsThisFrame = 0;
    220.     }
    221.  
    222.     /// <summary>
    223.     /// Request the pointer be hidden
    224.     /// </summary>
    225.     public void RequestHide()
    226.     {
    227.         if (!dimOnHideRequest)
    228.         {
    229.             Hide();
    230.         }
    231.         lastHideRequestTime = Time.time;
    232.     }
    233.  
    234.     /// <summary>
    235.     /// Request the pointer be shown. Hide requests take priority
    236.     /// </summary>
    237.     public void RequestShow()
    238.     {
    239.         Show();
    240.         lastShowRequestTime = Time.time;
    241.     }
    242.  
    243.  
    244.     // Disable/Enable child elements when we show/hide the cursor. For performance reasons.
    245.     void Hide()
    246.     {
    247.         foreach (Transform child in transform)
    248.         {
    249.             child.gameObject.SetActive(false);
    250.         }
    251.         if (GetComponent<Renderer>())
    252.             GetComponent<Renderer>().enabled = false;
    253.         foreach (string item in onHide)
    254.             PlayMakerFSM.BroadcastEvent(item);
    255.         hidden = true;
    256.  
    257.  
    258.     }
    259.  
    260.     void Show()
    261.     {
    262.         foreach (Transform child in transform)
    263.         {
    264.             child.gameObject.SetActive(true);
    265.         }
    266.         if (GetComponent<Renderer>())
    267.             GetComponent<Renderer>().enabled = true;
    268.         foreach (string item in onShow)
    269.             PlayMakerFSM.BroadcastEvent(item);
    270.         hidden = false;
    271.     }
    272.  
    273. }
    274.  
     
    Last edited: Oct 26, 2019
  6. hellstorm

    hellstorm

    Joined:
    Jun 29, 2015
    Posts:
    41


    thanks for the asset, and any help here if you have the time!
     
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    I somehow missed this post, sorry for the late reply. I think we can focus on the OVRInputModule class to resolve this issue. Please uncomment line 336 and add
    Debug.Log(pointerUpHandler + " " + pointerEvent.pointerPress + " " + pointerEvent.eligibleForClick);
    to line 377 so that we can figure out which UI elements are receiving the OVR input. After applying these changes, try clicking an item in hierarchy and see what is logged in the console.
     
  8. hellstorm

    hellstorm

    Joined:
    Jun 29, 2015
    Posts:
    41
    Pressed:
    True
     

    Attached Files:

    • log.png
      log.png
      File size:
      2.7 KB
      Views:
      430
  9. hellstorm

    hellstorm

    Joined:
    Jun 29, 2015
    Posts:
    41
    when expanding a toggle i get this

    ExpandToggle (UnityEngine.GameObject) ExpandToggle (UnityEngine.GameObject) True
     
  10. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    @yasirkula

    Is there a way to hide things in the hierarchy?
     
  11. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Yes, you can register to RuntimeHierarchy's GameObjectFilter event to achieve this.
     
    All_American likes this.
  12. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    Is there an example of that?
     
  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    There you go:

    Code (CSharp):
    1. runtimeHierarchy.GameObjectFilter = ( Transform obj ) =>
    2. {
    3.     if( obj.CompareTag( "Main Camera" ) )
    4.         return false; // Hide Main Camera from hierarchy
    5.  
    6.     return true;
    7. };
     
    All_American and Marcos-Elias like this.
  14. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    Awesome
     
    yasirkula likes this.
  15. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    What do I do with this? How do I access the RuntimeInspector?
     
  16. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    You have to have some C# scripting knowledge. runtimeHierarchy is a variable in your own script with the following declaration:
    public RuntimeInspectorNamespace.RuntimeHierarchy runtimeHierarchy;
     
  17. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    Yeah, I did that...doesn't work.

    It makes everything hidden.
     
    Last edited: Jan 23, 2020
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Did you change the code in any way?
     
  19. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    Not at all.
     
  20. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    I got it.

    I do not need the "DontDestroyonload" or the color pickers. How can I get to those to put them in the filter?
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    You can access them via
    RuntimeInspectorNamespace.ColorPicker.Instance
    and
    RuntimeInspectorNamespace.ObjectReferencePicker.Instance
    . There is a "ExposeDontDestroyOnLoadScene" property in RuntimeHierarchy's inspector..
     
    All_American likes this.
  22. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
  23. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    @yasirkula

    Is there a reason the "MainCamera" tag on the camera doesn't work to hide it from the hierarchy?

    Everything else is hidden fine but the camera doesn't want to cooperate.
     
  24. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    None that I know of; RuntimeHierarchy has no special code for the main camera.
     
  25. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    Is there a way to go do it by name instead of tag? Nothing I try works for the camera. Everything else is filtered.
     
  26. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    obj.name returns the object's name but it creates garbage at each call, so it is very bad for GC. If you are sure that main camera's tag is set, then I'd recommend you to store the main camera's Transform in a public variable and check if obj == mainCameraTransform.
     
  27. All_American

    All_American

    Joined:
    Oct 14, 2011
    Posts:
    1,528
    I’ll try it.
     
  28. kblood

    kblood

    Joined:
    Jun 20, 2012
    Posts:
    92
    This sure seems awesome. I have been working on modding the game Satellite Reign for a while now, and I have begun debugging the game in runtime as much as possible. I finally began to figure out how to customize its UI, and I have begun to consider making some inspector like UI.

    I googled to try to find out whether others might have done something similar to help do such things at runtime, and this came up. From what I have read it relies on prefabs and such, but browsing through the code, it seems like it should not be much of a problem for me to add this code to one of my Satellite Reign mods and instanciate and create this inspector and hierarchy UI stuff in the game via code... well, it will probably take some time, but it seems like it would be much faster than what I am currently doing. Took me several hours just to get some output of basic UI elements.

    Its a fun challenge to try to edit a Unity game at runtime with the option to add in new code through a mod. I generally like the concept of run-time editors, and this is a nice learning experience I think. Hopefully I can contribute to this with some code when I have begun working with it.

    One possibility I am thinking about exploring is exporting and importing transforms and their settings. Seems like it could be very powerful for making level editors and such.

    You seem to have some deep knowledge about Unity. You mentioned getting an objects name costs memory? Is that a Unity issue? Does it also happen when you call transform.name and.. well .name seems to be on everything in Unity, I am guessing it goes back to the UnityObject and GameObject? I was trying to use reflection to datamine the game, but kept running into problems, so for a while now I have instead been manually coding methods that exports data about in game objects, like transforms, custom game class objects, components and so on.

    Sure is a lot of ways to end up making Unity take up more resources than it ought to. Satellite Reign has ended up being pretty ressource heavy, or at least, something is limitting its framerate. I hope to maybe find out what causes that, although I suspect its not a problem I will be able to solve.

    But what do you think about my idea to implement this, through its code alone? That seems quite possible, right? There is that one third party addon, the color picker, but I should not need that for this, but if I do I guess it is mainly code anyway. I am not sure if I can import textures or images with this code. Well, I am pretty sure it is possible, but just have to figure out a way to do that, without being able to use DLL extensions but only Unity 5.6 code and C# from .Net 3.5. Adds a bit to the challenge, because there sure has been a lot of useful reflection features and such added to C# since.
     
  29. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    As far as I know, the .name memory issue happens on all types of UnityObject (googling "unity .name gc" also supports this claim). But it shouldn't cause continuous framerate or memory issues. It will just trigger the garbage collector more often.

    If you can't include prefabs in your mods, then trying to create the whole UI of this plugin via scripting would be very challenging. You can check if it is possible to load the prefabs via asset bundles. Or, you can give that plugin a try which seems to rely purely on OnGUI, so no prefabs are needed (haven't used it myself, though): https://github.com/ManlyMarco/RuntimeUnityEditor

    It is possible to load images at runtime via Texture2D.LoadImage function.

    Wish you success with your mod!
     
  30. kblood

    kblood

    Joined:
    Jun 20, 2012
    Posts:
    92
    Yes, after getting the full repository and taking a closer look I noticed how many prefabs this uses. I have tried to find a way to load Unity assets at runtime. I really want to try to make a way for that to be possible, but then I first need a way to serialize existing assets write them to a file, maybe a json file, and then a way to load these assets again and that will be tricky since they have to be instantiated, added and all the properties set in the correct order.

    I think that might be possible though, I am considering a reflection system that might be able to check the properties of in game objects and match them to a serialized class version of them in a namespace in the mod and then copy all the properties found on that class from the Unity object.

    Will probably be a bit tedious, but could possibly be a whole lot simpler than manually preparing for every class and property with mapping methods for everything.

    I will take a look at this other runtime editor. That also sounds promising.

    I looked a bit at a prefabs code, and I guess it could be possible to use it in game, but I suspect some of those fileIDs refer to other files and also that this is the new prefab system, so it might not even be possible to use with a game based on Unity 5.6.

    Loading images at runtime is very helpful, that is one thing I have been wanting to do. Could also be nice if I could maybe export and import meshes... I guess that might not actually be that difficult to serialize. I think the structure of a mesh is somewhat simple. But... not sure what I would use it for anyway though, texture and maybe shaders... except I guess shaders wont really be useful without having been compiled.

    Thank you for your help so far. This asset is still overall very interesting, as I might want to use it in Unity projects.

    Edit: Seems the other Inspector tool requires a DLL to be used, which I also do not think will be possible. Well, this has inspired me to get into trying to make some simple in game inspector for the game to help debug at runtime. I will just have to create the UI elements in code. A bit annoying, but using layoutelements, it mostly structures itself anyway.
     
    Last edited: Jan 30, 2020
  31. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    All of my plugins use the old prefab system, so there are no nested prefabs. For runtime mesh support, I'm sure that I've seen some plugins on GitHub. You have to use existing shaders, though. Compiling shaders at runtime is AFAIK not supported. Wish you best luck :D
     
  32. viktorkadza

    viktorkadza

    Joined:
    Sep 4, 2018
    Posts:
    46
    Hi i added [SerializeField] attribute to property and [System.Serializable] to class but still no properties exposed in inspector.

    Code (CSharp):
    1. using RuntimeInspectorNamespace;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.EventSystems;
    6.  
    7.  
    8. [System.Serializable]
    9. public class AplicationSetup : MonoBehaviour
    10. {
    11.  
    12.     [SerializeField]
    13.     public int aplicationFramerate;
    14.     [SerializeField]
    15.     public float timescale;
    16.  
    17.     public RuntimeInspector inspector;
    18.  
    19.     void Awake()
    20.     {
    21.         inspector.Inspect(this);
    22.         Application.targetFrameRate = aplicationFramerate;
    23.         setDragTreshold();
    24.     }
    25.     private void Start()
    26.     {
    27.         Time.timeScale = timescale;
    28.     }
    29.     void setDragTreshold()
    30.     {
    31.         int defaultValue = EventSystem.current.pixelDragThreshold;
    32.         EventSystem.current.pixelDragThreshold =
    33.                 Mathf.Max(
    34.                      defaultValue,
    35.                      (int)(defaultValue * Screen.dpi / 160f));
    36.         Debug.Log(Screen.dpi / 160f);
    37.     }
    38.  
    39.     private void Update()
    40.     {
    41.         Time.timeScale = timescale;
    42.     }
    43.  
    44.  
    45. }
    46.  
     
  33. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Perhaps AplicationSetup.Awake is called before RuntimeInspector.Awake, which means inspector.Inspect(this); getting called before RuntimeInspector getting a chance to initialize itself. Try moving that Inspect line to Start.
     
  34. viktorkadza

    viktorkadza

    Joined:
    Sep 4, 2018
    Posts:
    46
    It inspects the class, but shows no propertys, only the enable toggle.
     
  35. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Is "Expose Public Fields" enabled in RuntimeInspector's Inspector?
     
  36. viktorkadza

    viktorkadza

    Joined:
    Sep 4, 2018
    Posts:
    46
    You right, it was disabled.Thanks for great tool !
     
    yasirkula likes this.
  37. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Version 1.4.53 is now released with a fat release notes:
    • RuntimeHierarchy now uses a recycled list view, i.e. it uses only a few GameObjects to display data in RuntimeHierarchy and reuses them while scrolling the RuntimeHierarchy. It should make browsing large hierarchies much faster (@StarCoop : https://forum.unity.com/threads/run...rarchy-open-source.501220/page-3#post-4278658)
    • Added "Show Horizontal Scrollbar" option to RuntimeHierarchy. Note that only the visible items' width values are used to determine the size of the scrollable area (@eleicht : https://forum.unity.com/threads/runtime-inspector-and-hierarchy-open-source.501220/#post-3476421)
    • Improved UX of RuntimeHierarchy's "Can Reorganize Items" significantly
    • Removed "Debug Mode", "Expose Private Fields", "Expose Public Fields", "Expose Private Properties" and "Expose Public Properties" options from RuntimeInspector. They are now replaced with "Expose Fields" and "Expose Properties" which allow filtering variables via their serializableness. It makes more sense to filter variables this way rather than their visibility since private fields with SerializeField attribute should be in the same category with public fields
    • Added support for Range, TextArea and Multiline attributes (@wxxhrt : https://forum.unity.com/threads/run...rarchy-open-source.501220/page-2#post-3574501)
    • RuntimeInspector fields that are not in view aren't refreshed now, it is more performant and better for GC
    • RuntimeInspector will now try to exclude backing fields from variables list. For each field, if a property with the same name exists in the same class, then the field is assumed backing field and is ignored. This should help reduce duplicate entries in the inspector
    • RuntimeInspector now fetches private fields and properties from base classes, as well, which is the correct behaviour
    • Added Inspected Object Header Visibility to RuntimeInspector: if the inspected object has a collapsible header, determines that header's visibility
    • Color picker and reference picker windows will now inherit the properties of Inspector's canvas to match its size, render mode (Screen Space, World Space) and etc.
    • Color picker is now rendered correctly in World Space canvas render mode
    • Added optional tooltips to RuntimeInspector
    • Added "Label Width Percentage" to UI Skin for modifying the width values of labels in RuntimeInspector (@CabbageCrow : https://forum.unity.com/threads/run...rarchy-open-source.501220/page-3#post-4120036)
    • Added support for Vector2Int, Vector3Int, RectInt and BoundsInt
    • Added a custom drawer for Transform that consists of only Position, Rotation and Scale
    • Numerous bugfixes
    IMPORTANT: Delete the Plugins/RuntimeInspector folder before updating the plugin since some old scripts will otherwise cause compilation errors.
     
  38. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Thanks for the wonderful asset! Is there any way available to only show specific object(s) in the hierarchy instead of full scene hierarchy?
     
  39. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
  40. samueljonasson

    samueljonasson

    Joined:
    Apr 19, 2012
    Posts:
    7
    Thank you for this asset. Quite impressive. When I worked in Processing I used something similar to expose properties in a running application - that could then be saved.
    http://www.sojamo.de/libraries/controlP5/

    I am very interested in using the runtime inspector to update my configuration variables at runtime. I am using inspector.Inspect(config) to display the variables but I can't figure out if I can register OnValueChanged events for each property? Is that possible?
     
  41. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    RuntimeInspector doesn't have any OnValueChanged callbacks. However, as it supports editing properties, the properties' setters can be considered as OnValueChanged. So, if you had
    public int variable;
    in your config, you can add the following property to it:

    Code (CSharp):
    1. public int Variable
    2. {
    3.     get { return variable; }
    4.     set
    5.     {
    6.         if( value != variable )
    7.         {
    8.             variable = value;
    9.             // OnValueChanged logic here
    10.         }
    11.     }
    12. }
    You can then hide the variable field from RuntimeInspector via the "Expose Fields" property or "Hidden Variables": https://github.com/yasirkula/UnityRuntimeInspector/#e1-inspector
     
    samueljonasson likes this.
  42. samueljonasson

    samueljonasson

    Joined:
    Apr 19, 2012
    Posts:
    7
    Thank you. I will look into this approach.
     
  43. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Thanks for the wonderful asset.
    I want to select a specific object and using this
    Code (CSharp):
    1. runtimeHierarchy.Select(selectedObject);
    But it is not selecting the object
    even i tried this
    Code (CSharp):
    1.  
    2. runtimeHierarchy.Refresh();
    3.         runtimeHierarchy.Select(selectedObject);
    4.  
    remember i am returning false
     
    Last edited: May 18, 2020
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    If you are calling this function in Awake, try doing so in Start or in a coroutine with a single
    yield return null;
    before. I'm assuming that there are no error messages in the console.
     
  45. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    No i am not calling it on awak but on a specif event. It was working fine before. let me put it inside a coroutine.
     
  46. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Sorry it didn't work! How to debug it?
     
    Last edited: May 18, 2020
  47. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Can you verify that the object exists in RuntimeHierarchy by expanding its parent objects? Perhaps you're trying to select an object in the Scene but you've disabled "Expose Unity Scenes"?
     
  48. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    By setting true to Expose Unity Scenes property can see the expended view of hierarchy with desired object selection. But i don't want to expose all hierarchy objects. I want to show only single game object for this reason I have did this:
    Code (CSharp):
    1. runtimeHierarchy = GetComponent<RuntimeHierarchy>();
    2.         runtimeHierarchy.AddToPseudoScene("SceneName", displayHirarchyObject);
     
  49. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Object is showing in the hirarchy UI. but not expending according to the selection.
     
  50. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Thanks it is working fine now.