środa, 15 marca 2017

[DSP2017] 6# Holowizja - strzały słowem i… reset

Mieliśmy już sterowanie hologramem za pomocą spojrzenia i gestów z użyciem dłoni. Dziś pora na komendy wydawane głosowo.

Tradycyjnie już najpierw pobawiłem się tutorialami Holograms 101E: Introduction with Emulator (w zakresie głosu) oraz Holograms 212: Voice. Szkoda jedynie że bazują na początkowej wersji Holo toolkita, ale poza tym są najprawdę niezłe. W pierwszym mamy wydawanie komend głosowych przedmiotom z focusem (na które się wpatrujemy), jak również komend ogólnych do wszystkiego. W drugim momentami mamy już niemal odlot. Zaczyna się od zmiany ikony kursora na mikrofon i wyświetlania komend w celach informacyjnych, a potem trafiamy na… nagrywanie naszego głosu do zegarka kosmity (niczym jak do szafy w filmie “Miś”), dyktowanie tekstu czy otworzenie plecaka i kolorowaniu przedmiotów w powietrzu za pomocą komend zdefiniowanych w oparciu o reguły gramatyki. Co prawda techniczne możliwości w zakresie głosu osobom obeznanym w aplikacjach uniwersalnych Windows 10 mogą wydać się nawet dość typowe, ale scenaria i muzyka robią już swoje…

Emulator wspiera mikrofon, więc zabawa dostępna dla każdego. Przystępując do praktyki popatrzyłem sobie na testowe sceny do input-u w najnowszym Holo toolkicie. Znalazłem tam komendy wykonywane przez wskazane przedmioty (focus lub zaznaczenie) oraz komendy ogólne.

Przerobiłem poprzedni projekt HoloVision4 na obecny HoloVision5 w następujący sposób:

1. Przesunąłem sześcian na bok i dodałem kulę (sferę). Dodałem też dodatkowe “game” obiekty w celach grupujących i/lub do trzymania skryptów. Hierarchia sceny przedstawia się teraz następująco:

image

2.  Do obiektu SpeechInputSource dodałem skrypt SpeechInputSource (z HoloToolkit/Input/Scripts/Voice) i zdefiniowałem na nim dwie komendy głosowe “Shoot Down” oraz “Reset All”. Pierwsza spowoduje upadek wskazanego przedmiotu na płaszczyznę (poprzez dodanie do niego grawitacji jak ostatnio), druga zaś będzie skierowana ogólnie i ma powodować przywrócenie sceny do początkowego stanu.

image

3.  Do obiektu Items (trzymającego w sobie sześcian i kulę) dodaję skrypt SetGlobalListener (z HoloToolkit/Input/Scripts/SetGlobalListener) oraz nowo stworzony, własny skrypt ItemGlobalKeywords (w Assets/Scripts).

image

Skrypt ItemGlobalKeywords zapamiętuje początkowe położenia i rotacje dzieci elementu, do którego jest przypięty (w naszym przypadku będą to sześcian i kula). Jeśli zostanie odebrana komenda “Reset All”, to następuje przywracanie początkowych ustawień. Całość przedstawia się następująco:

using HoloToolkit.Unity.InputModule;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ItemGlobalKeywords : MonoBehaviour, ISpeechHandler
{
    private Vector3[] cachedChildPositions;
    private Quaternion[] cachedChildRotations;
    private Renderer[] childRenderers;

    private void Awake()
    {
        childRenderers = GetComponentsInChildren<Renderer>();
        if (childRenderers != null && childRenderers.Length > 0)
        {
            cachedChildPositions = new Vector3[childRenderers.Length];
            cachedChildRotations = new Quaternion[childRenderers.Length];

            for (int i = 0; i < childRenderers.Length; i++)
            {
                cachedChildPositions[i] = childRenderers[i].transform.localPosition;
                cachedChildRotations[i] = childRenderers[i].transform.rotation;
            }
        }
    }

    public void OnSpeechKeywordRecognized(SpeechKeywordRecognizedEventData eventData)
    {
        switch (eventData.RecognizedText.ToLower())
        {
            case "reset all":
                if (childRenderers != null && childRenderers.Length > 0 &&
                    cachedChildPositions != null && cachedChildPositions.Length == childRenderers.Length &&
                    cachedChildRotations != null && cachedChildRotations.Length == childRenderers.Length)
                {
                    for (int i = 0; i < childRenderers.Length; i++)
                    {
                        var rigidbody = childRenderers[i].GetComponent<Rigidbody>();
                        if (rigidbody != null)
                        {
                            DestroyImmediate(rigidbody);
                        }

                        childRenderers[i].transform.localPosition = cachedChildPositions[i];
                        childRenderers[i].transform.rotation = cachedChildRotations[i];
                    }
                }
                break;
        }
    }

    private void OnDestroy()
    {
        for (int i = 0; i < childRenderers.Length; i++)
        {
            DestroyImmediate(childRenderers[i]);
        }
    }
}

4. Do obiektów Cube i Sphere podpinam nowo stworzony skrypt o nazwie ItemKeywords. Jego zadaniem jest dodanie grawitacji do obiektu, jeśli zostanie rozpoznana komenda “Shoot down”. Realizuje to poniższy kod:

using HoloToolkit.Unity.InputModule;
using UnityEngine;

[RequireComponent(typeof(Renderer))]
public class ItemKeywords : MonoBehaviour, ISpeechHandler
{
    public void OnShoot()
    {
        if (!this.GetComponent<Rigidbody>())
        {
            var rigidbody = this.gameObject.AddComponent<Rigidbody>();
            rigidbody.collisionDetectionMode = CollisionDetectionMode.Continuous;
        }
    }

    public void OnSpeechKeywordRecognized(SpeechKeywordRecognizedEventData eventData)
    {
        switch (eventData.RecognizedText.ToLower())
        {
            case "shoot down":
                OnShoot();
                break;
        }
    }
}

Eksportujemy jak zawsze do Visual Studio. Aha pamiętajmy o włączeniu mikrofonu w Capabilities. W tym celu wchodzimy w Edit > Project Settings > Player i na zakładce Windows Store szukamy sekcji Publishing Settings > Capabilities.

image

Odpalamy!

Wskazuję kursorem sześcian. Mówię “Shoot down”.

shot1

Buch! Teraz strzelam do kuli.

shot2

Po nakierowaniu wzroku (kursora) na kulę i wypowiedzeniu “Shoot down” również ona opada.

shot3

Jak chcemy zacząć zabawę od początku, zawsze możemy powiedzieć “Reset all”. Sześcian i kula wylądują z powrotem na swoich początkowych położeniach w powietrzu i znów będzie można sobie do nich postrzelać.

Życzę miłej zabawy i do zobaczenia w następnym odcinku.

Brak komentarzy: