Managing state

Before we can place the bin, we need to have a surface; furthermore, before we can throw paper at the bin, we need to have placed the bin. To capture these dependencies, we will create a script responsible for transitioning the application from one state to the next.

We will create a GameObject that will act as a container for all our scene-wide scripts. Create a new empty GameObject via the GameObject | Create Empty menu. Rename it to Controllers by right-clicking on the newly created GameObject in the project's Hierarchy panel, selecting Rename, and typing in Controllers. This will be the GameObject we attach our controller scripts to.

Now, let's create a script called SceneController that will be responsible for managing the states (scanning, placing, and playing) for this application. With the Controllers GameObject selected, click on the Add Component button that is visible on the Inspector panel and then select the New Script button and enter the name SceneController. Double-click on the SceneController script shown in the Project panel to open it in Visual Studio.

Within our SceneController class, create an enum for the all possible states of your game: scanning the environment, placing the bin, and playing the game:

    public enum State 
    { 
        Scanning, 
        Placing, 
        Playing 
    } 

Add the associated property that will signal a method when updated:

    State _currentState = State.Scanning; 
 
    public State CurrentState 
    { 
        get { return _currentState; } 
        set 
        { 
            _currentState = value; 
            OnStateChanged();  
        } 
    } 
 
    void OnStateChanged() 
    { 
 
    } 

Our OnStateChanged method will be responsible for handling state changes. We need a way to transition from the state scanning to placing; in this context, we consider the scanning to be complete once we have observed enough of the environment to place the bin. There are many ways of quantifying enough; one approach might be determining whether you have enough surface area, or have found enough of a specific type of surface, such as vertical surfaces, but we will keep things simple in this instance and define enough as an elapsed amount of time after starting the scan.

To control the starting and stopping of scanning, we must first be able to communicate to the SpatialMappingManager, which is responsible for managing the scanning. There are many strategies for how components communicate between each other, but a common practice adopted by many Unity developers is to use the Singleton pattern. In the SpatialMappingManager class, add the following code:

    public static SpatialMappingManager SharedInstance 
    { 
        get 
        { 
            if(_sharedInstance == null) 
            { 
                _sharedInstance =  
GameObject.FindObjectOfType<SpatialMappingManager>(); } if(_sharedInstance == null) { GameObject instanceGameObject = new
GameObject(typeof(SpatialMappingManager)); _sharedInstance =
instanceGameObject.AddComponent<SpatialMappingManager>(); } return _sharedInstance; } }
The Singleton pattern is a design pattern that restricts to a single instance of a class. It is often useful when one object is responsible for coordinating actions across a system, and provides a convenient way of messaging between components.

With our static property in place, we now have access to the class SpatialMappingManager from within our SceneController class. Jump back into the SceneController (Script) and make the following amendments:

    public enum State 
    { 
        Scanning, 
        Placing, 
        Playing 
    } 
 
    public float scanningTime = 10f;  
 
    State _currentState = State.Scanning; 
 
    public State CurrentState 
    { 
        get { return _currentState; } 
        set 
        { 
            _currentState = value; 
            OnStateChanged();  
        } 
    } 
 
    void OnStateChanged() 
    { 
        StopAllCoroutines();  
 
        switch (_currentState) 
        { 
            case State.Scanning: 
                StartCoroutine(ScanningStateRoutine()); 
                break; 
            case State.Placing: 
                StartCoroutine(PlacingStateRoutine()); 
                break; 
        } 
 
    } 
 
    void Start() 
    { 
        CurrentState = State.Scanning; 
    } 
 
    IEnumerator ScanningStateRoutine() 
    { 
        SpatialMappingManager.SharedInstance.IsObserving = true; 
        yield return new WaitForSeconds(scanningTime); 
        CurrentState = State.Placing; 
    } 
 
    IEnumerator PlacingStateRoutine() 
    { 
        SpatialMappingManager.SharedInstance.IsObserving = false; 
        SpatialMappingManager.SharedInstance.SurfacesVisible = false;yield return null;         
    } 

We first expose the scanningTime variable, making it available so that it can be easily tweaked from within the editor. This, as the name suggests, determines how long we reside in the scanning state.

Next, we create a switch statement within the OnStateChanged method to handle each state for the scanning and placing states, we spawn a coroutine to manage each independently. As with component communication (and programming in general) there are many alternatives; a similar approach is to embed conditional logic within the Update method. The approach taken is a personal preference and using coroutines allows the clean separation of state flows by encapsulating them in individual methods.

ScanningStateRoutine simply starts scanning by setting the IsObserving property of the SpatialMappingManager to true, and then waits for the specified time assigned to scanningTime before transitioning to the placing state.

The PlacingStateRoutine stops scanning by setting the IsObserving property of the SpatialMappingManager to false as well as hiding the surfaces by setting its SurfaceVisible property to false; next we will implement the components that will allow the user to place the bin, starting with gaze--the topic of the next section.

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

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