HoloLens (1.ª geração) e Azure 309: Application Insights

Nota

Os tutoriais Mixed Reality Academy foram concebidos com o HoloLens (1.ª geração) e Mixed Reality Headsets Envolventes em mente. Como tal, consideramos importante deixar estes tutoriais em vigor para os programadores que ainda estão à procura de orientação no desenvolvimento desses dispositivos. Estes tutoriais não serão atualizados com os conjuntos de ferramentas ou interações mais recentes que estão a ser utilizados para HoloLens 2. Serão mantidas para continuarem a trabalhar nos dispositivos suportados. Haverá uma nova série de tutoriais que serão publicados no futuro que demonstrarão como desenvolver para HoloLens 2. Este aviso será atualizado com uma ligação para esses tutoriais quando forem publicados.

O ecrã de boas-vindas do tutorial da Academia Mixed Reality.

Neste curso, irá aprender a adicionar capacidades do Application Insights a uma aplicação de realidade mista, utilizando a API do Aplicação Azure Insights para recolher análises sobre o comportamento do utilizador.

O Application Insights é um serviço Microsoft que permite aos programadores recolher análises das suas aplicações e geri-la a partir de um portal fácil de utilizar. A análise pode ser qualquer coisa, desde o desempenho até às informações personalizadas que gostaria de recolher. Para obter mais informações, visite a página do Application Insights.

Depois de concluir este curso, terá uma aplicação de headset envolvente de realidade mista, que poderá fazer o seguinte:

  1. Permitir que o utilizador olhe e mova-se numa cena.
  2. Acione o envio de análises para o Serviço do Application Insights com o Gaze e a Proximidade com objetos no local.
  3. A aplicação também irá chamar o Serviço, obtendo informações sobre que objeto foi mais abordado pelo utilizador, nas últimas 24 horas. Esse objeto irá alterar a cor para verde.

Este curso irá ensiná-lo a obter os resultados do Serviço Application Insights numa aplicação de exemplo baseada no Unity. Cabe-lhe a si aplicar estes conceitos a uma aplicação personalizada que possa estar a criar.

Suporte de dispositivos

Curso HoloLens Headsets envolventes
MR e Azure 309: Application Insights ✔️ ✔️

Nota

Embora este curso se centre principalmente em headsets envolventes (VR) Windows Mixed Reality, também pode aplicar o que aprendeu neste curso para Microsoft HoloLens. À medida que acompanha o curso, verá notas sobre quaisquer alterações que possa ter de utilizar para suportar o HoloLens. Ao utilizar o HoloLens, poderá notar algum eco durante a captura de voz.

Pré-requisitos

Nota

Este tutorial foi concebido para programadores com experiência básica com o Unity e C#. Tenha também em atenção que os pré-requisitos e as instruções escritas neste documento representam o que foi testado e verificado no momento da escrita (julho de 2018). Pode utilizar o software mais recente, conforme listado no artigo Instalar as ferramentas , embora não se deva presumir que as informações neste curso corresponderão perfeitamente ao que irá encontrar no software mais recente do que o que está listado abaixo.

Recomendamos o seguinte hardware e software para este curso:

Antes de começar

Para evitar problemas ao criar este projeto, é altamente sugerido que crie o projeto neste tutorial numa pasta raiz ou de raiz próxima (os caminhos de pasta longos podem causar problemas no tempo de compilação).

Aviso

Tenha em atenção que os dados que vão para o Application Insights demoram tempo, por isso, seja paciente. Se quiser verificar se o Serviço recebeu os seus dados, consulte o Capítulo 14, que lhe mostrará como navegar no portal.

Capítulo 1 - Portal do Azure

Para utilizar o Application Insights, terá de criar e configurar um Serviço do Application Insights no portal do Azure.

  1. Inicie sessão no Portal do Azure.

    Nota

    Se ainda não tiver uma conta do Azure, terá de criar uma. Se estiver a seguir este tutorial numa situação de sala de aula ou laboratório, peça ajuda ao seu instrutor ou a um dos tutores para configurar a sua nova conta.

  2. Depois de iniciar sessão, clique em Novo no canto superior esquerdo, procure Application Insights e clique em Enter.

    Nota

    A palavra Novo pode ter sido substituída por Criar um recurso, em portais mais recentes.

    Captura de ecrã a mostrar o Portal do Azure, o Insight está realçado no painel Tudo.

  3. A nova página à direita irá fornecer uma descrição do serviço Aplicação Azure Insights. Na parte inferior esquerda desta página, selecione o botão Criar para criar uma associação com este Serviço.

    Captura de ecrã do ecrã Do Application Insights, Criar está realçado.

  4. Depois de clicar em Criar:

    1. Insira o Nome pretendido para esta instância de Serviço.

    2. Como Tipo de Aplicação, selecione Geral.

    3. Selecione uma Subscrição adequada.

    4. Escolha um Grupo de Recursos ou crie um novo. Um grupo de recursos fornece uma forma de monitorizar, controlar o acesso, aprovisionar e gerir a faturação de uma coleção de recursos do Azure. É recomendado manter todos os Serviços do Azure associados a um único projeto (por exemplo, como estes cursos) num grupo de recursos comum).

      Se quiser ler mais sobre os Grupos de Recursos do Azure, veja o artigo do grupo de recursos.

    5. Selecione uma Localização.

    6. Também terá de confirmar que compreendeu os Termos e Condições aplicados a este Serviço.

    7. Selecione Criar.

      Captura de ecrã da janela do Application Insights. O nome e o tipo de aplicação estão realçados.

  5. Depois de clicar em Criar, terá de aguardar pela criação do Serviço, o que poderá demorar um minuto.

  6. Será apresentada uma notificação no portal assim que a instância do Serviço for criada.

    Captura de ecrã a mostrar uma parte do friso do menu, o ícone de notificação está realçado.

  7. Selecione as notificações para explorar a nova instância do Serviço.

    Captura de ecrã a mostrar a caixa de diálogo Implementação concluída com êxito, Ir para recurso realçado.

  8. Clique no botão Ir para recurso na notificação para explorar a nova instância do Serviço. Será levado para a nova instância do Serviço Application Insights .

    Captura de ecrã a mostrar a instância do Serviço Application Insights onde o nome da instância é MyNewInsight.

    Nota

    Mantenha esta página Web aberta e fácil de aceder. Irá voltar aqui frequentemente para ver os dados recolhidos.

    Importante

    Para implementar o Application Insights, terá de utilizar três (3) valores específicos: Chave de Instrumentação, ID da Aplicação e Chave de API. Abaixo, verá como obter estes valores a partir do seu Serviço. Certifique-se de que anota estes valores numa página do Bloco de Notas em branco, uma vez que irá utilizá-los em breve no seu código.

  9. Para localizar a Chave de Instrumentação, terá de deslocar para baixo a lista de Funções de serviço e selecionar Propriedades, o separador apresentado irá revelar a Chave de Serviço.

    Captura de ecrã a mostrar as funções do serviço, As propriedades estão realçadas na secção Configurar e a Chave de Instrumentação está realçada no painel principal.

  10. Um pouco abaixo de Propriedades, encontrará o Acesso à API, no qual tem de clicar. O painel à direita irá fornecer o ID da Aplicação da sua aplicação.

    Captura de ecrã a mostrar as funções do serviço, A P I Access está realçada. A opção Criar Uma Chave P I e ID da Aplicação estão realçadas no painel principal.

  11. Com o painel ID da Aplicação ainda aberto, clique em Criar Chave de API, que abrirá o painel Criar chave de API .

    Captura de ecrã a mostrar o painel criar uma tecla P I.

  12. No painel Criar chave de API agora aberto, escreva uma descrição e marque as três caixas.

  13. Clique em Gerar Chave. A chave de API será criada e apresentada.

    Captura de ecrã a mostrar o painel Criar uma chave P I com as novas informações da chave de serviço.

    Aviso

    Esta é a única altura em que a Sua Chave de Serviço será apresentada, por isso, certifique-se de que efetua uma cópia da mesma agora.

Capítulo 2 - Configurar o projeto do Unity

Segue-se uma configuração típica para programar com a realidade mista e, como tal, é um bom modelo para outros projetos.

  1. Abra o Unity e clique em Novo.

    Captura de ecrã da janela Projetos do Unity. Não são apresentadas informações do projeto.

  2. Agora, terá de fornecer um nome do Projeto do Unity, inserir MR_Azure_Application_Insights. Certifique-se de que o Modelo está definido como 3D. Defina a Localização para um local adequado para si (lembre-se de que é melhor aproximar-se dos diretórios de raiz). Em seguida, clique em Criar projeto.

    Captura de ecrã a mostrar a janela Novos projetos do Unity, com as informações do projeto.

  3. Com o Unity aberto, vale a pena verificar se o Editor de Scripts predefinido está definido como Visual Studio. Aceda a Editar > Preferências e, em seguida, a partir da nova janela, navegue para Ferramentas Externas. Altere o Editor de Scripts Externos para o Visual Studio 2017. Feche a janela Preferências .

    Captura de ecrã a mostrar que o Visual Studio está configurado como editor de scripts externos.

  4. Em seguida, aceda a Definições de Compilação de Ficheiros > e mude a plataforma para Plataforma Universal do Windows, clicando no botão Mudar de Plataforma.

    Captura de ecrã a mostrar a janela Definições de Compilação, com a lista De seleção da plataforma. Plataforma Universal do Windows está selecionado.

  5. Aceda a Definições de Compilação de Ficheiros > e certifique-se de que:

    1. O Dispositivo de Destino está definido como Qualquer dispositivo

      Para o Microsoft HoloLens, defina Dispositivo de Destino como HoloLens.

    2. O Tipo de Compilação está definido como D3D

    3. O SDK está definido como Instalado mais recentemente

    4. Compilar e Executar está definido como Computador Local

    5. Guarde a cena e adicione-a à compilação.

      1. Para tal, selecione Adicionar Cenas Abertas. Será apresentada uma janela guardar.

        Captura de ecrã a mostrar a janela Definições de Compilação, a opção Adicionar Cenas Abertas está selecionada.

      2. Crie uma nova pasta para esta pasta e qualquer cenário futuro e, em seguida, clique no botão Nova pasta , para criar uma nova pasta, atribua-lhe o nome Cenas.

        Captura de ecrã da janela Guardar Cena, a pasta Cenas está selecionada.

      3. Abra a pasta Cenas recém-criada e, em seguida, no campo Nome do ficheiro : texto, escreva ApplicationInsightsScene e, em seguida, clique em Guardar.

        Captura de ecrã a mostrar a janela Guardar Cena com o nome do ficheiro introduzido.

  6. As restantes definições, em Definições de Compilação, devem ser deixadas como predefinição por agora.

  7. Na janela Definições de Compilação, selecione Definições do Leitor. Esta ação abrirá o painel relacionado no espaço onde o Inspetor está localizado.

    Captura de ecrã do separador Inspetor a mostrar as Definições do Leitor.

  8. Neste painel, é necessário verificar algumas definições:

    1. No separador Outras Definições :

      1. A Versão do Runtime de Scripting deve ser Experimental (.NET 4.6 Equivalente), o que irá acionar a necessidade de reiniciar o Editor.

      2. O Back-end de Scripting deve ser .NET

      3. O Nível de Compatibilidade de API deve ser .NET 4.6

      Captura de ecrã do separador Inspetor a mostrar os detalhes na secção de configuração de Outras Definições.

    2. No separador Definições de Publicação , em Capacidades, verifique:

      • InternetClient

        Captura de ecrã da lista Capacidades. O cliente da Internet está selecionado.

    3. Mais abaixo no painel, em Definições XR (encontradas abaixo das Definições de Publicação), assinale Realidade Virtual Suportada, certifique-se de que o SDK Windows Mixed Reality é adicionado.

      Captura de ecrã a mostrar a secção Definições de X R, a opção Realidade Virtual Suportada está selecionada.

  9. De volta às Definições de Compilação, os Projetos C# do Unity já não estão desativados; marque a caixa de verificação junto a esta opção.

  10. Feche a janela Definições de Compilação.

  11. Guarde o Seu Cenário e Projeto (CENA DE GRAVAÇÃO DE FICHEIRO>/PROJETO GUARDAR FICHEIRO>).

Capítulo 3 - Importar o pacote do Unity

Importante

Se quiser ignorar os componentes da Configuração do Unity deste curso e continuar diretamente para o código, pode transferir este Azure-MR-309.unitypackage, importá-lo para o seu projeto como um Pacote Personalizado. Isto também conterá as DLLs do próximo Capítulo. Após a importação, continue a partir do Capítulo 6.

Importante

Para utilizar o Application Insights no Unity, tem de importar a DLL para o mesmo, juntamente com a DLL newtonsoft. Atualmente, existe um problema conhecido no Unity que requer que os plug-ins sejam reconfigurados após a importação. Estes passos (4 a 7 nesta secção) deixarão de ser necessários depois de o erro ter sido resolvido.

Para importar o Application Insights para o seu próprio projeto, certifique-se de que transferiu o ".unitypackage", que contém os plug-ins. Em seguida, faça o seguinte:

  1. Adicione the.unitypackage** ao Unity com a opção > de menu Pacote Personalizado importar recursos>.

  2. Na caixa Importar Pacote do Unity que é apresentada, certifique-se de que está selecionado tudo em (e incluindo) Plug-ins .

    Captura de ecrã da caixa de diálogo Importar Pacote do Unity a mostrar todos os itens selecionados.

  3. Clique no botão Importar para adicionar os itens ao seu projeto.

  4. Aceda à pasta Informações em Plug-ins na vista Projeto e selecione apenas os seguintes plug-ins:

    • Microsoft.ApplicationInsights

    Captura de ecrã do painel Projeto, a pasta Informações está aberta.

  5. Com este plug-in selecionado, certifique-se de que Qualquer Plataforma está desmarcada e, em seguida, certifique-se de que o WSAPlayer também está desmarcado e, em seguida, clique em Aplicar. Fazê-lo é apenas para confirmar que os ficheiros estão configurados corretamente.

    Captura de ecrã do painel Inspetor a mostrar Editor e Autónomo selecionados.

    Nota

    Marcando os plug-ins como este, configura-os para serem utilizados apenas no Editor do Unity. Existe um conjunto diferente de DLLs na pasta WSA que será utilizado depois de o projeto ser exportado do Unity.

  6. Em seguida, tem de abrir a pasta WSA , na pasta Insights . Verá uma cópia do mesmo ficheiro que configurou. Selecione este ficheiro e, em seguida, no inspetor, certifique-se de que Qualquer Plataforma está desmarcada e, em seguida, certifique-se de que apenaso WSAPlayer está selecionado. Clique em Aplicar.

    Captura de ecrã do painel Inspetor a mostrar o W S A Player selecionado.

  7. Agora, terá de seguir os passos 4 a 6, mas, em vez disso, para os plug-ins Newtonsoft . Veja a captura de ecrã abaixo para saber qual deve ser o aspeto do resultado.

    Captura de ecrã de quatro vistas dos painéis Projeto e Inspetor a mostrar os resultados da configuração das seleções de pasta newtonsoft e plug-in.

Capítulo 4 - Configurar a câmara e os controlos de utilizador

Neste Capítulo, irá configurar a câmara e os controlos para permitir que o utilizador veja e se mova no cenário.

  1. Clique com o botão direito do rato numa área vazia no Painel de Hierarquia e, em seguida, em Criar>Vazio.

    Captura de ecrã do painel Hierarquia, a opção Criar Vazio está selecionada.

  2. Mude o nome do novo GameObject vazio para Câmara Principal.

    Captura de ecrã do painel Hierarquia com a opção Câmara Principal selecionada. O painel Inspetor

  3. Clique com o botão direito do rato numa área vazia no Painel de Hierarquia e, em seguida, no Objeto 3D e, em seguida, no Sphere.

  4. Mude o nome do Sphere para Right Hand.

  5. Defina a Escala de Transformação da Mão Direita como 0.1, 0.1, 0.1

    Captura de ecrã a mostrar os painéis Hierarquia e Inspetor, a secção Transformar no painel Inspetor está realçada.

  6. Remova o componente Colisor do Sphere da Mão Direita ao clicar em Engrenagem no componente Colisor do Sphere e, em seguida, em Remover Componente.

    Captura de ecrã do painel Inspetor, o ícone de engrenagem e Remover Componente estão realçados na secção Colisor do Sphere.

  7. No Painel hierarquia, arraste a Câmara Principal e os objetos Da Mão Direita para o objeto Principal da Câmara .

    Captura de ecrã do painel Hierarquia com a Câmara Principal selecionada, o painel Inspetor mostra a Câmara Principal selecionada.

  8. Defina a Posição de Transformação da Câmara Principal e do objeto Mão Direita como 0, 0, 0.

    Captura de ecrã do painel Hierarquia com a Câmara Principal selecionada, as definições Transformar estão realçadas no painel Inspetor.

    Captura de ecrã do painel Hierarquia com a opção Mão Direita selecionada, as definições Transformar estão realçadas no painel Inspetor.

Capítulo 5 – Configurar os objetos na cena do Unity

Agora, irá criar algumas formas básicas para a sua cena, com as quais o utilizador pode interagir.

  1. Clique com o botão direito do rato numa área vazia no Painel de Hierarquia e, em seguida, no Objeto 3D e, em seguida, selecione Plano.

  2. Defina a Posição da Transformação do Plano como 0, -1, 0.

  3. Defina a Escala de Transformação do Plano como 5, 1, 5.

    Captura de ecrã dos painéis Cena, Hierarquia e Inspetor. A secção Transformar no painel Inspetor está realçada.

  4. Crie um material básico para utilizar com o objeto Plano , para que as outras formas sejam mais fáceis de ver. Navegue para o Painel de Projeto, clique com o botão direito do rato e, em seguida, em Criar, seguido de Pasta, para criar uma nova pasta. Dê-lhe o nome Materiais.

    Captura de ecrã a mostrar o painel Projeto com a opção Criar e Pasta realçada.Captura de ecrã do painel Projeto. Os materiais estão realçados no painel Recursos.

  5. Abra a pasta Materiais e, em seguida, clique com o botão direito do rato, clique em Criar e, em seguida, em Material, para criar um novo material. Dê-lhe o nome Azul.

    Captura de ecrã a mostrar o painel Projeto com a opção Criar e Material realçada.Captura de ecrã do painel Projeto. A opção Azul está realçada no painel Materiais.

  6. Com o novo material Azul selecionado, observe o Inspetor e clique na janela retangular junto a Albedo. Selecione uma cor azul (a única imagem abaixo é Cor Hexadecima: #3592FFFF). Clique no botão Fechar depois de escolher.

    Captura de ecrã do painel Inspetor. A secção de cores está realçada.

  7. Arraste o novo material da pasta Materiais para o plano recém-criado , dentro da cena (ou largue-o no objeto Plano na Hierarquia).

    Captura de ecrã do painel Cena a mostrar o novo material da pasta Materiais.

  8. Clique com o botão direito do rato numa área vazia no Painel de Hierarquia e, em seguida , em Objeto 3D, Cápsula.

    • Com a Cápsula selecionada, altere a Posição da Transformação para: -10, 1, 0.
  9. Clique com o botão direito do rato numa área vazia no Painel de Hierarquia e, em seguida , em Objeto 3D, Cubo.

    • Com o Cubo selecionado, altere a Posição da Transformação para: 0, 0, 10.
  10. Clique com o botão direito do rato numa área vazia no Painel de Hierarquia e, em seguida , em Objeto 3D, Sphere.

    • Com o Sphere selecionado, altere a Posição da Transformação para: 10, 0, 0.

    Captura de ecrã dos painéis Cena, Hierarquia e Inspetor. A cápsula está selecionada no painel Hierarquia.

    Nota

    Estes valores de Posição são sugestões. Pode definir as posições dos objetos para o que quiser, embora seja mais fácil para o utilizador da aplicação se as distâncias dos objetos não estiverem muito longe da câmara.

  11. Quando a aplicação está em execução, tem de ser capaz de identificar os objetos dentro do cenário. Para tal, têm de ser etiquetados. Selecione um dos objetos e, no painel Inspetor , clique em Adicionar Etiqueta..., que trocará o Inspetor pelo painel Etiquetas & Camadas .

    Captura de ecrã do painel Inspetor a mostrar a opção Adicionar Etiqueta realçada.Captura de ecrã do painel Inspetor a mostrar Etiquetas e Camadas realçados.

  12. Clique no símbolo + (mais) e, em seguida, escreva o nome da etiqueta como ObjectInScene.

    Captura de ecrã do painel Inspetor com Etiquetas e Camadas selecionadas. A caixa de diálogo Novo Nome da Etiqueta está realçada.

    Aviso

    Se utilizar um nome diferente para a sua etiqueta, terá de garantir que esta alteração também é efetuada nos scripts DataFromAnalytics, ObjectTrigger e Gaze mais tarde, para que os objetos sejam encontrados e detetados na sua cena.

  13. Com a etiqueta criada, tem agora de a aplicar aos três objetos. Na Hierarquia, mantenha premida a tecla Shift e, em seguida, clique nos objetos Cápsula, Cubo e Esfera e, em seguida, no Inspetor, clique no menu pendente junto a Etiqueta e, em seguida, clique na etiqueta ObjectInScene que criou.

    Captura de ecrã do painel Inspetor, uma seta aponta para Etiqueta. O menu Não Marcado mostra Desmarcado e ObjectInScene selecionado.Captura de ecrã a mostrar dois menus com a opção Criar e Pasta realçada.

Capítulo 6 - Criar a classe ApplicationInsightsTracker

O primeiro script que precisa de criar é ApplicationInsightsTracker, responsável por:

  1. Criar eventos com base nas interações do utilizador para submeter ao Aplicação Azure Insights.

  2. Criar nomes de Eventos adequados, dependendo da interação do utilizador.

  3. Submeter eventos para a instância do Serviço Application Insights.

Para criar esta classe:

  1. Clique com o botão direito do rato no Painel de Projeto e, em seguida, em Criar>Pasta. Atribua um nome aos Scripts da pasta.

    Captura de ecrã do painel Projetos. O ícone da pasta Scripts está realçado no painel Ativos.Captura de ecrã a mostrar as opções do menu onde as opções Criar e Script C# estão selecionadas.

  2. Com a pasta Scripts criada, faça duplo clique na mesma para abrir. Em seguida, nessa pasta, clique com o botão direito do rato em Criar>Script C#. Atribua o nome ApplicationInsightsTracker ao script.

  3. Faça duplo clique no novo script ApplicationInsightsTracker para o abrir com o Visual Studio.

  4. Atualize os espaços de nomes na parte superior do script para serem os seguintes:

        using Microsoft.ApplicationInsights;
        using Microsoft.ApplicationInsights.DataContracts;
        using Microsoft.ApplicationInsights.Extensibility;
        using UnityEngine;
    
  5. Dentro da classe, insira as seguintes variáveis:

        /// <summary>
        /// Allows this class to behavior like a singleton
        /// </summary>
        public static ApplicationInsightsTracker Instance;
    
        /// <summary>
        /// Insert your Instrumentation Key here
        /// </summary>
        internal string instrumentationKey = "Insert Instrumentation Key here";
    
        /// <summary>
        /// Insert your Application Id here
        /// </summary>
        internal string applicationId = "Insert Application Id here";
    
        /// <summary>
        /// Insert your API Key here
        /// </summary>
        internal string API_Key = "Insert API Key here";
    
        /// <summary>
        /// Represent the Analytic Custom Event object
        /// </summary>
        private TelemetryClient telemetryClient;
    
        /// <summary>
        /// Represent the Analytic object able to host gaze duration
        /// </summary>
        private MetricTelemetry metric;
    

    Nota

    Defina adequadamente os valores instrumentationKey, applicationId e API_Key , com as Chaves de Serviço do Portal do Azure, conforme mencionado no Capítulo 1, passo 9.

  6. Em seguida, adicione os métodos Start() e Awake(), que serão chamados quando a classe inicializar:

        /// <summary>
        /// Sets this class instance as a singleton
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Use this for initialization
        /// </summary>
        void Start()
        {
            // Instantiate telemetry and metric
            telemetryClient = new TelemetryClient();
    
            metric = new MetricTelemetry();
    
            // Assign the Instrumentation Key to the Event and Metric objects
            TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey;
    
            telemetryClient.InstrumentationKey = instrumentationKey;
        }
    
  7. Adicione os métodos responsáveis pelo envio dos eventos e métricas registados pela sua aplicação:

        /// <summary>
        /// Submit the Event to Azure Analytics using the event trigger object
        /// </summary>
        public void RecordProximityEvent(string objectName)
        {
            telemetryClient.TrackEvent(CreateEventName(objectName));
        }
    
        /// <summary>
        /// Uses the name of the object involved in the event to create 
        /// and return an Event Name convention
        /// </summary>
        public string CreateEventName(string name)
        {
            string eventName = $"User near {name}";
            return eventName;
        }
    
        /// <summary>
        /// Submit a Metric to Azure Analytics using the metric gazed object
        /// and the time count of the gaze
        /// </summary>
        public void RecordGazeMetrics(string objectName, int time)
        {
            // Output Console information about gaze.
            Debug.Log($"Finished gazing at {objectName}, which went for <b>{time}</b> second{(time != 1 ? "s" : "")}");
    
            metric.Name = $"Gazed {objectName}";
    
            metric.Value = time;
    
            telemetryClient.TrackMetric(metric);
        }
    
  8. Certifique-se de que guarda as alterações no Visual Studio antes de regressar ao Unity.

Capítulo 7 - Criar o script Gaze

O script seguinte a criar é o script Gaze . Este script é responsável por criar um Raycast que será projetado para a frente a partir da Câmara Principal, para detetar o objeto que o utilizador está a ver. Neste caso, o Raycast terá de identificar se o utilizador está a olhar para um objeto com a etiqueta ObjectInScene e, em seguida, contar quanto tempo o utilizador olha para esse objeto.

  1. Faça duplo clique na pasta Scripts para abri-la.

  2. Clique com o botão direito do rato dentro da pasta Scripts e clique em Criar>Script C#. Dê o nome Gaze ao script.

  3. Faça duplo clique no script para o abrir com o Visual Studio.

  4. Substitua o código existente pelo seguinte:

        using UnityEngine;
    
        public class Gaze : MonoBehaviour
        {
            /// <summary>
            /// Provides Singleton-like behavior to this class.
            /// </summary>
            public static Gaze Instance;
    
            /// <summary>
            /// Provides a reference to the object the user is currently looking at.
            /// </summary>
            public GameObject FocusedGameObject { get; private set; }
    
            /// <summary>
            /// Provides whether an object has been successfully hit by the raycast.
            /// </summary>
            public bool Hit { get; private set; }
    
            /// <summary>
            /// Provides a reference to compare whether the user is still looking at 
            /// the same object (and has not looked away).
            /// </summary>
            private GameObject _oldFocusedObject = null;
    
            /// <summary>
            /// Max Ray Distance
            /// </summary>
            private float _gazeMaxDistance = 300;
    
            /// <summary>
            /// Max Ray Distance
            /// </summary>
            private float _gazeTimeCounter = 0;
    
            /// <summary>
            /// The cursor object will be created when the app is running,
            /// this will store its values. 
            /// </summary>
            private GameObject _cursor;
        }
    
  5. O código para os métodos Awake() e Start() tem agora de ser adicionado.

        private void Awake()
        {
            // Set this class to behave similar to singleton
            Instance = this;
            _cursor = CreateCursor();
        }
    
        void Start()
        {
            FocusedGameObject = null;
        }
    
        /// <summary>
        /// Create a cursor object, to provide what the user
        /// is looking at.
        /// </summary>
        /// <returns></returns>
        private GameObject CreateCursor()    
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            // Remove the collider, so it does not block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
    
            newCursor.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
    
            newCursor.GetComponent<MeshRenderer>().material.color = 
            Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
    
            newCursor.SetActive(false);
            return newCursor;
        }
    
  6. Dentro da classe Gaze , adicione o seguinte código no método Update() para projetar um Raycast e detetar o destino atingido:

        /// <summary>
        /// Called every frame
        /// </summary>
        void Update()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedGameObject;
    
            RaycastHit hitInfo;
    
            // Initialize Raycasting.
            Hit = Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, _gazeMaxDistance);
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedGameObject = hitInfo.collider.gameObject;
    
                    // Lerp the cursor to the hit point, which helps to stabilize the gaze.
                    _cursor.transform.position = Vector3.Lerp(_cursor.transform.position, hitInfo.point, 0.6f);
    
                    _cursor.SetActive(true);
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedGameObject = null;
    
                    _cursor.SetActive(false);
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedGameObject = null;
    
                _cursor.SetActive(false);
            }
    
            // Check whether the previous focused object is this same object. If so, reset the focused object.
            if (FocusedGameObject != _oldFocusedObject)
            {
                ResetFocusedObject();
            }
            // If they are the same, but are null, reset the counter. 
            else if (FocusedGameObject == null && _oldFocusedObject == null)
            {
                _gazeTimeCounter = 0;
            }
            // Count whilst the user continues looking at the same object.
            else
            {
                _gazeTimeCounter += Time.deltaTime;
            }
        }
    
  7. Adicione o método ResetFocusedObject() para enviar dados para o Application Insights quando o utilizador tiver analisado um objeto.

        /// <summary>
        /// Reset the old focused object, stop the gaze timer, and send data if it
        /// is greater than one.
        /// </summary>
        public void ResetFocusedObject()
        {
            // Ensure the old focused object is not null.
            if (_oldFocusedObject != null)
            {
                // Only looking for objects with the correct tag.
                if (_oldFocusedObject.CompareTag("ObjectInScene"))
                {
                    // Turn the timer into an int, and ensure that more than zero time has passed.
                    int gazeAsInt = (int)_gazeTimeCounter;
    
                    if (gazeAsInt > 0)
                    {
                        //Record the object gazed and duration of gaze for Analytics
                        ApplicationInsightsTracker.Instance.RecordGazeMetrics(_oldFocusedObject.name, gazeAsInt);
                    }
                    //Reset timer
                    _gazeTimeCounter = 0;
                }
            }
        }
    
  8. Concluiu agora o script Gaze . Guarde as alterações no Visual Studio antes de regressar ao Unity.

Capítulo 8 - Criar a classe ObjectTrigger

O script seguinte que precisa de criar é o ObjectTrigger, que é responsável por:

  • Adicionar componentes necessários para a colisão com a Câmara Principal.
  • Detetar se a câmara está perto de um objeto etiquetado como ObjectInScene.

Para criar o script:

  1. Faça duplo clique na pasta Scripts para abri-la.

  2. Clique com o botão direito do rato dentro da pasta Scripts e clique em Criar>Script C#. Atribua o nome ObjectTrigger ao script.

  3. Faça duplo clique no script para o abrir com o Visual Studio. Substitua o código existente pelo seguinte:

        using UnityEngine;
    
        public class ObjectTrigger : MonoBehaviour
        {
            private void Start()
            {
                // Add the Collider and Rigidbody components, 
                // and set their respective settings. This allows for collision.
                gameObject.AddComponent<SphereCollider>().radius = 1.5f;
    
                gameObject.AddComponent<Rigidbody>().useGravity = false;
            }
    
            /// <summary>
            /// Triggered when an object with a collider enters this objects trigger collider.
            /// </summary>
            /// <param name="collision">Collided object</param>
            private void OnCollisionEnter(Collision collision)
            {
                CompareTriggerEvent(collision, true);
            }
    
            /// <summary>
            /// Triggered when an object with a collider exits this objects trigger collider.
            /// </summary>
            /// <param name="collision">Collided object</param>
            private void OnCollisionExit(Collision collision)
            {
                CompareTriggerEvent(collision, false);
            }
    
            /// <summary>
            /// Method for providing debug message, and sending event information to InsightsTracker.
            /// </summary>
            /// <param name="other">Collided object</param>
            /// <param name="enter">Enter = true, Exit = False</param>
            private void CompareTriggerEvent(Collision other, bool enter)
            {
                if (other.collider.CompareTag("ObjectInScene"))
                {
                    string message = $"User is{(enter == true ? " " : " no longer ")}near <b>{other.gameObject.name}</b>";
    
                    if (enter == true)
                    {
                        ApplicationInsightsTracker.Instance.RecordProximityEvent(other.gameObject.name);
                    }
                    Debug.Log(message);
                }
            }
        }
    
  4. Certifique-se de que guarda as alterações no Visual Studio antes de regressar ao Unity.

Capítulo 9 - Criar a classe DataFromAnalytics

Agora, terá de criar o script DataFromAnalytics , que é responsável por:

  • Obter dados de análise sobre que objeto foi mais abordado pela câmara.
  • Utilizar as Chaves de Serviço, que permitem a comunicação com a instância do Serviço Aplicação Azure Insights.
  • Ordenar os objetos na cena, de acordo com o qual tem a contagem de eventos mais elevada.
  • Alterar a cor material do objeto mais abordado para verde.

Para criar o script:

  1. Faça duplo clique na pasta Scripts para abri-la.

  2. Clique com o botão direito do rato dentro da pasta Scripts e clique em Criar>Script C#. Atribua o nome DataFromAnalytics ao script.

  3. Faça duplo clique no script para o abrir com o Visual Studio.

  4. Insira os seguintes espaços de nomes:

        using Newtonsoft.Json;
        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.Linq;
        using UnityEngine;
        using UnityEngine.Networking;
    
  5. Dentro do script, insira o seguinte:

        /// <summary>
        /// Number of most recent events to be queried
        /// </summary>
        private int _quantityOfEventsQueried = 10;
    
        /// <summary>
        /// The timespan with which to query. Needs to be in hours.
        /// </summary>
        private int _timepspanAsHours = 24;
    
        /// <summary>
        /// A list of the objects in the scene
        /// </summary>
        private List<GameObject> _listOfGameObjectsInScene;
    
        /// <summary>
        /// Number of queries which have returned, after being sent.
        /// </summary>
        private int _queriesReturned = 0;
    
        /// <summary>
        /// List of GameObjects, as the Key, with their event count, as the Value.
        /// </summary>
        private List<KeyValuePair<GameObject, int>> _pairedObjectsWithEventCount = new List<KeyValuePair<GameObject, int>>();
    
        // Use this for initialization
        void Start()
        {
            // Find all objects in scene which have the ObjectInScene tag (as there may be other GameObjects in the scene which you do not want).
            _listOfGameObjectsInScene = GameObject.FindGameObjectsWithTag("ObjectInScene").ToList();
    
            FetchAnalytics();
        }
    
  6. Na classe DataFromAnalytics , logo após o método Start(), adicione o seguinte método denominado FetchAnalytics(). Este método é responsável por preencher a lista de pares de valores chave, com um GameObject e um número de contagem de eventos de marcador de posição. Em seguida, inicializa a coroutina GetWebRequest( ). A estrutura de consulta da chamada para o Application Insights também pode ser encontrada neste método, como o ponto final do URL da Consulta .

        private void FetchAnalytics()
        {
            // Iterate through the objects in the list
            for (int i = 0; i < _listOfGameObjectsInScene.Count; i++)
            {
                // The current event number is not known, so set it to zero.
                int eventCount = 0;
    
                // Add new pair to list, as placeholder, until eventCount is known.
                _pairedObjectsWithEventCount.Add(new KeyValuePair<GameObject, int>(_listOfGameObjectsInScene[i], eventCount));
    
                // Set the renderer of the object to the default color, white
                _listOfGameObjectsInScene[i].GetComponent<Renderer>().material.color = Color.white;
    
                // Create the appropriate object name using Insights structure
                string objectName = _listOfGameObjectsInScene[i].name;
    
     		    // Build the queryUrl for this object.
     		    string queryUrl = Uri.EscapeUriString(string.Format(
                    "https://api.applicationinsights.io/v1/apps/{0}/events/$all?timespan=PT{1}H&$search={2}&$select=customMetric/name&$top={3}&$count=true",
     			    ApplicationInsightsTracker.Instance.applicationId, _timepspanAsHours, "Gazed " + objectName, _quantityOfEventsQueried));
    
    
                // Send this object away within the WebRequest Coroutine, to determine it is event count.
                StartCoroutine("GetWebRequest", new KeyValuePair<string, int>(queryUrl, i));
            }
        }
    
  7. Logo abaixo do método FetchAnalytics( ), adicione um método chamado GetWebRequest(), que devolve um IEnumerator. Este método é responsável por pedir o número de vezes que um evento, correspondente a um GameObject específico, foi chamado no Application Insights. Quando todas as consultas enviadas forem devolvidas, o método DetermineWinner() é chamado.

        /// <summary>
        /// Requests the data count for number of events, according to the
        /// input query URL.
        /// </summary>
        /// <param name="webQueryPair">Query URL and the list number count.</param>
        /// <returns></returns>
        private IEnumerator GetWebRequest(KeyValuePair<string, int> webQueryPair)
        {
            // Set the URL and count as their own variables (for readability).
            string url = webQueryPair.Key;
            int currentCount = webQueryPair.Value;
    
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(url))
            {
                DownloadHandlerBuffer handlerBuffer = new DownloadHandlerBuffer();
    
                unityWebRequest.downloadHandler = handlerBuffer;
    
                unityWebRequest.SetRequestHeader("host", "api.applicationinsights.io");
    
                unityWebRequest.SetRequestHeader("x-api-key", ApplicationInsightsTracker.Instance.API_Key);
    
                yield return unityWebRequest.SendWebRequest();
    
                if (unityWebRequest.isNetworkError)
                {
                    // Failure with web request.
                    Debug.Log("<color=red>Error Sending:</color> " + unityWebRequest.error);
                }
                else
                {
                    // This query has returned, so add to the current count.
                    _queriesReturned++;
    
                    // Initialize event count integer.
                    int eventCount = 0;
    
                    // Deserialize the response with the custom Analytics class.
                    Analytics welcome = JsonConvert.DeserializeObject<Analytics>(unityWebRequest.downloadHandler.text);
    
                    // Get and return the count for the Event
                    if (int.TryParse(welcome.OdataCount, out eventCount) == false)
                    {
                        // Parsing failed. Can sometimes mean that the Query URL was incorrect.
                        Debug.Log("<color=red>Failure to Parse Data Results. Check Query URL for issues.</color>");
                    }
                    else
                    {
                        // Overwrite the current pair, with its actual values, now that the event count is known.
                        _pairedObjectsWithEventCount[currentCount] = new KeyValuePair<GameObject, int>(_pairedObjectsWithEventCount[currentCount].Key, eventCount);
                    }
    
                    // If all queries (compared with the number which was sent away) have 
                    // returned, then run the determine winner method. 
                    if (_queriesReturned == _pairedObjectsWithEventCount.Count)
                    {
                        DetermineWinner();
                    }
                }
            }
        }
    
  8. O método seguinte é DetermineWinner(), que ordena a lista de pares GameObject e Int , de acordo com a contagem de eventos mais elevada. Em seguida, altera a cor material desse GameObject para verde (como feedback para que tenha a contagem mais elevada). Esta ação apresenta uma mensagem com os resultados da análise.

        /// <summary>
        /// Call to determine the keyValue pair, within the objects list, 
        /// with the highest event count.
        /// </summary>
        private void DetermineWinner()
        {
            // Sort the values within the list of pairs.
            _pairedObjectsWithEventCount.Sort((x, y) => y.Value.CompareTo(x.Value));
    
            // Change its colour to green
            _pairedObjectsWithEventCount.First().Key.GetComponent<Renderer>().material.color = Color.green;
    
            // Provide the winner, and other results, within the console window. 
            string message = $"<b>Analytics Results:</b>\n " +
                $"<i>{_pairedObjectsWithEventCount.First().Key.name}</i> has the highest event count, " +
                $"with <i>{_pairedObjectsWithEventCount.First().Value.ToString()}</i>.\nFollowed by: ";
    
            for (int i = 1; i < _pairedObjectsWithEventCount.Count; i++)
            {
                message += $"{_pairedObjectsWithEventCount[i].Key.name}, " +
                    $"with {_pairedObjectsWithEventCount[i].Value.ToString()} events.\n";
            }
    
            Debug.Log(message);
        }
    
  9. Adicione a estrutura da classe que será utilizada para anular a serialização do objeto JSON, recebido do Application Insights. Adicione estas classes na parte inferior do ficheiro de classe DataFromAnalytics , fora da definição de classe.

        /// <summary>
        /// These classes represent the structure of the JSON response from Azure Insight
        /// </summary>
        [Serializable]
        public class Analytics
        {
            [JsonProperty("@odata.context")]
            public string OdataContext { get; set; }
    
            [JsonProperty("@odata.count")]
            public string OdataCount { get; set; }
    
            [JsonProperty("value")]
            public Value[] Value { get; set; }
        }
    
        [Serializable]
        public class Value
        {
            [JsonProperty("customMetric")]
            public CustomMetric CustomMetric { get; set; }
        }
    
        [Serializable]
        public class CustomMetric
        {
            [JsonProperty("name")]
            public string Name { get; set; }
        }
    
  10. Certifique-se de que guarda as alterações no Visual Studio antes de regressar ao Unity.

Capítulo 10 - Criar a classe Movimento

O script Movimento é o script seguinte que terá de criar. É responsável por:

  • Mover a Câmara Principal de acordo com a direção para a que a câmara está a olhar.
  • Adicionar todos os outros scripts a objetos de cena.

Para criar o script:

  1. Faça duplo clique na pasta Scripts para abri-la.

  2. Clique com o botão direito do rato dentro da pasta Scripts e clique em Criar>Script C#. Atribua o nome Movimento ao script.

  3. Faça duplo clique no script para o abrir com o Visual Studio.

  4. Substitua o código existente pelo seguinte:

        using UnityEngine;
        using UnityEngine.XR.WSA.Input;
    
        public class Movement : MonoBehaviour
        {
            /// <summary>
            /// The rendered object representing the right controller.
            /// </summary>
            public GameObject Controller;
    
            /// <summary>
            /// The movement speed of the user.
            /// </summary>
            public float UserSpeed;
    
            /// <summary>
            /// Provides whether source updates have been registered.
            /// </summary>
            private bool _isAttached = false;
    
            /// <summary>
            /// The chosen controller hand to use. 
            /// </summary>
            private InteractionSourceHandedness _handness = InteractionSourceHandedness.Right;
    
            /// <summary>
            /// Used to calculate and proposes movement translation.
            /// </summary>
            private Vector3 _playerMovementTranslation;
    
            private void Start()
            {
                // You are now adding components dynamically 
                // to ensure they are existing on the correct object  
    
                // Add all camera related scripts to the camera. 
                Camera.main.gameObject.AddComponent<Gaze>();
                Camera.main.gameObject.AddComponent<ObjectTrigger>();
    
                // Add all other scripts to this object.
                gameObject.AddComponent<ApplicationInsightsTracker>();
                gameObject.AddComponent<DataFromAnalytics>();
            }
    
            // Update is called once per frame
            void Update()
            {
    
            }
        }
    
  5. Na classe Movimento , abaixo do método update() vazio, insira os seguintes métodos que permitem ao utilizador utilizar o controlador manual para se mover no espaço virtual:

        /// <summary>
        /// Used for tracking the current position and rotation of the controller.
        /// </summary>
        private void UpdateControllerState()
        {
    #if UNITY_WSA && UNITY_2017_2_OR_NEWER
            // Check for current connected controllers, only if WSA.
            string message = string.Empty;
    
            if (InteractionManager.GetCurrentReading().Length > 0)
            {
                foreach (var sourceState in InteractionManager.GetCurrentReading())
                {
                    if (sourceState.source.kind == InteractionSourceKind.Controller && sourceState.source.handedness == _handness)
                    {
                        // If a controller source is found, which matches the selected handness, 
                        // check whether interaction source updated events have been registered. 
                        if (_isAttached == false)
                        {
                            // Register events, as not yet registered.
                            message = "<color=green>Source Found: Registering Controller Source Events</color>";
                            _isAttached = true;
    
                            InteractionManager.InteractionSourceUpdated += InteractionManager_InteractionSourceUpdated;
                        }
    
                        // Update the position and rotation information for the controller.
                        Vector3 newPosition;
                        if (sourceState.sourcePose.TryGetPosition(out newPosition, InteractionSourceNode.Pointer) && ValidPosition(newPosition))
                        {
                            Controller.transform.localPosition = newPosition;
                        }
    
                        Quaternion newRotation;
    
                        if (sourceState.sourcePose.TryGetRotation(out newRotation, InteractionSourceNode.Pointer) && ValidRotation(newRotation))
                        {
                            Controller.transform.localRotation = newRotation;
                        }
                    }
                }
            }
            else
            {
                // Controller source not detected. 
                message = "<color=blue>Trying to detect controller source</color>";
    
                if (_isAttached == true)
                {
                    // A source was previously connected, however, has been lost. Disconnected
                    // all registered events. 
    
                    _isAttached = false;
    
                    InteractionManager.InteractionSourceUpdated -= InteractionManager_InteractionSourceUpdated;
    
                    message = "<color=red>Source Lost: Detaching Controller Source Events</color>";
                }
            }
    
            if(message != string.Empty)
            {
                Debug.Log(message);
            }
    #endif
        }
    
        /// <summary>
        /// This registered event is triggered when a source state has been updated.
        /// </summary>
        /// <param name="obj"></param>
        private void InteractionManager_InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
        {
            if (obj.state.source.handedness == _handness)
            {
                if(obj.state.thumbstickPosition.magnitude > 0.2f)
                {
                    float thumbstickY = obj.state.thumbstickPosition.y;
    
                    // Vertical Input.
                    if (thumbstickY > 0.3f || thumbstickY < -0.3f)
                    {
                        _playerMovementTranslation = Camera.main.transform.forward;
                        _playerMovementTranslation.y = 0;
                        transform.Translate(_playerMovementTranslation * UserSpeed * Time.deltaTime * thumbstickY, Space.World);
                    }
                }
            }
        }
    
        /// <summary>
        /// Check that controller position is valid. 
        /// </summary>
        /// <param name="inputVector3">The Vector3 to check</param>
        /// <returns>The position is valid</returns>
        private bool ValidPosition(Vector3 inputVector3)
        {
            return !float.IsNaN(inputVector3.x) && !float.IsNaN(inputVector3.y) && !float.IsNaN(inputVector3.z) && !float.IsInfinity(inputVector3.x) && !float.IsInfinity(inputVector3.y) && !float.IsInfinity(inputVector3.z);
        }
    
        /// <summary>
        /// Check that controller rotation is valid. 
        /// </summary>
        /// <param name="inputQuaternion">The Quaternion to check</param>
        /// <returns>The rotation is valid</returns>
        private bool ValidRotation(Quaternion inputQuaternion)
        {
            return !float.IsNaN(inputQuaternion.x) && !float.IsNaN(inputQuaternion.y) && !float.IsNaN(inputQuaternion.z) && !float.IsNaN(inputQuaternion.w) && !float.IsInfinity(inputQuaternion.x) && !float.IsInfinity(inputQuaternion.y) && !float.IsInfinity(inputQuaternion.z) && !float.IsInfinity(inputQuaternion.w);
        }   
    
  6. Por último, adicione a chamada de método no método Update( ).

        // Update is called once per frame
        void Update()
        {
            UpdateControllerState();
        }
    
  7. Certifique-se de que guarda as alterações no Visual Studio antes de regressar ao Unity.

Capítulo 11 - Configurar as referências de scripts

Neste Capítulo, tem de colocar o script Movimento no Elemento Principal da Câmara e definir os respetivos destinos de referência. Esse script irá então processar a colocação dos outros scripts onde precisam de estar.

  1. Na pasta Scripts no Painel de Projeto, arraste o script Movimento para o objeto Principal da Câmara , localizado no Painel de Hierarquia.

    Captura de ecrã dos painéis Projeto e Hierarquia. O movimento está realçado.

  2. Clique no Elemento Principal da Câmara. No Painel hierarquia, arraste o objeto Mão Direita do Painel de Hierarquia para o destino de referência, Controlador, no Painel de Inspetores. Defina a Velocidade do Utilizador como 5, conforme mostrado na imagem abaixo.

    Captura de ecrã a mostrar os painéis Hierarquia e Inspetor. Uma linha liga a Mão Direita em ambos os painéis.

Capítulo 12 - Criar o projeto unity

Tudo o que é necessário para a secção Unity deste projeto foi agora concluído, por isso está na altura de o construir a partir do Unity.

  1. Navegue para Definições de Compilação (Definições de Compilação de Ficheiros>).

  2. Na janela Definições de Compilação , clique em Compilar.

    Captura de ecrã a mostrar a janela Definições de Compilação a mostrar Cenas na Compilação.

  3. Será apresentada uma janela de Explorador de Ficheiros, solicitando-lhe uma localização para a compilação. Crie uma nova pasta (clicando em Nova Pasta no canto superior esquerdo) e atribua-lhe o nome BUILDS.

    Captura de ecrã a mostrar Explorador de Ficheiros a mostrar a pasta Compilações realçada.

    1. Abra a nova pasta BUILDS e crie outra pasta (utilizando Nova Pasta mais uma vez) e dê-lhe o nome MR_Azure_Application_Insights.

      Captura de ecrã do Explorador de ficheiros a mostrar a pasta MR_Azure_Insights.

    2. Com a pasta MR_Azure_Application_Insights selecionada, clique em Selecionar Pasta. O projeto demorará cerca de um minuto a criar.

  4. A seguir a Compilação, Explorador de Ficheiros aparecerão a mostrar-lhe a localização do seu novo projeto.

Capítulo 13 – Implementar MR_Azure_Application_Insights aplicação no seu computador

Para implementar a aplicação MR_Azure_Application_Insights no seu Computador Local:

  1. Abra o ficheiro de solução da sua aplicação MR_Azure_Application_Insights no Visual Studio.

  2. Na Plataforma de Soluções, selecione x86, Máquina Local.

  3. Na Configuração da Solução , selecione Depurar.

    Captura de ecrã do ecrã Configuração da Solução do Visual Studio a mostrar a Depuração na barra de menus.

  4. Aceda ao menu Compilar e clique em Implementar Solução para colocar a aplicação sideload no seu computador.

  5. A sua aplicação deverá agora aparecer na lista de aplicações instaladas, prontas para serem iniciadas.

  6. Inicie a aplicação de realidade mista.

  7. Mova-se pelo local, aproximando-se dos objetos e olhando para os mesmos, quando o Azure Insight Service recolher dados de eventos suficientes, definirá o objeto que foi mais abordado como verde.

Importante

Embora o tempo médio de espera para que os Eventos e Métricas sejam recolhidos pelo Serviço demora cerca de 15 minutos, em algumas ocasiões poderá demorar até 1 hora.

Capítulo 14 - O portal do Serviço Application Insights

Depois de percorrer o local e observar vários objetos, pode ver os dados recolhidos no portal do Serviço Application Insights .

  1. Voltar ao portal do Serviço Application Insights.

  2. Selecione Explorador de Métricas.

    Captura de ecrã do painel MyNewInsight a mostrar a lista de opções. O Explorador de Métricas está listado na secção Investigar.

  3. Será aberto num separador que contém o gráfico, que representa os Eventos e Métricas relacionados com a sua aplicação. Conforme mencionado acima, pode demorar algum tempo (até 1 hora) para que os dados sejam apresentados no gráfico

    Captura de ecrã do Explorador de Métricas a mostrar o gráfico de eventos e métricas.

  4. Selecione a barra Eventos no Total de Eventos por Versão da Aplicação para ver uma discriminação detalhada dos eventos com os respetivos nomes.

    Captura de ecrã do painel Pesquisa a mostrar os resultados de um filtro de evento personalizado.

A sua aplicação do Serviço Application Insights terminou

Parabéns, criou uma aplicação de realidade mista que tira partido do Serviço Application Insights para monitorizar a atividade do utilizador na sua aplicação.

Ecrã de boas-vindas do curso.

Exercícios de Bónus

Exercício 1

Experimente gerar, em vez de criar manualmente, os objetos ObjectInScene e definir as coordenadas no plano dentro dos scripts. Desta forma, pode perguntar ao Azure qual era o objeto mais popular (seja pelo olhar ou pelos resultados de proximidade) e gerar mais um desses objetos.

Exercício 2

Ordene os resultados do Application Insights por tempo, para que obtenha os dados mais relevantes e implemente esses dados confidenciais de tempo na sua aplicação.