Nothing but net - throwing paper

As we did in the previous chapter, we will implement throwing by tracking the user's hands and using the tracked direction and displacement to influence the papers flight path, but unlike the previous chapter, we won't be implementing this from scratch, but we'll  take advantage of a script that comes bundled with HoloTookit, namely, the GestureManager script.

GestureManager encapsulates a lot of the logic for detecting tap and manipulation gestures and managing their state. Here, we are mainly interested in the manipulation gesture. The manipulation gesture is activated when the user holds their finger down and, when activated, the user's hand is tracked with its position being updated and made accessible.

Let's get started by jumping back into the Unity Editor and add this script to the scene. GestureManager requires that GazeManager is attached to the same GameObject. We will attach it to our Gaze GameObject. With the scene open, select the Gaze GameObject from within the Hierarchy panel, click on the Add Component button in the Inspector panel, enter, and select GestureManager to add to the GameObject. To make use of GestureManager, we will implement our own class. Let's do this now. With the Gaze GameObject still selected, click on the Add Component button in the Inspector panel, select New Script, and enter the name PlayerInputController. This script will be responsible for translating the output received from GestureManager into user actions related to our game, such as tossing the paper. Double-click on the PlayerInputController script from within the Project panel to open it in Visual Studio.

Our approach will resemble what we did in the previous chapter, obviously requiring less code because the tracking is now managed by GestureManager, freeing us to concentrate on the application's logic. We will start by registering for the OnManipulationStarted, OnManipulationCompleted, and OnManipulationCanceled events. When we detect a manipulation starting, we will instantiate the paper prefab and start tracking until the gesture is completed or canceled. If canceled, we will simply destroy the instantiated prefab, otherwise we will toss the paper forward in line with the user's hand direction and displacement. Let's start by adding the properties and variables, remembering to include the namespace HoloToolkit.Unity. Within the PlayerInputController class, add the following to the code:

    public GameObject PaperPrefab; 
 
    public Vector3 FingertipsOffset = new Vector3(0, 0.053f, 0.01f); 
 
    GameObject trackedGameObject; 
 
    Vector3 trackingStartPosition = Vector3.zero; 
 
    public bool CanTrack 
    { 
        get 
        { 
            return SceneController.Instance.CurrentState == SceneController.State.Playing;  
        } 
    } 
 
    public bool IsTracking 
    { 
        get 
        { 
            return CanTrack && GestureManager.Instance.ManipulationInProgress; 
        } 
    } 
 

Most of this will look familiar to you, assuming you have read the previous chapter. PaperPrefab is the prefab we will instantiate and throw. trackedGameObject holds reference to the currently tracked object. FingertipsOffset is the offset we apply to the position of the trackedGameObject GameObject when being tracked. We are slightly offsetting the paper from the tracked position because tracking centers at the center of the user's palm, rather than their fingertips, where the user would expect the paper to be held. trackingStartPosition is set when OnManipulationStarted is called and is used to determine how far and what direction the user is trying to throw the paper. The CanTrack and IsTracking properties influence the flow of our code, CanTrack returns true if the application is in a valid state for the user to start tossing paper, while the IsTracking property returns true if we are currently tracking and is used in the Update method when updating the position of trackedGameObject. Let's now turn our attention to the methods that will be responsible for creating, updating, and canceling tracking. Add the following methods to the PlayerInputController class:

    void CreateAndStartTrackingGameObject() 
    { 
        if (trackedGameObject == null) 
        { 
            trackedGameObject = Instantiate(PaperPrefab); 
            trackedGameObject.GetComponent<Rigidbody>().useGravity =  
false; trackedGameObject.GetComponent<Collider>().enabled = false; trackedGameObject.transform.position =
GestureManager.Instance.ManipulationPosition +
Camera.main.transform.TransformVector(FingertipsOffset); trackingStartPosition =
trackedGameObject.transform.position; } } void UpdateTrackedObject() { if (trackedGameObject != null) { trackedGameObject.transform.position =
GestureManager.Instance.ManipulationPosition +
Camera.main.transform.TransformVector(FingertipsOffset); } } void ThrowTrackedGameObject() { trackedGameObject.GetComponent<Rigidbody>().useGravity = true; trackedGameObject.GetComponent<Collider>().enabled = true; trackedGameObject.GetComponent<Rigidbody>().velocity =
velocity; trackedGameObject = null; } void DestoryTrackedGameObject() { GameObject.Destroy(trackedGameObject); trackedGameObject = null; }

We start with CreateAndStartTrackingGameObject; this method is called when the event OnManipulationStarted is fired and is responsible for instantiating PaperPrefab, updating its position and turning off the gravity of the Collider, as we don't want it to react with our environment while being dragged.

The next method, UpdateTrackedGameObject, is called from the Update method and is responsible for updating the instantiated GameObject's position using the ManipulationPosition property of the GestureManager class. ThrowTrackedGameObject is called once the manipulation gesture is completed, signaled by the event OnManipulationCompleted. Here, we are just enabling gravity and the collider, so it interacts to the environment. We will return to this method to add a velocity, allowing the user to toss the paper. The last of these methods is DestoryTrackedGameObject. As you might suspect, this method is called when the event OnManipulationCanceled is fired and simply destroys the currently tracked object.

With these methods in place, let's register the GestureManager events to the appropriate delegates. Within the Start method, add the following code:

    void Start () 
{ GestureManager.Instance.OnManipulationStarted +=
Instance_OnManipulationStarted; GestureManager.Instance.OnManipulationCompleted +=
Instance_OnManipulationCompleted; GestureManager.Instance.OnManipulationCanceled +=
Instance_OnManipulationCanceled; }

Now add the following delegates, wiring up the events to our methods:

void Instance_OnManipulationStarted(UnityEngine.VR.WSA.Input.InteractionSourceKind sourceKind) 
    { 
        if(CanTrack) 
        { 
            CreateAndStartTrackingGameObject(); 
        }          
    } 
 
    void Instance_OnManipulationCompleted(UnityEngine.VR.WSA.Input.InteractionSourceKind sourceKind) 
    { 
        ThrowTrackedGameObject();  
    } 
 
    void Instance_OnManipulationCanceled(UnityEngine.VR.WSA.Input.InteractionSourceKind sourceKind) 
    { 
        DestoryTrackedGameObject();  
    } 

No surprises here; we are simply calling the appropriate method for each of the events. With this in place, we almost have everything in place to start tracking. The last method we need to wire up is UpdateTrackedGameObject. This will be called from within the Update method. Add the following to the Update method:

    void Update () { 
        if (IsTracking) 
        { 
            UpdateTrackedGameObject();  
        } 
   } 

Now is a good time to stop and test out tracking, but before we test, we first need to wire up the paper prefab to  PlayerInputController. Jump back into the Editor and select the Gaze GameObject from the Hierarchy panel. Now, from the Project panel's search bar, enter in CrumbledPaper and drag the prefab onto the Paper Prefab field of PlayerInputController in the Inspector panel. Once finished, launch the Build Settings dialog by selecting the menu item File | Build Settings and click on Build button to build the project.

Our final task is to implement tossing. Similar to the previous chapter, we will fake this using trial and error. Back within Visual Studio, make the following amendments to ThrowTrackedGameObject of the PlayerInputController class:

    void ThrowTrackedGameObject() 
    { 
 
        const float minVelocity = 0.09f; 
        const float maxVelocity = 0.3f; 
 
        Vector3 displacement = trackedGameObject.transform.position -  
trackingStartPosition; Vector3 direction = displacement.normalized; Vector3 velocity = Camera.main.transform.forward * 0.2f; if(displacement.magnitude > minVelocity) { velocity += Camera.main.transform.forward * 2.5f; velocity += Mathf.Min(maxVelocity, displacement.magnitude /
maxVelocity) * direction * 4.0f; } trackedGameObject.GetComponent<Rigidbody>().useGravity = true; trackedGameObject.GetComponent<Collider>().enabled = true; trackedGameObject.GetComponent<Rigidbody>().velocity =
velocity; trackedGameObject = null; }

As we did in the previous chapter, we are influencing the user's throw based on how far they have moved their hand after initiating the gesture. In this example, we only apply significant velocity if the user has moved their hands beyond a preset threshold. If this distance is satisfied, we add a default velocity based on the user's facing direction along with some additional force based on the direction and distance the user's hand has moved while being tracked. With this method now complete, this concludes this chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.218.184