Search Unity

Origami Tutorial : Gaze Gesture Manager : help deconstructing void Start() script

Discussion in 'VR' started by behram, Jun 21, 2016.

  1. behram

    behram

    Joined:
    Jun 21, 2016
    Posts:
    18
    Hello,
    I have the Origami tutorial working but I'm not able to wrap my head around whats happening in the Start() function of the Gaze Gesture Manager script.

    Q: How is public GameObject FocusedObject being used
    Q:How did Unity manage to Divine if FocusedObject was Null or not (it is not being explicitly set afaik)
    Q:What happens when the script runs (via Start() ) the first time
    Q: How is instance = This being used

    Thank you so much for any help.
    Cheers,
    b

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.VR.WSA.Input;
    3.  
    4. public class GazeGestureManager : MonoBehaviour
    5. {
    6.     public static GazeGestureManager Instance { get; private set; }
    7.    
    8.  
    9.     // Represents the hologram that is currently being gazed at.
    10.    
    11.     public GameObject FocusedObject { get; private set; }
    12.  
    13.  
    14.     GestureRecognizer recognizer;
    15.  
    16.     // Use this for initialization
    17.     void Start()
    18.     {
    19.         Instance = this;
    20.  
    21.         // Set up a GestureRecognizer to detect Select gestures.
    22.         recognizer = new GestureRecognizer();
    23.         recognizer.TappedEvent += (source, tapCount, ray) =>
    24.         {
    25.             // Send an OnSelect message to the focused object and its ancestors.
    26.             if (FocusedObject != null)
    27.             {
    28.                 FocusedObject.SendMessageUpwards("OnSelect");
    29.             }
    30.         };
    31.         recognizer.StartCapturingGestures();
    32.     }
    33.  
    34.     // Update is called once per frame
    35.     void Update()
    36.     {
    37.         // I THINK I UNDERSTAND THIS PART
    38.        
    39.  
    40.      
    41.      
    42.  
    43.    
    44.     }
    45. }
     
  2. Unity_Wesley

    Unity_Wesley

    Unity Technologies

    Joined:
    Sep 17, 2015
    Posts:
    558
    Hello,

    It looks like this script is a helper for gaze and gesture management through the apps lifetime.

    Q: How is public GameObject FocusedObject being used
    -This is used to track the current Game Object that the user was looking when a Tapped Event is Fired

    Q:How did Unity manage to Divine if FocusedObject was Null or not (it is not being explicitly set afaik)
    -With the way Tapped Event is setup, every time there is a Air tap from the user it will step through if(FocusedObject!=null) loop. The recognizer is always listening for any registered events once it is started.

    Q:What happens when the script runs (via Start() ) the first time
    -When the start function runs, it sets up the Gesture Recognizer and sets an event for when the user Air taps. The Tapped Event is always listening for a Air tap from the user.

    Q: How is instance = This being used
    Unsure how this is being used, could be used in another script in Microsoft project.

    I would recommend looking at the Microsoft HoloLens support forums, there is a lot of posts and information there to help.

    http://forums.hololens.com/

    Thank you,
    Wesley
     
    behram likes this.
  3. pfreese

    pfreese

    Unity Technologies

    Joined:
    Feb 23, 2015
    Posts:
    85
    This line:
    Code (CSharp):
    1. Instance = this;
    is part of the class' implementation as a singleton. The other part is here:
    Code (CSharp):
    1. public static GazeGestureManager Instance { get; private set; }
    This allows code in other modules to call GazeGestureManager.Instance.SomeMethod() without needing an instance pointer. The idea behind the Singleton pattern is that there is only ever one instance of the class, so it should be accessible globally.
     
    behram likes this.
  4. behram

    behram

    Joined:
    Jun 21, 2016
    Posts:
    18
    Thanks Wesley. Discussing this is helping my understanding of how Unity works as well as how Events work.
    I "think" I am beginning to understand now.

    Correct me if I am wrong on my assumptions below.
    1.Just because something is setup in the Start() function does not mean it will run once and "only" once.
    Events and their handlers once initiated always persist even after Start() is finished.

    2.The very first time the scripts starts the FocusedObject is indeed NULL but then it evaluates to true in the Update() function via RayCast (if an object is hit).

    3.Since the recognizer.TappedEvent is already set in motion it will evaluate to True and send an OnSelect message.

    A singleton it is. Thank you Sir.

    I know unity has a great tutorial on Delegates and Events but I urge the Training team to put some more video tutorials on the topic,especially Lambdas. I am seeing the use of anonymous methods and Lambda's quite a bit when I started to use plugins for Unity.

    Thank you so much Wesley and Pr.Reese I have gained valuable knowledge today :)
    Cheers,
    b
     
  5. Unity_Wesley

    Unity_Wesley

    Unity Technologies

    Joined:
    Sep 17, 2015
    Posts:
    558
    No problem we are always glad to help :)

    Correct me if I am wrong on my assumptions below.
    1.Just because something is setup in the Start() function does not mean it will run once and "only" once.
    Events and their handlers once initiated always persist even after Start() is finished.
    -This is correct in the meaning of once you tell the recognizer to start looking for events it will continue until the stop function is called or it is destroyed.

    2.The very first time the scripts starts the FocusedObject is indeed NULL but then it evaluates to true in the Update() function via RayCast (if an object is hit).
    -Correct

    3.Since the recognizer.TappedEvent is already set in motion it will evaluate to True and send an OnSelect message.
    -Correct, when a Tapped event occurs it will run through the loop an evaluate the true or false and the time stamp of the Tapped Event.
     
    behram likes this.
  6. behram

    behram

    Joined:
    Jun 21, 2016
    Posts:
    18
    Thank you Wesley.

    I want to continue to ask C# related questions (wrt HL & Origami Tutorial ) in this thread so that it clears my understanding of intermediate Unity Scripting and may help someone else who is new to Events,Handlers,etc

    Q:SendMessageUpwards
    SMU will send a message (OnSelect function) to the inspector of all parent objects.
    So for e.g if I was gazing at the Ramp1 object in the Origami collection, the SMU will call the OnSelect function on it's immediate parent (Stage) and also the root (Origami) object.
    If that is true then wont the OnSelect function add a rigidbody to the stage & Origami object ?
    Dont we just need a rigidbody to the spehere.

    Q:BroadcastMessage("OnReset")
    The broadcast message is the most expensive from all three (SMU,SM,BM).
    Does the BM return all objects in the hierarchy return to their initial position individually ?
    Would it not be easier to "just" have the Origami object return to it's initial position since it is the parent of all other objects.

    Q:
    A:Unity HL optimization
    According to the performance recommendation document below,Lambdas are not advised (in Tips for Avoiding allocations section )
    https://developer.microsoft.com/en-us/windows/holographic/performance_recommendations_for_unity

    Does this apply to the Origami collection example or is that tip meant to hold true in another context ?

    B: I read from Simon Jacksons "Mastering Unity 2D Game Development" book that there was a faster version of GetComponent call.
    Instead of using " myScriptRigidBody = collider.GetComponent<Rigidbody>(); "
    Use
    myScriptRigidBody =(Rigidbody2D)GetComponent(typeof(Rigidbody2D));
    Because the GetComponent uses C# generics to determine what type of component you are asking for (it's a two-step process: first, you determine the type and then get the component).

    Phew ! So much to learn.
    Thanks
    b
     
  7. BrandonFogerty

    BrandonFogerty

    Joined:
    Jan 29, 2016
    Posts:
    83
    Hi behram,

    The following are my responses to your questions.

    Question:SendMessageUpwards
    SMU will send a message (OnSelect function) to the inspector of all parent objects.
    So for e.g if I was gazing at the Ramp1 object in the Origami collection, the SMU will call the OnSelect function on it's immediate parent (Stage) and also the root (Origami) object.
    If that is true then wont the OnSelect function add a rigidbody to the stage & Origami object ?
    Dont we just need a rigidbody to the spehere.

    Answer: As you said, SendMessageUpwards will *try* to invoke the "OnSelect" method on all components of all parent game objects. If a component does not implement the OnSelect method, it will be ignored for that component on that game object. The root Origami Collection game object does not have any components that implement the OnSelect method so it is ignored for that game object. The Stage game object is a sibling of the "Sphere1" and "Sphere2" so it will not receive the OnSelect event when the user selects one of the paper balls. As you said, when the user selects a paper ball, we just need to add a rigidbody component to it. However the GazeGestureManager is generic and therefore agnostic to the paper balls and their concrete functionality.


    Question:BroadcastMessage("OnReset")
    The broadcast message is the most expensive from all three (SMU,SM,BM).
    Does the BM return all objects in the hierarchy return to their initial position individually ?
    Would it not be easier to "just" have the Origami object return to it's initial position since it is the parent of all other objects.

    Answer: Other than the direction for method invocation, BroadcastMessage works similarly to SendMessageUpwards. BroadcastMessage will only invoke the "OnReset" method on components that implement the "OnReset" method in child game objects. The only components that implement "OnReset" are the SphereCommands (Paper balls) and the UnderworldReset. The action that happens when OnReset is called depends on the component's OnReset implementation. In this case, the paper balls will reset their position. The UnderworldReset will hide all the origami world game objects. If the balls did not move at all, you could just reset the root origami's position as you suggested. However when the user selects the balls, they fall. Their new position will still be relative to the root origami game object however their position will be different from where they started. For example, if you select a ball and it falls into the underworld, it will still be in the underworld even if you reset the root origami game object's position. That is why you need to reset the ball's position and not the root object.

    Question:
    A:Unity HL optimization
    According to the performance recommendation document below,Lambdas are not advised (in Tips for Avoiding allocations section )
    https://developer.microsoft.com/en-us/windows/holographic/performance_recommendations_for_unity

    Does this apply to the Origami collection example or is that tip meant to hold true in another context ?

    Answer: Good catch. If you are trying to conserve on your memory consumption you should consider limiting your use of lambdas. Instead of a lambda, you can just pass the function name in as a parameter. For example,

    Code (csharp):
    1. delegate void DoSomethingDelegate();
    2.  
    3. void Start()
    4. {
    5.     WhenSomethingHappens(DoSomething);
    6. }
    7.  
    8. void WhenSomethingHappens(DoSomethingDelegate method)
    9. {
    10.     method();
    11. }
    12.  
    13. void DoSomething()
    14. {
    15.     Debug.Log("Hi there!  I did something!");
    16. }


    The Origami tutorial isn't resource intensive so it is alright in that context.


    B: I read from Simon Jacksons "Mastering Unity 2D Game Development" book that there was a faster version of GetComponent call.
    Instead of using " myScriptRigidBody = collider.GetComponent<Rigidbody>(); "
    Use
    myScriptRigidBody =(Rigidbody2D)GetComponent(typeof(Rigidbody2D));
    Because the GetComponent uses C# generics to determine what type of component you are asking for (it's a two-step process: first, you determine the type and then get the component).

    Answer: I do not believe there is any significant performance difference between the 2 GetComponent methods.

    I hope that helps!
     
    behram likes this.
  8. behram

    behram

    Joined:
    Jun 21, 2016
    Posts:
    18
    Wow ! Thank you so much Brandon.
    I am gaining extremely valuable insights into Unity which will hold me in good stead for future development.
    Once again,thank you and the team so much.

    behram
     
  9. BrandonFogerty

    BrandonFogerty

    Joined:
    Jan 29, 2016
    Posts:
    83
    No problem behram. It is my pleasure. We are here to help and we are excited to see what amazing experiences you create!